This adds a port, card and profile to RAOP sinks to make it possible to change the latency at runtime (and have it persist) using pavucontrol or pactl set-port-latency-offset. -- Colin
From bd815a400ad280627083cbce3ef9b927f669faa0 Mon Sep 17 00:00:00 2001 From: Colin Leroy <[email protected]> Date: Sat, 7 Oct 2017 20:10:21 +0200 Subject: [PATCH 2/3] RAOP: Init dummy port and card for latency change
This adds a port, card and profile to RAOP sinks to make it
possible to change the latency at runtime (and have it persist)
using pavucontrol or pactl set-port-latency-offset.
---
src/modules/raop/raop-sink.c | 110 +++++++++++++++++++++++++++++++++++++++++--
1 file changed, 107 insertions(+), 3 deletions(-)
diff --git a/src/modules/raop/raop-sink.c b/src/modules/raop/raop-sink.c
index cd90e3d9..244f6951 100644
--- a/src/modules/raop/raop-sink.c
+++ b/src/modules/raop/raop-sink.c
@@ -69,6 +69,7 @@ struct userdata {
pa_core *core;
pa_module *module;
pa_sink *sink;
+ pa_card *card;
pa_thread *thread;
pa_thread_mq thread_mq;
@@ -122,9 +123,6 @@ static int64_t sink_get_latency(const struct userdata *u) {
latency = pa_bytes_to_usec(u->write_count, &u->sink->sample_spec) - (int64_t) now;
- /* RAOP default latency */
- latency += u->latency * PA_USEC_PER_MSEC;
-
return latency;
}
@@ -465,6 +463,83 @@ finish:
pa_log_debug("Thread shutting down");
}
+static int sink_set_port_cb(pa_sink *s, pa_device_port *p) {
+ return 0;
+}
+
+static pa_device_port *raop_create_port(struct userdata *u, const char *server) {
+ pa_device_port_new_data data;
+ pa_device_port *port;
+
+ pa_device_port_new_data_init(&data);
+
+ pa_device_port_new_data_set_name(&data, "network-output");
+ pa_device_port_new_data_set_description(&data, server);
+ pa_device_port_new_data_set_direction(&data, PA_DIRECTION_OUTPUT);
+
+ port = pa_device_port_new(u->core, &data, 0);
+
+ pa_device_port_new_data_done(&data);
+
+ if (port == NULL)
+ return NULL;
+
+ pa_device_port_ref(port);
+ /* init the latency_offset directly instead of using
+ * pa_device_port_set_latency_offset(), so that mode module-card-restore
+ * can do its job when PulseAudio restarts and the user-set latency
+ * is not overwritten.
+ */
+ port->latency_offset = u->latency * PA_USEC_PER_MSEC;
+
+ return port;
+}
+
+static pa_card_profile *raop_create_profile() {
+ pa_card_profile *profile;
+
+ profile = pa_card_profile_new("RAOP", _("RAOP standard profile"), 0);
+ profile->priority = 10;
+ profile->n_sinks = 1;
+ profile->n_sources = 0;
+ profile->max_sink_channels = 2;
+ profile->max_source_channels = 0;
+
+ return profile;
+}
+
+static pa_card *raop_create_card(pa_module *m, pa_device_port *port, pa_card_profile *profile, const char *server, const char *nicename) {
+ pa_card_new_data data;
+ pa_card *card;
+ char *card_name;
+
+ pa_card_new_data_init(&data);
+
+ card_name = pa_sprintf_malloc("raop_client.%s", server);
+
+ pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, card_name);
+ pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, nicename);
+ data.driver = __FILE__;
+
+ pa_card_new_data_set_name(&data, card_name);
+ pa_xfree(card_name);
+
+ pa_hashmap_put(data.ports, port->name, port);
+ pa_hashmap_put(data.profiles, profile->name, profile);
+
+ card = pa_card_new(m->core, &data);
+
+ pa_card_new_data_done(&data);
+
+ if (card == NULL)
+ return NULL;
+
+ card->active_profile = profile;
+ pa_card_put(card);
+
+ return card;
+}
+
pa_sink* pa_raop_sink_new(pa_module *m, pa_modargs *ma, const char *driver) {
struct userdata *u = NULL;
pa_sample_spec ss;
@@ -473,6 +548,9 @@ pa_sink* pa_raop_sink_new(pa_module *m, pa_modargs *ma, const char *driver) {
const char /* *username, */ *password;
pa_sink_new_data data;
const char *name = NULL;
+ const char *description = NULL;
+ pa_device_port *port;
+ pa_card_profile *profile;
pa_assert(m);
pa_assert(ma);
@@ -590,6 +668,28 @@ pa_sink* pa_raop_sink_new(pa_module *m, pa_modargs *ma, const char *driver) {
goto fail;
}
+ port = raop_create_port(u, server);
+ if (port == NULL) {
+ pa_log("Failed to create port object");
+ goto fail;
+ }
+
+ profile = raop_create_profile();
+ pa_hashmap_put(port->profiles, profile->name, profile);
+
+ description = pa_proplist_gets(data.proplist, PA_PROP_DEVICE_DESCRIPTION);
+ if (description == NULL)
+ description = server;
+
+ u->card = raop_create_card(m, port, profile, server, description);
+ if (u->card == NULL) {
+ pa_log("Failed to create card object");
+ goto fail;
+ }
+
+ data.card = u->card;
+ pa_hashmap_put(data.ports, port->name, port);
+
u->sink = pa_sink_new(m->core, &data, PA_SINK_LATENCY | PA_SINK_NETWORK);
pa_sink_new_data_done(&data);
@@ -602,6 +702,7 @@ pa_sink* pa_raop_sink_new(pa_module *m, pa_modargs *ma, const char *driver) {
pa_sink_set_set_volume_callback(u->sink, sink_set_volume_cb);
pa_sink_set_set_mute_callback(u->sink, sink_set_mute_cb);
u->sink->userdata = u;
+ u->sink->set_port = sink_set_port_cb;
pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
pa_sink_set_rtpoll(u->sink, u->rtpoll);
@@ -680,6 +781,9 @@ static void userdata_free(struct userdata *u) {
pa_smoother_free(u->smoother);
u->smoother = NULL;
+ if (u->card)
+ pa_card_free(u->card);
+
pa_xfree(u);
}
--
2.11.0
pgpIyFBhYi5XV.pgp
Description: OpenPGP digital signature
_______________________________________________ pulseaudio-discuss mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
