Previously the userdata for the volume callbacks was saved to pa_core.shared only once when loading module-bluetooth-device, and only when the SCO over PCM feature was used. That breaks volume handling in cases where the HSP profile is used without the SCO over PCM setup. Now the userdata is set always when a sink or source is created, and removed when a sink or source is removed. --- src/modules/bluetooth/module-bluetooth-device.c | 101 +++++++++++++++------- 1 files changed, 69 insertions(+), 32 deletions(-) diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c index 540d48c..fd82ece 100644 --- a/src/modules/bluetooth/module-bluetooth-device.c +++ b/src/modules/bluetooth/module-bluetooth-device.c @@ -1961,6 +1961,8 @@ static pa_hook_result_t source_state_changed_cb(pa_core *c, pa_source *s, struct /* Run from main thread */ static int add_sink(struct userdata *u) { + char *k; + if (USE_SCO_OVER_PCM(u)) { pa_proplist *p; @@ -2014,6 +2016,10 @@ static int add_sink(struct userdata *u) { if (u->profile == PROFILE_HSP) { u->sink->set_volume = sink_set_volume_cb; u->sink->n_volume_steps = 16; + + k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->sink); + pa_shared_set(u->core, k, u); + pa_xfree(k); } return 0; @@ -2021,6 +2027,8 @@ static int add_sink(struct userdata *u) { /* Run from main thread */ static int add_source(struct userdata *u) { + char *k; + if (USE_SCO_OVER_PCM(u)) { u->source = u->hsp.sco_source; pa_proplist_sets(u->source->proplist, "bluetooth.protocol", "hsp"); @@ -2079,6 +2087,10 @@ static int add_source(struct userdata *u) { if (u->profile == PROFILE_HSP) { u->source->set_volume = source_set_volume_cb; u->source->n_volume_steps = 16; + + k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->source); + pa_shared_set(u->core, k, u); + pa_xfree(k); } return 0; @@ -2325,6 +2337,8 @@ static int init_profile(struct userdata *u) { /* Run from main thread */ static void stop_thread(struct userdata *u) { + char *k; + pa_assert(u); if (u->thread) { @@ -2349,11 +2363,23 @@ static void stop_thread(struct userdata *u) { } if (u->sink) { + if (u->profile == PROFILE_HSP) { + k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->sink); + pa_shared_remove(u->core, k); + pa_xfree(k); + } + pa_sink_unref(u->sink); u->sink = NULL; } if (u->source) { + if (u->profile == PROFILE_HSP) { + k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->source); + pa_shared_remove(u->core, k); + pa_xfree(k); + } + pa_source_unref(u->source); u->source = NULL; } @@ -2383,8 +2409,20 @@ static int start_thread(struct userdata *u) { if (USE_SCO_OVER_PCM(u)) { if (sco_over_pcm_state_update(u) < 0) { - u->sink = NULL; - u->source = NULL; + char *k; + + if (u->sink) { + k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->sink); + pa_shared_remove(u->core, k); + pa_xfree(k); + u->sink = NULL; + } + if (u->source) { + k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->source); + pa_shared_remove(u->core, k); + pa_xfree(k); + u->source = NULL; + } return -1; } @@ -2421,6 +2459,22 @@ static int start_thread(struct userdata *u) { return 0; } +static void save_sco_volume_callbacks(struct userdata *u) { + pa_assert(u); + pa_assert(USE_SCO_OVER_PCM(u)); + + u->hsp.sco_sink_set_volume = u->hsp.sco_sink->set_volume; + u->hsp.sco_source_set_volume = u->hsp.sco_source->set_volume; +} + +static void restore_sco_volume_callbacks(struct userdata *u) { + pa_assert(u); + pa_assert(USE_SCO_OVER_PCM(u)); + + u->hsp.sco_sink->set_volume = u->hsp.sco_sink_set_volume; + u->hsp.sco_source->set_volume = u->hsp.sco_source_set_volume; +} + /* Run from main thread */ static int card_set_profile(pa_card *c, pa_card_profile *new_profile) { struct userdata *u; @@ -2474,9 +2528,15 @@ static int card_set_profile(pa_card *c, pa_card_profile *new_profile) { stop_thread(u); shutdown_bt(u); + if (USE_SCO_OVER_PCM(u)) + restore_sco_volume_callbacks(u); + u->profile = *d; u->sample_spec = u->requested_sample_spec; + if (USE_SCO_OVER_PCM(u)) + save_sco_volume_callbacks(u); + init_bt(u); if (u->profile != PROFILE_OFF) @@ -2641,6 +2701,9 @@ static int add_card(struct userdata *u, const pa_bluetooth_device *device) { d = PA_CARD_PROFILE_DATA(u->card->active_profile); u->profile = *d; + if (USE_SCO_OVER_PCM(u)) + save_sco_volume_callbacks(u); + return 0; } @@ -2704,7 +2767,7 @@ int pa__init(pa_module* m) { struct userdata *u; const char *address, *path; DBusError err; - char *mike, *speaker, *transport, *k; + char *mike, *speaker, *transport; const pa_bluetooth_device *device; pa_assert(m); @@ -2805,20 +2868,6 @@ int pa__init(pa_module* m) { /* Connect to the BT service */ init_bt(u); - if (u->hsp.sco_sink) { - u->hsp.sco_sink_set_volume = u->hsp.sco_sink->set_volume; - k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->hsp.sco_sink); - pa_shared_set(u->core, k, u); - pa_xfree(k); - } - - if (u->hsp.sco_source) { - u->hsp.sco_source_set_volume = u->hsp.sco_source->set_volume; - k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->hsp.sco_source); - pa_shared_set(u->core, k, u); - pa_xfree(k); - } - if (u->profile != PROFILE_OFF) if (init_profile(u) < 0) goto fail; @@ -2851,7 +2900,6 @@ int pa__get_n_used(pa_module *m) { void pa__done(pa_module *m) { struct userdata *u; - char *k; pa_assert(m); @@ -2866,6 +2914,9 @@ void pa__done(pa_module *m) { stop_thread(u); + if (USE_SCO_OVER_PCM(u)) + restore_sco_volume_callbacks(u); + if (u->connection) { if (u->path) { @@ -2893,20 +2944,6 @@ void pa__done(pa_module *m) { shutdown_bt(u); - if (u->hsp.sco_sink) { - u->hsp.sco_sink->set_volume = u->hsp.sco_sink_set_volume; - k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->hsp.sco_sink); - pa_shared_remove(u->core, k); - pa_xfree(k); - } - - if (u->hsp.sco_source) { - u->hsp.sco_source->set_volume = u->hsp.sco_source_set_volume; - k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->hsp.sco_source); - pa_shared_remove(u->core, k); - pa_xfree(k); - } - if (u->a2dp.buffer) pa_xfree(u->a2dp.buffer); -- 1.7.4.1