tizenaudio-policy: Preparation for new loopback module management 64/255464/7
authorSangchul Lee <sc11.lee@samsung.com>
Thu, 18 Mar 2021 23:58:42 +0000 (08:58 +0900)
committerSangchul Lee <sc11.lee@samsung.com>
Wed, 7 Apr 2021 08:34:02 +0000 (17:34 +0900)
[Version] 13.0.59
[Issue Type] Improvement

Change-Id: I1fa78fdc41913f0db7e8d08b0ebe4d4c33b21c62
Signed-off-by: Sangchul Lee <sc11.lee@samsung.com>
packaging/pulseaudio-modules-tizen.spec
src/module-tizenaudio-policy.c

index 0b48635..e0f63c5 100644 (file)
@@ -1,6 +1,6 @@
 Name:             pulseaudio-modules-tizen
 Summary:          Pulseaudio modules for Tizen
-Version:          13.0.58
+Version:          13.0.59
 Release:          0
 Group:            Multimedia/Audio
 License:          LGPL-2.1+
index c18391c..bb3a727 100644 (file)
@@ -150,6 +150,12 @@ static device_type_t convert_device_type_str(const char *device)
     return DEVICE_UNKNOWN;
 }
 
+typedef struct _loopback_module {
+    pa_sink *sink;
+    pa_source *source;
+    pa_module *module;
+} loopback_module;
+
 struct userdata {
     pa_core *core;
     pa_module *module;
@@ -172,6 +178,7 @@ struct userdata {
     uint32_t module_null_sink_index;
     uint32_t module_null_source_index;
     pa_module *module_loopback;
+    pa_hashmap *loopback_modules;
     struct {
         int32_t latency_msec;
         int32_t adjust_sec;
@@ -446,6 +453,134 @@ static void update_bt_sco_option(struct userdata *u, const char* role) {
     }
 }
 
+static void update_loopback_module_args(struct userdata* u, int32_t parent_id, pa_sink *sink, pa_source *source)
+{
+    loopback_module *loopback;
+
+    pa_assert(u);
+
+    if (parent_id < 0) {
+        pa_log_error("invalid parent_id(%d)", parent_id);
+        return;
+    }
+
+    loopback = pa_hashmap_get(u->loopback_modules, (const void*)parent_id);
+    if (!loopback) {
+        loopback = pa_xnew0(loopback_module, 1);
+        pa_hashmap_put(u->loopback_modules, (void*)parent_id, loopback);
+    }
+    if (sink)
+        loopback->sink = sink;
+    if (source)
+        loopback->source = source;
+
+    pa_log_info("loopback module for parent_id(%d) is updated, sink(%s), source(%s)",
+        parent_id, loopback->sink ? loopback->sink->name : "null", loopback->source ? loopback->source->name : "null");
+}
+
+static void load_loopback_module_by_parent_id(struct userdata* u, int32_t parent_id)
+{
+    loopback_module *loopback;
+    char *args;
+    const char *volume_type;
+
+    pa_assert(u);
+
+    if (parent_id < 0) {
+        pa_log_error("invalid parent_id(%d)", parent_id);
+        return;
+    }
+
+    loopback = pa_hashmap_get(u->loopback_modules, (const void*)parent_id);
+    if (!loopback) {
+        pa_log_error("could not find loopback module for parent_id(%d)", parent_id);
+        return;
+    }
+
+    if (!loopback->sink || !loopback->source) {
+        pa_log_debug("sink(%p) or source(%p) is not set", loopback->sink, loopback->source);
+        return;
+    }
+
+    if (!u->loopback_args.latency_msec)
+        u->loopback_args.latency_msec = LOOPBACK_DEFAULT_LATENCY_MSEC;
+    if (!u->loopback_args.adjust_sec)
+        u->loopback_args.adjust_sec = LOOPBACK_DEFAULT_ADJUST_SEC;
+
+    volume_type = pa_stream_manager_get_volume_type(u->stream_manager, STREAM_SINK_INPUT, STREAM_ROLE_LOOPBACK);
+    args = pa_sprintf_malloc("sink=%s source=%s latency_msec=%d adjust_time=%d sink_input_properties=%s=%s",
+                             loopback->sink->name, loopback->source->name,
+                             u->loopback_args.latency_msec, u->loopback_args.adjust_sec,
+                             PA_PROP_MEDIA_TIZEN_VOLUME_TYPE, volume_type);
+
+    if (pa_module_load(&loopback->module, u->core, MODULE_LOOPBACK, args))
+        pa_log_error("failed to load module-loopback for parent_id(%d) with (%s)", parent_id, args);
+    else
+        pa_log_info("load module-loopback(%p) for parent_id(%d) with (%s)", loopback->module, parent_id, args);
+
+    pa_xfree(args);
+}
+
+static void unload_loopback_modules_by_device_disconnect(struct userdata* u, pa_sink *sink, pa_source *source)
+{
+    loopback_module *loopback;
+    int32_t parent_id;
+    void *state;
+
+    pa_assert(u);
+
+    pa_log_info("disconnected sink(%s), source(%s)", sink ? sink->name : "null", source ? source->name : "null");
+
+    PA_HASHMAP_FOREACH_KV(parent_id, loopback, u->loopback_modules, state) {
+        if (loopback->module &&
+           ((sink && (loopback->sink == sink)) ||
+           (source && (loopback->source == source)))) {
+            pa_log_info("  -- unload module-loopback(%p) for parent_id(%d)", loopback->module, parent_id);
+            pa_hashmap_remove_and_free(u->loopback_modules, (const void*)parent_id);
+        }
+    }
+}
+
+static void unload_loopback_modules_by_stream_disconnect(struct userdata* u, int32_t parent_id, pa_sink_input *i, pa_source_output *o)
+{
+    loopback_module *loopback;
+
+    pa_assert(u);
+
+    if (parent_id < 0)
+        return;
+
+    if (!i && !o)
+        return;
+
+    loopback = pa_hashmap_get(u->loopback_modules, (const void*)parent_id);
+    if (!loopback)
+        return;
+
+    if (!loopback->module) {
+        pa_log_info("module is not loaded yet");
+        return;
+    }
+
+    pa_log_info("disconnected sink-input(%p) or source-output(%p) of parent_id(%d)", i, o, parent_id);
+
+    if (i && loopback->sink)
+        if (pa_idxset_get_by_data(loopback->sink->inputs, i, NULL) && pa_idxset_size(loopback->sink->inputs))
+            goto unload;
+
+    if (o && loopback->source)
+        if (pa_idxset_get_by_data(loopback->source->outputs, o, NULL) && pa_idxset_size(loopback->source->outputs))
+            goto unload;
+
+    pa_log_warn("no loopback module to be unloaded with parent_id(%d), sink-input(%p), source-output(%p)", parent_id, i, o);
+
+    return;
+
+unload:
+    pa_log_info("  -- unload module-loopback(%p) for parent_id(%d)", loopback->module, parent_id);
+    pa_hashmap_remove_and_free(u->loopback_modules, (const void*)parent_id);
+}
+
 /* Load/Unload module-loopback */
 static void update_loopback_module(struct userdata *u, bool load) {
     char *args = NULL;
@@ -1801,6 +1936,16 @@ static pa_hook_result_t device_connection_changed_hook_cb(pa_core *c, pa_tz_devi
     return PA_HOOK_OK;
 }
 
+static void loopback_module_free(loopback_module *loopback) {
+    pa_assert(loopback);
+
+    pa_log_info("unload module-loopback(%p)", loopback->module);
+
+    pa_module_unload(loopback->module, true);
+
+    pa_xfree(loopback);
+}
+
 int pa__init(pa_module *m)
 {
     pa_modargs *ma = NULL;
@@ -1862,6 +2007,8 @@ int pa__init(pa_module *m)
         u->module_null_source_index = module_loaded->index;
     pa_xfree(args);
 
+    u->loopback_modules = pa_hashmap_new_full(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func, NULL, (pa_free_cb_t)loopback_module_free);
+
     __load_dump_config(u);
 
     pa_log_info("Tizen Audio Policy module is loaded\n");
@@ -1888,6 +2035,11 @@ void pa__done(pa_module *m)
 
     bt_sco_close(u, false);
 
+    if (u->loopback_modules) {
+        pa_hashmap_remove_all(u->loopback_modules);
+        pa_hashmap_free(u->loopback_modules);
+    }
+
     if (u->module_null_sink_index != PA_INVALID_INDEX)
         pa_module_unload_by_index(m->core, u->module_null_sink_index, true);