aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorPaul Adenot <[email protected]>2023-07-25 16:59:59 +0200
committerPaul Adenot <[email protected]>2023-07-26 14:02:22 +0200
commiteef055ab2127bce96ed1a5a06a287f2a2abaa9a9 (patch)
tree24ac90cfc5646ce737a32f8e7bccecbaf49da7dd
parent29d266e628eef31e27820c9f2c697ab53d91f275 (diff)
downloadcubeb-eef055ab2127bce96ed1a5a06a287f2a2abaa9a9.tar.gz
cubeb-eef055ab2127bce96ed1a5a06a287f2a2abaa9a9.zip
AAudio: When a device is disconnected, reinitialize the stream with the same parameters
-rw-r--r--src/cubeb_aaudio.cpp50
1 files changed, 50 insertions, 0 deletions
diff --git a/src/cubeb_aaudio.cpp b/src/cubeb_aaudio.cpp
index e8424a0..d220ff7 100644
--- a/src/cubeb_aaudio.cpp
+++ b/src/cubeb_aaudio.cpp
@@ -145,6 +145,8 @@ struct cubeb_stream {
// mutex synchronizes access to the stream from the state thread
// and user-called functions. Everything that is accessed in the
// aaudio data (or error) callback is synchronized only via atomics.
+ // This lock is acquired for the entirety of the reinitialization period, when
+ // changing device.
std::mutex mutex;
std::unique_ptr<char[]> in_buf;
@@ -848,10 +850,58 @@ aaudio_input_data_cb(AAudioStream * astream, void * user_data,
}
static void
+reinitialize_stream(cubeb_stream * stm) {
+ // This cannot be done from within the error callback, bounce to another
+ // thread.
+ // In this situation, the lock is acquired for the entire duration of the
+ // function, so that this reinitialization period is atomic.
+ std::thread([stm] {
+ lock_guard lock(stm->mutex);
+ stream_state state = stm->state.load();
+ bool was_playing = state == stream_state::STARTED ||
+ state == stream_state::STARTING ||
+ state == stream_state::DRAINING;
+ int err = aaudio_stream_stop_locked(stm, lock);
+ // error ignored.
+ aaudio_stream_destroy_locked(stm, lock);
+ err = aaudio_stream_init_impl(stm, lock);
+
+ assert(stm->in_use.load());
+
+ if (err != CUBEB_OK) {
+ aaudio_stream_destroy_locked(stm, lock);
+ LOG("aaudio_stream_init_impl error while reiniting: %s",
+ WRAP(AAudio_convertResultToText)(err));
+ stm->state.store(stream_state::ERROR);
+ return;
+ }
+
+ if (was_playing) {
+ err = aaudio_stream_start_locked(stm, lock);
+ if (err != CUBEB_OK) {
+ aaudio_stream_destroy_locked(stm, lock);
+ LOG("aaudio_stream_start error while reiniting: %s",
+ WRAP(AAudio_convertResultToText)(err));
+ stm->state.store(stream_state::ERROR);
+ return;
+ }
+ }
+ }).detach();
+}
+
+static void
aaudio_error_cb(AAudioStream * astream, void * user_data, aaudio_result_t error)
{
cubeb_stream * stm = static_cast<cubeb_stream *>(user_data);
assert(stm->ostream == astream || stm->istream == astream);
+
+ // Device change -- reinitialize on the new default device.
+ if (error == AAUDIO_ERROR_DISCONNECTED) {
+ LOG("Audio device change, reinitializing stream");
+ reinitialize_stream(stm);
+ return;
+ }
+
LOG("AAudio error callback: %s", WRAP(AAudio_convertResultToText)(error));
stm->state.store(stream_state::ERROR);
}