On 17 September 2017 at 19h51, Tanu Kaskinen wrote: Hi,
> "git am" fails to apply the patch on top of the master branch (as it > failed to apply the previous versions too, but I forgot to mention > that earlier). Sorry, I forgot to pull :) > The commit message could explain also why pa_smoother_reset() is used > instead of pause()/resume(). Done. > Why do you check the return value of pa_modargs_get_value() before > calling pa_modargs_get_value_u32()? As far as I can tell, that makes > no difference. pa_modargs_get_value_u32() (and its friends) set the parameter to 0 if it's not present, returning -1 only in case of integer conversion error. > Nitpicking: the convention is to use the PA_USEC_PER_MSEC constant > instead of bare "1000". Fixed too :) I attached an updated patch. -- Colin
From ed8d46e28280dbb435d6c1f5a854e532b6e33dd1 Mon Sep 17 00:00:00 2001 From: Colin Leroy <[email protected]> Date: Sun, 17 Sep 2017 20:46:49 +0200 Subject: [PATCH] RAOP: Announce real latency Use predefined values depending on the server, and make it configurable. AirPlay is supposed to have 2s of latency. With my hardware, this is more 2.352 seconds after numerous tests. Switch from pausing/resuming the smoother to resetting it because the smoother got stuck returning the same value after an idle/running cycle, making latency calculation wrong. --- src/modules/raop/module-raop-discover.c | 46 +++++++++++++++++++++++++++++++-- src/modules/raop/module-raop-sink.c | 4 ++- src/modules/raop/raop-sink.c | 17 ++++++++++-- src/modules/raop/raop-util.h | 2 ++ 4 files changed, 64 insertions(+), 5 deletions(-) diff --git a/src/modules/raop/module-raop-discover.c b/src/modules/raop/module-raop-discover.c index d65615b2..37c2c6cf 100644 --- a/src/modules/raop/module-raop-discover.c +++ b/src/modules/raop/module-raop-discover.c @@ -44,11 +44,14 @@ #include <pulsecore/avahi-wrap.h> #include "module-raop-discover-symdef.h" +#include "raop-util.h" PA_MODULE_AUTHOR("Colin Guthrie"); PA_MODULE_DESCRIPTION("mDNS/DNS-SD Service Discovery of RAOP devices"); PA_MODULE_VERSION(PACKAGE_VERSION); PA_MODULE_LOAD_ONCE(true); +PA_MODULE_USAGE( + "latency_msec=<audio latency - applies to all devices> "); #define SERVICE_TYPE_SINK "_raop._tcp" @@ -61,9 +64,13 @@ struct userdata { AvahiServiceBrowser *sink_browser; pa_hashmap *tunnels; + + bool latency_set; + uint32_t latency; }; static const char* const valid_modargs[] = { + "latency_msec", NULL }; @@ -127,6 +134,23 @@ static void tunnel_free(struct tunnel *t) { pa_xfree(t); } +/* This functions returns RAOP audio latency as guessed by the + * device model header. + * Feel free to complete the possible values after testing with + * your hardware. + */ +static uint32_t guess_latency_from_device(const char *model) { + uint32_t default_latency = RAOP_DEFAULT_LATENCY; + + if (pa_streq(model, "PIONEER,1")) { + /* Pioneer N-30 */ + default_latency = 2352; + } + + pa_log_debug("Default latency is %u ms for device model %s.", default_latency, model); + return default_latency; +} + static void resolver_cb( AvahiServiceResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, @@ -145,6 +169,7 @@ static void resolver_cb( char at[AVAHI_ADDRESS_STR_MAX]; AvahiStringList *l; pa_module *m; + uint32_t latency = RAOP_DEFAULT_LATENCY; pa_assert(u); @@ -226,6 +251,9 @@ static void resolver_cb( /* Sample rate */ pa_xfree(sr); sr = pa_xstrdup(value); + } else if (pa_streq(key, "am")) { + /* Device model */ + latency = guess_latency_from_device(value); } avahi_free(key); @@ -308,6 +336,13 @@ static void resolver_cb( pa_xfree(t); } + if (u->latency_set) + latency = u->latency; + + t = args; + args = pa_sprintf_malloc("%s latency_msec=%u", args, latency); + pa_xfree(t); + pa_log_debug("Loading module-raop-sink with arguments '%s'", args); if (pa_module_load(&m, u->core, "module-raop-sink", args) >= 0) { @@ -426,16 +461,23 @@ int pa__init(pa_module *m) { struct userdata *u; pa_modargs *ma = NULL; int error; + uint32_t l; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log("Failed to parse module arguments."); goto fail; } - m->userdata = u = pa_xnew(struct userdata, 1); + m->userdata = u = pa_xnew0(struct userdata, 1); u->core = m->core; u->module = m; - u->sink_browser = NULL; + + if (pa_modargs_get_value(ma, "latency_msec", NULL) != NULL) { + if (pa_modargs_get_value_u32(ma, "latency_msec", &l) == 0) { + u->latency_set = true; + u->latency = l; + } + } u->tunnels = pa_hashmap_new(tunnel_hash, tunnel_compare); diff --git a/src/modules/raop/module-raop-sink.c b/src/modules/raop/module-raop-sink.c index 82fa48d9..d6826572 100644 --- a/src/modules/raop/module-raop-sink.c +++ b/src/modules/raop/module-raop-sink.c @@ -46,7 +46,8 @@ PA_MODULE_USAGE( "rate=<sample rate> " "channels=<number of channels> " "username=<authentication user name, default: \"iTunes\"> " - "password=<authentication password>"); + "password=<authentication password> " + "latency_msec=<audio latency>"); static const char* const valid_modargs[] = { "name", @@ -61,6 +62,7 @@ static const char* const valid_modargs[] = { "channels", "username", "password", + "latency_msec", NULL }; diff --git a/src/modules/raop/raop-sink.c b/src/modules/raop/raop-sink.c index 4d13927f..7280225e 100644 --- a/src/modules/raop/raop-sink.c +++ b/src/modules/raop/raop-sink.c @@ -63,6 +63,7 @@ #include "raop-sink.h" #include "raop-client.h" +#include "raop-util.h" struct userdata { pa_core *core; @@ -87,6 +88,8 @@ struct userdata { pa_usec_t start; pa_smoother *smoother; uint64_t write_count; + + uint32_t latency; }; enum { @@ -119,6 +122,9 @@ 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; } @@ -136,7 +142,6 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse pa_assert(PA_SINK_IS_OPENED(u->sink->thread_info.state)); - pa_smoother_pause(u->smoother, pa_rtclock_now()); /* Issue a TEARDOWN if we are still connected */ if (pa_raop_client_is_alive(u->raop)) { pa_raop_client_teardown(u->raop); @@ -163,7 +168,7 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse pa_log_debug("RAOP: RUNNING"); now = pa_rtclock_now(); - pa_smoother_resume(u->smoother, now, true); + pa_smoother_reset(u->smoother, now, false); if (!pa_raop_client_is_alive(u->raop)) { /* Connecting will trigger a RECORD and start steaming */ @@ -468,6 +473,7 @@ 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; + uint32_t l; pa_assert(m); pa_assert(ma); @@ -494,6 +500,13 @@ pa_sink* pa_raop_sink_new(pa_module *m, pa_modargs *ma, const char *driver) { u->thread = NULL; u->rtpoll = pa_rtpoll_new(); u->rtpoll_item = NULL; + u->latency = RAOP_DEFAULT_LATENCY; + + if (pa_modargs_get_value(ma, "latency_msec", NULL) != NULL) { + if (pa_modargs_get_value_u32(ma, "latency_msec", &l) == 0) { + u->latency = l; + } + } if (pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll) < 0) { pa_log("pa_thread_mq_init() failed."); diff --git a/src/modules/raop/raop-util.h b/src/modules/raop/raop-util.h index d3f75666..7c25e5ca 100644 --- a/src/modules/raop/raop-util.h +++ b/src/modules/raop/raop-util.h @@ -27,6 +27,8 @@ Kungliga Tekniska högskolan. ***/ +#define RAOP_DEFAULT_LATENCY 2000 /* msec */ + int pa_raop_base64_encode(const void *data, int len, char **str); int pa_raop_base64_decode(const char *str, void *data); -- 2.11.0
pgpzg4n383PDk.pgp
Description: OpenPGP digital signature
_______________________________________________ pulseaudio-discuss mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
