From 157533e3debe00f042adc6cbb9860f61768bc15f Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 11 Jul 2013 13:57:41 +0200 Subject: [PATCH] module-tunnel: automatically find the PulseAudio server Make the PulseAudio tunnel behave the same way as a client when it comes to figuring out how to connect to the current PulseAudio daemon. This can be useful if you start a second PulseAudio instance for e.g. network access. --- src/modules/module-tunnel.c | 174 ++++++++++++++++++++++++++++++++++++++++---- src/pulsecore/auth-cookie.c | 35 +++++++++ src/pulsecore/auth-cookie.h | 1 + 3 files changed, 197 insertions(+), 13 deletions(-) diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index de60573..46150e1 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -31,6 +31,10 @@ #include #include +#ifdef HAVE_X11 +#include +#endif + #include #include #include @@ -54,6 +58,11 @@ #include #include #include +#include + +#ifdef HAVE_X11 +#include +#endif #ifdef TUNNEL_SINK #include "module-tunnel-sink-symdef.h" @@ -61,6 +70,11 @@ #include "module-tunnel-source-symdef.h" #endif +#define ENV_DEFAULT_SINK "PULSE_SINK" +#define ENV_DEFAULT_SOURCE "PULSE_SOURCE" +#define ENV_DEFAULT_SERVER "PULSE_SERVER" +#define ENV_COOKIE_FILE "PULSE_COOKIE" + #ifdef TUNNEL_SINK PA_MODULE_DESCRIPTION("Tunnel module for sinks"); PA_MODULE_USAGE( @@ -1898,6 +1912,8 @@ static void sink_set_mute(pa_sink *sink) { int pa__init(pa_module*m) { pa_modargs *ma = NULL; struct userdata *u = NULL; + const char *server; + pa_strlist *server_list = NULL; pa_sample_spec ss; pa_channel_map map; char *dn = NULL; @@ -1906,6 +1922,10 @@ int pa__init(pa_module*m) { #else pa_source_new_data data; #endif +#ifdef HAVE_X11 + xcb_connection_t *xcb = NULL; +#endif + const char *cookie_path; pa_assert(m); @@ -1922,11 +1942,9 @@ int pa__init(pa_module*m) { u->pstream = NULL; u->server_name = NULL; #ifdef TUNNEL_SINK - u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL));; u->sink = NULL; u->requested_bytes = 0; #else - u->source_name = pa_xstrdup(pa_modargs_get_value(ma, "source", NULL));; u->source = NULL; #endif u->smoother = pa_smoother_new( @@ -1948,14 +1966,114 @@ int pa__init(pa_module*m) { u->rtpoll = pa_rtpoll_new(); pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll); - if (!(u->auth_cookie = pa_auth_cookie_get(u->core, pa_modargs_get_value(ma, "cookie", PA_NATIVE_COOKIE_FILE), true, PA_NATIVE_COOKIE_LENGTH))) - goto fail; +#ifdef HAVE_X11 + /* Need an X11 connection to get root properties */ + if (getenv("DISPLAY") != NULL) { + if (!(xcb = xcb_connect(getenv("DISPLAY"), NULL))) + pa_log("xcb_connect() failed"); + else { + if (xcb_connection_has_error(xcb)) { + pa_log("xcb_connection_has_error() returned true"); + xcb_disconnect(xcb); + xcb = NULL; + } + } + } +#endif - if (!(u->server_name = pa_xstrdup(pa_modargs_get_value(ma, "server", NULL)))) { - pa_log("No server specified."); - goto fail; + /* Figure out the cookie the same way a normal client would */ + cookie_path = pa_modargs_get_value(ma, "cookie", NULL); + + if (cookie_path == NULL) + cookie_path = getenv(ENV_COOKIE_FILE); + +#ifdef HAVE_X11 + if ((cookie_path == NULL) && (xcb != NULL)) { + char t[1024]; + if (pa_x11_get_prop(xcb, 0, "PULSE_COOKIE", t, sizeof(t))) { + uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; + + if (pa_parsehex(t, cookie, sizeof(cookie)) != sizeof(cookie)) + pa_log("Failed to parse cookie data"); + else { + if (!(u->auth_cookie = pa_auth_cookie_create(u->core, cookie, sizeof(cookie)))) + goto fail; + } + } + } +#endif + + if ((cookie_path == NULL) && (u->auth_cookie == NULL)) + cookie_path = PA_NATIVE_COOKIE_FILE; + + if (cookie_path != NULL) { + if (!(u->auth_cookie = pa_auth_cookie_get(u->core, cookie_path, true, PA_NATIVE_COOKIE_LENGTH))) + goto fail; + } + + /* Same thing for the server name */ + server = pa_modargs_get_value(ma, "server", NULL); + + if (server == NULL) + server = getenv(ENV_DEFAULT_SERVER); + +#ifdef HAVE_X11 + if ((server == NULL) && (xcb != NULL)) { + char t[1024]; + if (pa_x11_get_prop(xcb, 0, "PULSE_SERVER", t, sizeof(t))) + server = pa_xstrdup(t); + } +#endif + + if (server) { + if (!(server_list = pa_strlist_parse(server))) { + pa_log("Invalid server specified."); + goto fail; + } + } else { + char *ufn; + + pa_log("No server address found. Attempting default local sockets."); + + /* The system wide instance via PF_LOCAL */ + server_list = pa_strlist_prepend(server_list, PA_SYSTEM_RUNTIME_PATH PA_PATH_SEP PA_NATIVE_DEFAULT_UNIX_SOCKET); + + /* The user instance via PF_LOCAL */ + if ((ufn = pa_runtime_path(PA_NATIVE_DEFAULT_UNIX_SOCKET))) { + server_list = pa_strlist_prepend(server_list, ufn); + pa_xfree(ufn); + } } + /* Also determine the default sink/source on the other server */ +#ifdef TUNNEL_SINK + u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL));; + + if (u->sink_name == NULL) + u->sink_name = pa_xstrdup(getenv(ENV_DEFAULT_SINK)); + +#ifdef HAVE_X11 + if ((u->sink_name == NULL) && (xcb != NULL)) { + char t[1024]; + if (pa_x11_get_prop(xcb, 0, "PULSE_SINK", t, sizeof(t))) + u->sink_name = pa_xstrdup(t); + } +#endif +#else + u->source_name = pa_xstrdup(pa_modargs_get_value(ma, "source", NULL));; + + if (u->source_name == NULL) + u->source_name = pa_xstrdup(getenv(ENV_DEFAULT_SOURCE)); + +#ifdef HAVE_X11 + if ((u->source_name == NULL) && (xcb != NULL)) { + char t[1024]; + if (pa_x11_get_prop(xcb, 0, "PULSE_SOURCE", t, sizeof(t))) + u->source_name = pa_xstrdup(t); + } +#endif +#endif + ss = m->core->default_sample_spec; map = m->core->default_channel_map; if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { @@ -1963,10 +2081,24 @@ int pa__init(pa_module*m) { goto fail; } - if (!(u->client = pa_socket_client_new_string(m->core->mainloop, true, u->server_name, PA_NATIVE_DEFAULT_PORT))) { - pa_log("Failed to connect to server '%s'", u->server_name); - goto fail; - } + for (;;) { + server_list = pa_strlist_pop(server_list, &u->server_name); + + if (u->server_name == NULL) { + pa_log("Failed to connect to server '%s'", server); + goto fail; + } + + pa_log_debug("Trying to connect to %s...", u->server_name); + + if (!(u->client = pa_socket_client_new_string(m->core->mainloop, true, u->server_name, PA_NATIVE_DEFAULT_PORT))) { + pa_xfree(u->server_name); + u->server_name = NULL; + continue; + } + + break; + } pa_socket_client_set_callback(u->client, on_connection, u); @@ -1978,7 +2110,7 @@ int pa__init(pa_module*m) { pa_sink_new_data_init(&data); data.driver = __FILE__; data.module = m; - data.namereg_fail = true; + data.namereg_fail = false; pa_sink_new_data_set_name(&data, dn); pa_sink_new_data_set_sample_spec(&data, &ss); pa_sink_new_data_set_channel_map(&data, &map); @@ -2022,7 +2154,7 @@ int pa__init(pa_module*m) { pa_source_new_data_init(&data); data.driver = __FILE__; data.module = m; - data.namereg_fail = true; + data.namereg_fail = false; pa_source_new_data_set_name(&data, dn); pa_source_new_data_set_sample_spec(&data, &ss); pa_source_new_data_set_channel_map(&data, &map); @@ -2079,6 +2211,14 @@ int pa__init(pa_module*m) { pa_source_put(u->source); #endif + if (server_list) + pa_strlist_free(server_list); + +#ifdef HAVE_X11 + if (xcb) + xcb_disconnect(xcb); +#endif + pa_modargs_free(ma); return 0; @@ -2086,6 +2226,14 @@ int pa__init(pa_module*m) { fail: pa__done(m); + if (server_list) + pa_strlist_free(server_list); + +#ifdef HAVE_X11 + if (xcb) + xcb_disconnect(xcb); +#endif + if (ma) pa_modargs_free(ma); diff --git a/src/pulsecore/auth-cookie.c b/src/pulsecore/auth-cookie.c index c5e5d7c..62036d7 100644 --- a/src/pulsecore/auth-cookie.c +++ b/src/pulsecore/auth-cookie.c @@ -77,6 +77,41 @@ pa_auth_cookie* pa_auth_cookie_get(pa_core *core, const char *cn, bool create, s return c; } +pa_auth_cookie* pa_auth_cookie_create(pa_core *core, const void *data, size_t size) +{ + pa_auth_cookie *c; + char *t; + + pa_assert(core); + pa_assert(data); + pa_assert(size > 0); + + t = pa_xstrdup("auth-cookie"); + + if ((c = pa_shared_get(core, t))) { + + pa_xfree(t); + + if (c->size != size) + return NULL; + + return pa_auth_cookie_ref(c); + } + + c = pa_xmalloc(PA_ALIGN(sizeof(pa_auth_cookie)) + size); + PA_REFCNT_INIT(c); + c->core = core; + c->name = t; + c->size = size; + + pa_assert_se(pa_shared_set(core, t, c) >= 0); + + memcpy((uint8_t*) c + PA_ALIGN(sizeof(pa_auth_cookie)), data, size); + + return c; +} + + pa_auth_cookie* pa_auth_cookie_ref(pa_auth_cookie *c) { pa_assert(c); pa_assert(PA_REFCNT_VALUE(c) >= 1); diff --git a/src/pulsecore/auth-cookie.h b/src/pulsecore/auth-cookie.h index 7c689a4..e4a3504 100644 --- a/src/pulsecore/auth-cookie.h +++ b/src/pulsecore/auth-cookie.h @@ -27,6 +27,7 @@ typedef struct pa_auth_cookie pa_auth_cookie; pa_auth_cookie* pa_auth_cookie_get(pa_core *c, const char *cn, bool create, size_t size); +pa_auth_cookie* pa_auth_cookie_create(pa_core *c, const void *data, size_t size); pa_auth_cookie* pa_auth_cookie_ref(pa_auth_cookie *c); void pa_auth_cookie_unref(pa_auth_cookie *c); -- 1.8.1.4