Hi, 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 d4549b517930975d0c637fb685f6ae147018f8a4 Mon Sep 17 00:00:00 2001 From: Colin Leroy <[email protected]> Date: Fri, 6 Oct 2017 20:03:42 +0200 Subject: [PATCH 1/2] 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..bb9c4556 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) { + 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, _("Network output")); + 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); + + if (card == NULL) + return NULL; + + pa_card_new_data_done(&data); + + 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); + 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
pgpdrXOf2DGje.pgp
Description: OpenPGP digital signature
_______________________________________________ pulseaudio-discuss mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
