[pulseaudio-discuss] [PATCH v3 05/11] tunnel-new: Read parameters from tunnel manager when available

Tanu Kaskinen tanu.kaskinen at linux.intel.com
Thu Dec 4 10:44:48 PST 2014


This prepares for loading tunnel sink and source module instances from
the tunnel manager.

If the tunnel manager is available, and the tunnel manager has
sample spec and channel map information for the device, then let's use
that information when creating the sink or source so that the tunnel
will automatically match the parameters of the remote device. The
remote device's proplist is copied to the tunnel too.
---
 src/Makefile.am                        |   4 +-
 src/modules/module-tunnel-sink-new.c   | 154 ++++++++++++++++++++++++++++----
 src/modules/module-tunnel-source-new.c | 155 +++++++++++++++++++++++++++++----
 3 files changed, 277 insertions(+), 36 deletions(-)

diff --git a/src/Makefile.am b/src/Makefile.am
index 67d451b..e6a34bb 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1743,11 +1743,11 @@ module_match_la_LIBADD = $(MODULE_LIBADD)
 
 module_tunnel_sink_new_la_SOURCES = modules/module-tunnel-sink-new.c
 module_tunnel_sink_new_la_LDFLAGS = $(MODULE_LDFLAGS)
-module_tunnel_sink_new_la_LIBADD = $(MODULE_LIBADD)
+module_tunnel_sink_new_la_LIBADD = $(MODULE_LIBADD) libtunnel-manager.la
 
 module_tunnel_source_new_la_SOURCES = modules/module-tunnel-source-new.c
 module_tunnel_source_new_la_LDFLAGS = $(MODULE_LDFLAGS)
-module_tunnel_source_new_la_LIBADD = $(MODULE_LIBADD)
+module_tunnel_source_new_la_LIBADD = $(MODULE_LIBADD) libtunnel-manager.la
 
 module_tunnel_sink_la_SOURCES = modules/module-tunnel.c
 module_tunnel_sink_la_CFLAGS = -DTUNNEL_SINK=1 $(AM_CFLAGS) $(X11_CFLAGS)
diff --git a/src/modules/module-tunnel-sink-new.c b/src/modules/module-tunnel-sink-new.c
index 7d3bd99..c49f11d 100644
--- a/src/modules/module-tunnel-sink-new.c
+++ b/src/modules/module-tunnel-sink-new.c
@@ -23,6 +23,8 @@
 #include <config.h>
 #endif
 
+#include <modules/tunnel-manager/remote-device.h>
+
 #include <pulse/context.h>
 #include <pulse/timeval.h>
 #include <pulse/xmalloc.h>
@@ -87,8 +89,20 @@ struct userdata {
     char *cookie_file;
     char *remote_server;
     char *remote_sink_name;
+    pa_proplist *user_proplist;
+
+    struct remote_device_data *remote_device_data;
+};
+
+struct remote_device_data {
+    struct userdata *userdata;
+    pa_tunnel_manager_remote_device *device;
+    pa_hook_slot *unlinked_slot;
+    pa_hook_slot *proplist_changed_slot;
 };
 
+static void remote_device_data_free(struct remote_device_data *data);
+
 static const char* const valid_modargs[] = {
     "sink_name",
     "sink_properties",
@@ -103,6 +117,68 @@ static const char* const valid_modargs[] = {
     NULL,
 };
 
+static pa_hook_result_t remote_device_unlinked_cb(void *hook_data, void *call_data, void *userdata) {
+    struct remote_device_data *data = userdata;
+
+    pa_assert(data);
+
+    remote_device_data_free(data);
+
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t remote_device_proplist_changed_cb(void *hook_data, void *call_data, void *userdata) {
+    pa_tunnel_manager_remote_device *device = hook_data;
+    struct remote_device_data *data = userdata;
+    pa_proplist *proplist;
+
+    pa_assert(device);
+    pa_assert(data);
+
+    proplist = pa_proplist_copy(device->proplist);
+
+    if (data->userdata->user_proplist)
+        pa_proplist_update(proplist, PA_UPDATE_REPLACE, data->userdata->user_proplist);
+
+    pa_sink_update_proplist(data->userdata->sink, PA_UPDATE_SET, proplist);
+    pa_proplist_free(proplist);
+
+    return PA_HOOK_OK;
+}
+
+static void remote_device_data_new(struct userdata *u, pa_tunnel_manager_remote_device *device) {
+    struct remote_device_data *data;
+
+    pa_assert(u);
+    pa_assert(device);
+
+    data = pa_xnew0(struct remote_device_data, 1);
+    data->userdata = u;
+    data->device = device;
+    data->unlinked_slot = pa_hook_connect(&device->hooks[PA_TUNNEL_MANAGER_REMOTE_DEVICE_HOOK_UNLINKED], PA_HOOK_NORMAL,
+                                          remote_device_unlinked_cb, data);
+    data->proplist_changed_slot = pa_hook_connect(&device->hooks[PA_TUNNEL_MANAGER_REMOTE_DEVICE_HOOK_PROPLIST_CHANGED],
+                                                  PA_HOOK_NORMAL, remote_device_proplist_changed_cb, data);
+
+    pa_assert(!u->remote_device_data);
+    u->remote_device_data = data;
+}
+
+static void remote_device_data_free(struct remote_device_data *data) {
+    pa_assert(data);
+
+    if (data->userdata)
+        data->userdata->remote_device_data = NULL;
+
+    if (data->proplist_changed_slot)
+        pa_hook_slot_free(data->proplist_changed_slot);
+
+    if (data->unlinked_slot)
+        pa_hook_slot_free(data->unlinked_slot);
+
+    pa_xfree(data);
+}
+
 static void cork_stream(struct userdata *u, bool cork) {
     pa_operation *operation;
 
@@ -463,13 +539,6 @@ int pa__init(pa_module *m) {
         goto fail;
     }
 
-    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) {
-        pa_log("Invalid sample format specification or channel map");
-        goto fail;
-    }
-
     remote_server = pa_modargs_get_value(ma, "server", NULL);
     if (!remote_server) {
         pa_log("No server given!");
@@ -489,6 +558,41 @@ int pa__init(pa_module *m) {
     u->cookie_file = pa_xstrdup(pa_modargs_get_value(ma, "cookie", NULL));
     u->remote_sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL));
 
+    if (u->remote_sink_name) {
+        pa_tunnel_manager *manager;
+
+        manager = pa_tunnel_manager_get(m->core, false);
+        if (manager) {
+            pa_tunnel_manager_remote_server *server;
+            void *state;
+
+            PA_HASHMAP_FOREACH(server, manager->remote_servers, state) {
+                if (pa_streq(server->address, u->remote_server)) {
+                    pa_tunnel_manager_remote_device *device;
+
+                    device = pa_hashmap_get(server->devices, u->remote_sink_name);
+                    if (device)
+                        remote_device_data_new(u, device);
+
+                    break;
+                }
+            }
+        }
+    }
+
+    if (u->remote_device_data) {
+        ss = u->remote_device_data->device->sample_spec;
+        map = u->remote_device_data->device->channel_map;
+    } else {
+        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) {
+        pa_log("Invalid sample format specification or channel map");
+        goto fail;
+    }
+
     u->thread_mq = pa_xnew0(pa_thread_mq, 1);
     pa_thread_mq_init_thread_mainloop(u->thread_mq, m->core->mainloop, u->thread_mainloop_api);
 
@@ -504,17 +608,27 @@ int pa__init(pa_module *m) {
     pa_sink_new_data_set_sample_spec(&sink_data, &ss);
     pa_sink_new_data_set_channel_map(&sink_data, &map);
 
-    pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_CLASS, "sound");
-    pa_proplist_setf(sink_data.proplist,
-                     PA_PROP_DEVICE_DESCRIPTION,
-                     _("Tunnel to %s/%s"),
-                     remote_server,
-                     pa_strempty(u->remote_sink_name));
+    if (u->remote_device_data)
+        pa_proplist_update(sink_data.proplist, PA_UPDATE_SET, u->remote_device_data->device->proplist);
+    else {
+        pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_CLASS, "sound");
+        pa_proplist_setf(sink_data.proplist,
+                         PA_PROP_DEVICE_DESCRIPTION,
+                         _("Tunnel to %s/%s"),
+                         remote_server,
+                         pa_strempty(u->remote_sink_name));
+    }
+
+    if (pa_modargs_get_value(ma, "sink_properties", NULL)) {
+        u->user_proplist = pa_proplist_new();
 
-    if (pa_modargs_get_proplist(ma, "sink_properties", sink_data.proplist, PA_UPDATE_REPLACE) < 0) {
-        pa_log("Invalid properties");
-        pa_sink_new_data_done(&sink_data);
-        goto fail;
+        if (pa_modargs_get_proplist(ma, "sink_properties", u->user_proplist, PA_UPDATE_SET) < 0) {
+            pa_log("Invalid properties");
+            pa_sink_new_data_done(&sink_data);
+            goto fail;
+        }
+
+        pa_proplist_update(sink_data.proplist, PA_UPDATE_REPLACE, u->user_proplist);
     }
     if (!(u->sink = pa_sink_new(m->core, &sink_data, PA_SINK_LATENCY | PA_SINK_DYNAMIC_LATENCY | PA_SINK_NETWORK))) {
         pa_log("Failed to create sink.");
@@ -565,6 +679,12 @@ void pa__done(pa_module *m) {
     if (u->sink)
         pa_sink_unlink(u->sink);
 
+    if (u->remote_device_data)
+        remote_device_data_free(u->remote_device_data);
+
+    if (u->user_proplist)
+        pa_proplist_free(u->user_proplist);
+
     if (u->thread) {
         pa_asyncmsgq_send(u->thread_mq->inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
         pa_thread_free(u->thread);
diff --git a/src/modules/module-tunnel-source-new.c b/src/modules/module-tunnel-source-new.c
index c6580eb..e8b637b 100644
--- a/src/modules/module-tunnel-source-new.c
+++ b/src/modules/module-tunnel-source-new.c
@@ -23,6 +23,8 @@
 #include <config.h>
 #endif
 
+#include <modules/tunnel-manager/remote-device.h>
+
 #include <pulse/context.h>
 #include <pulse/timeval.h>
 #include <pulse/xmalloc.h>
@@ -85,8 +87,20 @@ struct userdata {
     char *cookie_file;
     char *remote_server;
     char *remote_source_name;
+    pa_proplist *user_proplist;
+
+    struct remote_device_data *remote_device_data;
+};
+
+struct remote_device_data {
+    struct userdata *userdata;
+    pa_tunnel_manager_remote_device *device;
+    pa_hook_slot *unlinked_slot;
+    pa_hook_slot *proplist_changed_slot;
 };
 
+static void remote_device_data_free(struct remote_device_data *data);
+
 static const char* const valid_modargs[] = {
     "source_name",
     "source_properties",
@@ -101,6 +115,68 @@ static const char* const valid_modargs[] = {
     NULL,
 };
 
+static pa_hook_result_t remote_device_unlinked_cb(void *hook_data, void *call_data, void *userdata) {
+    struct remote_device_data *data = userdata;
+
+    pa_assert(data);
+
+    remote_device_data_free(data);
+
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t remote_device_proplist_changed_cb(void *hook_data, void *call_data, void *userdata) {
+    pa_tunnel_manager_remote_device *device = hook_data;
+    struct remote_device_data *data = userdata;
+    pa_proplist *proplist;
+
+    pa_assert(device);
+    pa_assert(data);
+
+    proplist = pa_proplist_copy(device->proplist);
+
+    if (data->userdata->user_proplist)
+        pa_proplist_update(proplist, PA_UPDATE_REPLACE, data->userdata->user_proplist);
+
+    pa_source_update_proplist(data->userdata->source, PA_UPDATE_SET, proplist);
+    pa_proplist_free(proplist);
+
+    return PA_HOOK_OK;
+}
+
+static void remote_device_data_new(struct userdata *u, pa_tunnel_manager_remote_device *device) {
+    struct remote_device_data *data;
+
+    pa_assert(u);
+    pa_assert(device);
+
+    data = pa_xnew0(struct remote_device_data, 1);
+    data->userdata = u;
+    data->device = device;
+    data->unlinked_slot = pa_hook_connect(&device->hooks[PA_TUNNEL_MANAGER_REMOTE_DEVICE_HOOK_UNLINKED], PA_HOOK_NORMAL,
+                                          remote_device_unlinked_cb, data);
+    data->proplist_changed_slot = pa_hook_connect(&device->hooks[PA_TUNNEL_MANAGER_REMOTE_DEVICE_HOOK_PROPLIST_CHANGED],
+                                                  PA_HOOK_NORMAL, remote_device_proplist_changed_cb, data);
+
+    pa_assert(!u->remote_device_data);
+    u->remote_device_data = data;
+}
+
+static void remote_device_data_free(struct remote_device_data *data) {
+    pa_assert(data);
+
+    if (data->userdata)
+        data->userdata->remote_device_data = NULL;
+
+    if (data->proplist_changed_slot)
+        pa_hook_slot_free(data->proplist_changed_slot);
+
+    if (data->unlinked_slot)
+        pa_hook_slot_free(data->unlinked_slot);
+
+    pa_xfree(data);
+}
+
 static void cork_stream(struct userdata *u, bool cork) {
     pa_operation *operation;
 
@@ -471,13 +547,6 @@ int pa__init(pa_module *m) {
         goto fail;
     }
 
-    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) {
-        pa_log("Invalid sample format specification or channel map");
-        goto fail;
-    }
-
     remote_server = pa_modargs_get_value(ma, "server", NULL);
     if (!remote_server) {
         pa_log("No server given!");
@@ -497,6 +566,41 @@ int pa__init(pa_module *m) {
     u->cookie_file = pa_xstrdup(pa_modargs_get_value(ma, "cookie", NULL));
     u->remote_source_name = pa_xstrdup(pa_modargs_get_value(ma, "source", NULL));
 
+    if (u->remote_source_name) {
+        pa_tunnel_manager *manager;
+
+        manager = pa_tunnel_manager_get(m->core, false);
+        if (manager) {
+            pa_tunnel_manager_remote_server *server;
+            void *state;
+
+            PA_HASHMAP_FOREACH(server, manager->remote_servers, state) {
+                if (pa_streq(server->address, u->remote_server)) {
+                    pa_tunnel_manager_remote_device *device;
+
+                    device = pa_hashmap_get(server->devices, u->remote_source_name);
+                    if (device)
+                        remote_device_data_new(u, device);
+
+                    break;
+                }
+            }
+        }
+    }
+
+    if (u->remote_device_data) {
+        ss = u->remote_device_data->device->sample_spec;
+        map = u->remote_device_data->device->channel_map;
+    } else {
+        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) {
+        pa_log("Invalid sample format specification or channel map");
+        goto fail;
+    }
+
     u->thread_mq = pa_xnew0(pa_thread_mq, 1);
     pa_thread_mq_init_thread_mainloop(u->thread_mq, m->core->mainloop, u->thread_mainloop_api);
 
@@ -512,18 +616,29 @@ int pa__init(pa_module *m) {
     pa_source_new_data_set_sample_spec(&source_data, &ss);
     pa_source_new_data_set_channel_map(&source_data, &map);
 
-    pa_proplist_sets(source_data.proplist, PA_PROP_DEVICE_CLASS, "sound");
-    pa_proplist_setf(source_data.proplist,
-                     PA_PROP_DEVICE_DESCRIPTION,
-                     _("Tunnel to %s/%s"),
-                     remote_server,
-                     pa_strempty(u->remote_source_name));
+    if (u->remote_device_data)
+        pa_proplist_update(source_data.proplist, PA_UPDATE_SET, u->remote_device_data->device->proplist);
+    else {
+        pa_proplist_sets(source_data.proplist, PA_PROP_DEVICE_CLASS, "sound");
+        pa_proplist_setf(source_data.proplist,
+                         PA_PROP_DEVICE_DESCRIPTION,
+                         _("Tunnel to %s/%s"),
+                         remote_server,
+                         pa_strempty(u->remote_source_name));
+    }
 
-    if (pa_modargs_get_proplist(ma, "source_properties", source_data.proplist, PA_UPDATE_REPLACE) < 0) {
-        pa_log("Invalid properties");
-        pa_source_new_data_done(&source_data);
-        goto fail;
+    if (pa_modargs_get_value(ma, "source_properties", NULL)) {
+        u->user_proplist = pa_proplist_new();
+
+        if (pa_modargs_get_proplist(ma, "source_properties", u->user_proplist, PA_UPDATE_SET) < 0) {
+            pa_log("Invalid properties");
+            pa_source_new_data_done(&source_data);
+            goto fail;
+        }
+
+        pa_proplist_update(source_data.proplist, PA_UPDATE_REPLACE, u->user_proplist);
     }
+
     if (!(u->source = pa_source_new(m->core, &source_data, PA_SOURCE_LATENCY | PA_SOURCE_DYNAMIC_LATENCY | PA_SOURCE_NETWORK))) {
         pa_log("Failed to create source.");
         pa_source_new_data_done(&source_data);
@@ -571,6 +686,12 @@ void pa__done(pa_module *m) {
     if (u->source)
         pa_source_unlink(u->source);
 
+    if (u->remote_device_data)
+        remote_device_data_free(u->remote_device_data);
+
+    if (u->user_proplist)
+        pa_proplist_free(u->user_proplist);
+
     if (u->thread) {
         pa_asyncmsgq_send(u->thread_mq->inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
         pa_thread_free(u->thread);
-- 
1.9.3



More information about the pulseaudio-discuss mailing list