From 54ddc5425467180008beeb9323a034a6f0c04545 Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Sun, 24 Jan 2021 23:35:41 +0100 Subject: [PATCH] fixup! bluetooth: Switch codecs without tearing down sink/source/thread --- src/modules/bluetooth/module-bluez5-device.c | 42 +++++++++++++++----- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/src/modules/bluetooth/module-bluez5-device.c b/src/modules/bluetooth/module-bluez5-device.c index 9f6f66439..102704e6e 100644 --- a/src/modules/bluetooth/module-bluez5-device.c +++ b/src/modules/bluetooth/module-bluez5-device.c @@ -893,6 +893,13 @@ static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_ if (!PA_SOURCE_IS_OPENED(s->thread_info.state)) break; + /* Ignore the transition if the source is suspended for internal reasons + * such as external source-output changes resulting in pa_source_reconfigure. + * Logic in our handler decides whether to release the transport or not. + */ + if (new_suspend_cause & PA_SUSPEND_INTERNAL) + break; + /* Stop the device if the sink is suspended as well */ if (!u->sink || u->sink->state == PA_SINK_SUSPENDED) transport_release(u); @@ -910,6 +917,9 @@ static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_ if (s->thread_info.state != PA_SOURCE_SUSPENDED) break; + if (s->suspend_cause & PA_SUSPEND_INTERNAL) + break; + /* Resume the device if the sink was suspended as well */ if (!u->sink || !PA_SINK_IS_OPENED(u->sink->thread_info.state)) if (!setup_transport_and_stream(u)) @@ -1167,6 +1177,13 @@ static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, if (!PA_SINK_IS_OPENED(s->thread_info.state)) break; + /* Ignore the transition if the sink is suspended for internal reasons + * such as external sink-input changes resulting in pa_sink_reconfigure. + * Logic in our handler decides whether to release the transport or not. + */ + if (new_suspend_cause & PA_SUSPEND_INTERNAL) + break; + /* Stop the device if the source is suspended as well */ if (!u->source || u->source->state == PA_SOURCE_SUSPENDED) /* We deliberately ignore whether stopping @@ -1181,6 +1198,9 @@ static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, if (s->thread_info.state != PA_SINK_SUSPENDED) break; + if (s->suspend_cause & PA_SUSPEND_INTERNAL) + break; + /* Resume the device if the source was suspended as well */ if (!u->source || !PA_SOURCE_IS_OPENED(u->source->thread_info.state)) if (!setup_transport_and_stream(u)) @@ -2563,10 +2583,7 @@ static void switch_codec_cb_handler(bool success, pa_bluetooth_profile_t profile u->profile = profile; is_a2dp_sink = u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK; - // SUSPEND callbacks release the transport and free the codec, but do not reinitialize it yet. - // Acquire the transport (could have been done in the callbacks when leaving SUSPEND) but - // _also_ reinitialize the codec with transport_config here: - + // Reacquire the transport and configure the codec r = setup_transport(u); pa_assert(!r); // if (r == -EINPROGRESS) @@ -2578,11 +2595,10 @@ static void switch_codec_cb_handler(bool success, pa_bluetooth_profile_t profile // Finish off by reconfiguring - // TODO HACK: Also cork/uncork sources so that the resampler is updated - if (is_a2dp_sink) { pa_sink_input *i; uint32_t idx; + PA_IDXSET_FOREACH(i, u->sink->inputs, idx) { pa_sink_input_cork(i, true); } @@ -2591,10 +2607,13 @@ static void switch_codec_cb_handler(bool success, pa_bluetooth_profile_t profile pa_sink_input_cork(i, false); } - pa_sink_suspend(u->sink, false, PA_SUSPEND_INTERNAL); + pa_asyncmsgq_send(u->sink->asyncmsgq, PA_MSGOBJECT(u->sink), PA_SINK_MESSAGE_SETUP_STREAM, NULL, 0, NULL); + + pa_sink_suspend(u->sink, false, PA_SUSPEND_UNAVAILABLE); } else { pa_source_output *i; uint32_t idx; + PA_IDXSET_FOREACH(i, u->source->outputs, idx) { pa_source_output_cork(i, true); } @@ -2603,7 +2622,9 @@ static void switch_codec_cb_handler(bool success, pa_bluetooth_profile_t profile pa_source_output_cork(i, false); } - pa_source_suspend(u->source, false, PA_SUSPEND_INTERNAL); + pa_asyncmsgq_send(u->source->asyncmsgq, PA_MSGOBJECT(u->source), PA_SOURCE_MESSAGE_SETUP_STREAM, NULL, 0, NULL); + + pa_source_suspend(u->source, false, PA_SUSPEND_UNAVAILABLE); } pa_log_info("Codec successfully switched to %s with profile: %s", @@ -2777,10 +2798,11 @@ static int bluez5_device_message_handler(const char *object_path, const char *me profile = u->profile; // Suspending releases the transport + if (is_a2dp_sink) - pa_sink_suspend(u->sink, true, PA_SUSPEND_INTERNAL); + pa_sink_suspend(u->sink, true, PA_SUSPEND_UNAVAILABLE); else - pa_source_suspend(u->source, true, PA_SUSPEND_INTERNAL); + pa_source_suspend(u->source, true, PA_SUSPEND_UNAVAILABLE); // TODO: Can we do this if it's synchronous? release_codec(u);