[pulseaudio-discuss] [PATCH v0 18/20] bluetooth: Handle suspend in module-bluetooth-policy

Mikel Astiz mikel.astiz.oss at gmail.com
Wed Aug 22 01:08:31 PDT 2012


From: Mikel Astiz <mikel.astiz at bmw-carit.de>

Load module-loopback only while the sink or source is not suspended. If
it enters suspend state after the module was loaded, this module should
be unloaded.

This patch is required in order to avoid module-bluetooth-policy always
resuming an IDLE device, therefore undesirably requesting the SCO link
for HFGW use-cases.
---
 src/modules/bluetooth/module-bluetooth-policy.c |   43 ++++++++++++++++++++---
 1 files changed, 38 insertions(+), 5 deletions(-)

diff --git a/src/modules/bluetooth/module-bluetooth-policy.c b/src/modules/bluetooth/module-bluetooth-policy.c
index c5db1d3..a53d47d 100644
--- a/src/modules/bluetooth/module-bluetooth-policy.c
+++ b/src/modules/bluetooth/module-bluetooth-policy.c
@@ -54,6 +54,9 @@ struct userdata {
     bool enable_hfgw;
     pa_hook_slot *source_put_slot;
     pa_hook_slot *sink_put_slot;
+    pa_hook_slot *source_state_changed_slot;
+    pa_hook_slot *sink_state_changed_slot;
+    pa_hashmap *loaded_modules;
 };
 
 static const char *get_bluetooth_protocol(pa_proplist *p) {
@@ -72,6 +75,8 @@ static const char *get_bluetooth_protocol(pa_proplist *p) {
 
 static pa_hook_result_t device_hook_callback(pa_core *c, pa_object *o, struct userdata *u) {
     char *args;
+    pa_module *module;
+    void *old_module;
 
     pa_assert(c);
     pa_assert(o);
@@ -79,11 +84,12 @@ static pa_hook_result_t device_hook_callback(pa_core *c, pa_object *o, struct us
 
     if (pa_sink_isinstance(o)) {
         pa_sink *sink = PA_SINK(o);
+        pa_sink_state_t state = pa_sink_get_state(sink);
         const char *protocol = get_bluetooth_protocol(sink->proplist);
         const char *role;
 
-        if (protocol == NULL)
-            return PA_HOOK_OK;
+        if (protocol == NULL || state != PA_SINK_IDLE)
+            goto unload;
 
         if (u->enable_hfgw && pa_streq(protocol, "hfgw")) /* HFP profile (we're doing headset role) */
             role = "phone";
@@ -95,11 +101,12 @@ static pa_hook_result_t device_hook_callback(pa_core *c, pa_object *o, struct us
         args = pa_sprintf_malloc("sink=\"%s\" sink_dont_move=\"true\" source_output_properties=\"media.role=%s\"", sink->name, role);
     } else if (pa_source_isinstance(o)) {
         pa_source *source = PA_SOURCE(o);
+        pa_source_state_t state = pa_source_get_state(source);
         const char *protocol = get_bluetooth_protocol(source->proplist);
         const char *role;
 
-        if (protocol == NULL)
-            return PA_HOOK_OK;
+        if (protocol == NULL || state != PA_SOURCE_IDLE)
+            goto unload;
 
         if (u->enable_a2dp_source && pa_streq(protocol, "a2dp_source")) /* A2DP profile (we're doing sink role) */
             role = "music";
@@ -114,11 +121,24 @@ static pa_hook_result_t device_hook_callback(pa_core *c, pa_object *o, struct us
     } else
         return PA_HOOK_OK;
 
+    if (pa_hashmap_get(u->loaded_modules, o) != NULL) {
+        pa_xfree(args);
+        return PA_HOOK_OK;
+    }
+
     /* Load module-loopback */
-    (void) pa_module_load(c, "module-loopback", args);
+    if ((module = pa_module_load(c, "module-loopback", args)) != NULL)
+        pa_hashmap_put(u->loaded_modules, o, PA_UINT32_TO_PTR(module->index));
+
     pa_xfree(args);
 
     return PA_HOOK_OK;
+
+unload:
+    if ((old_module = pa_hashmap_remove(u->loaded_modules, o)) != NULL)
+        pa_module_unload_by_index(c, PA_PTR_TO_UINT32(old_module), TRUE);
+
+    return PA_HOOK_OK;
 }
 
 int pa__init(pa_module *m) {
@@ -134,6 +154,8 @@ int pa__init(pa_module *m) {
 
     m->userdata = u = pa_xnew(struct userdata, 1);
 
+    u->loaded_modules = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
+
     u->enable_a2dp_source = TRUE;
     if (pa_modargs_get_value_boolean(ma, "a2dp_source", &u->enable_a2dp_source) < 0) {
         pa_log("Failed to parse a2dp_source argument.");
@@ -150,6 +172,10 @@ int pa__init(pa_module *m) {
 
     u->sink_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_NORMAL, (pa_hook_cb_t) device_hook_callback, u);
 
+    u->sink_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) device_hook_callback, u);
+
+    u->source_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_STATE_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) device_hook_callback, u);
+
     pa_modargs_free(ma);
     return 0;
 
@@ -172,5 +198,12 @@ void pa__done(pa_module *m) {
     if (u->sink_put_slot)
         pa_hook_slot_free(u->sink_put_slot);
 
+    if (u->source_state_changed_slot)
+        pa_hook_slot_free(u->source_state_changed_slot);
+
+    if (u->sink_state_changed_slot)
+        pa_hook_slot_free(u->sink_state_changed_slot);
+
+    pa_hashmap_free(u->loaded_modules, NULL, NULL);
     pa_xfree(u);
 }
-- 
1.7.7.6



More information about the pulseaudio-discuss mailing list