[pulseaudio-discuss] [PATCH 18/30] skoa-router: Rescue streams on port changes

Tanu Kaskinen tanu.kaskinen at linux.intel.com
Thu Jan 16 07:02:44 PST 2014


In the future, when port changes on a device, streams connected to
that device will be killed, unless a router module rescues the streams
first. This patch implements that rescue logic in module-skoa-router.
---
 src/modules/module-skoa-router.c | 59 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 59 insertions(+)

diff --git a/src/modules/module-skoa-router.c b/src/modules/module-skoa-router.c
index d532e54..23796cf 100644
--- a/src/modules/module-skoa-router.c
+++ b/src/modules/module-skoa-router.c
@@ -35,6 +35,7 @@ PA_MODULE_LOAD_ONCE(true);
 
 struct userdata {
     pa_hook_slot *card_set_profile_slot;
+    pa_hook_slot *device_set_port_slot;
 };
 
 static pa_hook_result_t card_set_profile_cb(void *hook_data, void *call_data, void *userdata) {
@@ -140,6 +141,59 @@ static pa_hook_result_t card_set_profile_cb(void *hook_data, void *call_data, vo
     return PA_HOOK_OK;
 }
 
+static pa_hook_result_t device_set_port_cb(void *hook_data, void *call_data, void *userdata) {
+    pa_device_set_port_hook_data *data = call_data;
+    pa_sink *sink = NULL;
+    pa_source *source = NULL;
+    const char *device_name;
+    pa_queue *streams = NULL;
+
+    pa_assert(data);
+
+    /* When the port changes, streams connected to the device are killed. Here
+     * we prevent that by detaching the streams before the port switch, and
+     * attaching them to the same device after the port switch. */
+
+    if (data->port->direction == PA_DIRECTION_OUTPUT) {
+        sink = data->port->device;
+        device_name = sink->name;
+        streams = pa_sink_move_all_start(sink, streams);
+    } else {
+        source = data->port->device;
+        device_name = source->name;
+        streams = pa_source_move_all_start(source, streams);
+    }
+
+    if (!pa_queue_isempty(streams))
+        pa_log_debug("Started to move streams away from device %s.", device_name);
+
+    if (sink)
+        data->ret = pa_sink_set_port(sink, data->port, data->save, true);
+    else
+        data->ret = pa_source_set_port(source, data->port, data->save, true);
+
+    data->ret_valid = true;
+
+    if (data->ret >= 0) {
+        if (sink)
+            pa_sink_move_all_finish(sink, streams, false);
+        else
+            pa_source_move_all_finish(source, streams, false);
+
+        pa_log_debug("Finished moving streams to device %s.", device_name);
+    } else {
+        if (!pa_queue_isempty(streams))
+            pa_log("Port change failed, have to fail the stream rescue operation.");
+
+        if (sink)
+            pa_sink_move_all_fail(streams);
+        else
+            pa_source_move_all_fail(streams);
+    }
+
+    return PA_HOOK_OK;
+}
+
 int pa__init(pa_module *module) {
     struct userdata *u;
 
@@ -148,6 +202,8 @@ int pa__init(pa_module *module) {
     module->userdata = u = pa_xnew0(struct userdata, 1);
     u->card_set_profile_slot = pa_hook_connect(&module->core->hooks[PA_CORE_HOOK_CARD_SET_PROFILE], PA_HOOK_NORMAL,
                                                card_set_profile_cb, NULL);
+    u->device_set_port_slot = pa_hook_connect(&module->core->hooks[PA_CORE_HOOK_DEVICE_SET_PORT], PA_HOOK_NORMAL,
+                                              device_set_port_cb, NULL);
 
     return 0;
 }
@@ -160,6 +216,9 @@ void pa__done(pa_module *module) {
     if (!(u = module->userdata))
         return;
 
+    if (u->device_set_port_slot)
+        pa_hook_slot_free(u->device_set_port_slot);
+
     if (u->card_set_profile_slot)
         pa_hook_slot_free(u->card_set_profile_slot);
 
-- 
1.8.3.1



More information about the pulseaudio-discuss mailing list