[pulseaudio-discuss] [PATCH v1 16/18] bluetooth: Handle suspend in module-bluetooth-policy
Mikel Astiz
mikel.astiz.oss at gmail.com
Mon Aug 27 08:24:11 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 | 68 ++++++++++++++++++++---
1 files changed, 60 insertions(+), 8 deletions(-)
diff --git a/src/modules/bluetooth/module-bluetooth-policy.c b/src/modules/bluetooth/module-bluetooth-policy.c
index 03beeb2..0e1ad34 100644
--- a/src/modules/bluetooth/module-bluetooth-policy.c
+++ b/src/modules/bluetooth/module-bluetooth-policy.c
@@ -36,7 +36,7 @@
#include "module-bluetooth-policy-symdef.h"
PA_MODULE_AUTHOR("Frédéric Dalleau");
-PA_MODULE_DESCRIPTION("When a bluetooth sink or source is added, load module-loopback");
+PA_MODULE_DESCRIPTION("When a bluetooth sink or source is added and idle, load module-loopback");
PA_MODULE_VERSION(PACKAGE_VERSION);
PA_MODULE_LOAD_ONCE(TRUE);
PA_MODULE_USAGE(
@@ -54,14 +54,18 @@ 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;
};
/* When a source is created, loopback it to default sink */
-static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, void *userdata) {
+static pa_hook_result_t source_hook_callback(pa_core *c, pa_source *source, void *userdata) {
struct userdata *u = userdata;
const char *s;
const char *role;
char *args;
+ pa_module *module;
pa_assert(c);
pa_assert(source);
@@ -87,20 +91,38 @@ static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source,
return PA_HOOK_OK;
}
+ /* Load module only if idle, and unload if necessary otherwise */
+ if (pa_source_get_state(source) != PA_SOURCE_IDLE) {
+ void *old = pa_hashmap_remove(u->loaded_modules, source);
+
+ if (old != NULL)
+ pa_module_unload_by_index(c, PA_PTR_TO_UINT32(old), TRUE);
+
+ return PA_HOOK_OK;
+ }
+
+ /* Check if module already loaded */
+ if (pa_hashmap_get(u->loaded_modules, source) != NULL)
+ return PA_HOOK_OK;
+
/* Load module-loopback */
args = pa_sprintf_malloc("source=\"%s\" source_dont_move=\"true\" sink_input_properties=\"media.role=%s\"", source->name, role);
- (void) pa_module_load(c, "module-loopback", args);
+
+ if ((module = pa_module_load(c, "module-loopback", args)) != NULL)
+ pa_hashmap_put(u->loaded_modules, source, PA_UINT32_TO_PTR(module->index));
+
pa_xfree(args);
return PA_HOOK_OK;
}
-/* When a sink is created, loopback it to default source */
-static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void *userdata) {
+/* When a sink is created and idle, loopback it to default source */
+static pa_hook_result_t sink_hook_callback(pa_core *c, pa_sink *sink, void *userdata) {
struct userdata *u = userdata;
const char *s;
const char *role;
char *args;
+ pa_module *module;
pa_assert(c);
pa_assert(sink);
@@ -124,9 +146,26 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void *
return PA_HOOK_OK;
}
+ /* Load module only if idle, and unload if necessary otherwise */
+ if (pa_sink_get_state(sink) != PA_SINK_IDLE) {
+ void *old = pa_hashmap_remove(u->loaded_modules, sink);
+
+ if (old != NULL)
+ pa_module_unload_by_index(c, PA_PTR_TO_UINT32(old), TRUE);
+
+ return PA_HOOK_OK;
+ }
+
+ /* Check if module already loaded */
+ if (pa_hashmap_get(u->loaded_modules, sink) != NULL)
+ return PA_HOOK_OK;
+
/* Load module-loopback */
args = pa_sprintf_malloc("sink=\"%s\" sink_dont_move=\"true\" source_output_properties=\"media.role=%s\"", sink->name, role);
- (void) pa_module_load(c, "module-loopback", args);
+
+ if ((module = pa_module_load(c, "module-loopback", args)) != NULL)
+ pa_hashmap_put(u->loaded_modules, sink, PA_UINT32_TO_PTR(module->index));
+
pa_xfree(args);
return PA_HOOK_OK;
@@ -145,6 +184,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.");
@@ -157,9 +198,13 @@ int pa__init(pa_module *m) {
goto fail;
}
- u->source_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_PUT], PA_HOOK_NORMAL, (pa_hook_cb_t) source_put_hook_callback, u);
+ u->source_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_PUT], PA_HOOK_NORMAL, (pa_hook_cb_t) source_hook_callback, u);
+
+ u->sink_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_NORMAL, (pa_hook_cb_t) sink_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) sink_hook_callback, u);
- u->sink_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_NORMAL, (pa_hook_cb_t) sink_put_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) source_hook_callback, u);
pa_modargs_free(ma);
return 0;
@@ -183,5 +228,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