From 33dbfa328104c591e8daf06f4ab7cd041fa0e655 Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Wed, 21 Jun 2023 10:16:42 -0400 Subject: [PATCH] Ladybird: Detect changes to the default audio device When the default audio device changes on the host, it's convenient to automatically switch to that device rather than needing to reload the page to update. --- Ladybird/AudioCodecPluginLadybird.cpp | 61 ++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 6 deletions(-) diff --git a/Ladybird/AudioCodecPluginLadybird.cpp b/Ladybird/AudioCodecPluginLadybird.cpp index 534dd4d2c1..eab2e9624e 100644 --- a/Ladybird/AudioCodecPluginLadybird.cpp +++ b/Ladybird/AudioCodecPluginLadybird.cpp @@ -27,6 +27,7 @@ struct AudioTask { Pause, Seek, Volume, + RecreateAudioDevice, }; Type type; @@ -82,20 +83,64 @@ private: No, }; + struct AudioDevice { + static AudioDevice create() + { + auto const& device_info = QMediaDevices::defaultAudioOutput(); + + auto format = device_info.preferredFormat(); + format.setChannelCount(2); + + auto audio_output = make(device_info, format); + return AudioDevice { move(audio_output) }; + } + + AudioDevice(AudioDevice&&) = default; + + AudioDevice& operator=(AudioDevice&& device) + { + if (audio_output) { + audio_output->stop(); + io_device = nullptr; + } + + swap(audio_output, device.audio_output); + swap(io_device, device.io_device); + return *this; + } + + ~AudioDevice() + { + if (audio_output) + audio_output->stop(); + } + + OwnPtr audio_output; + QIODevice* io_device { nullptr }; + + private: + explicit AudioDevice(NonnullOwnPtr output) + : audio_output(move(output)) + { + io_device = audio_output->start(); + } + }; + void run() override { auto devices = make(); - auto const& device_info = devices->defaultAudioOutput(); + auto audio_device = AudioDevice::create(); - auto format = device_info.preferredFormat(); - format.setChannelCount(2); - - auto audio_output = make(device_info, format); - auto* io_device = audio_output->start(); + connect(devices, &QMediaDevices::audioOutputsChanged, this, [this]() { + queue_task({ AudioTask::Type::RecreateAudioDevice }).release_value_but_fixme_should_propagate_errors(); + }); auto paused = Paused::Yes; while (true) { + auto& audio_output = audio_device.audio_output; + auto* io_device = audio_device.io_device; + if (auto result = m_task_queue.dequeue(); result.is_error()) { VERIFY(result.error() == AudioTaskQueue::QueueStatus::Empty); } else { @@ -136,6 +181,10 @@ private: VERIFY(task.data.has_value()); audio_output->setVolume(*task.data); break; + + case AudioTask::Type::RecreateAudioDevice: + audio_device = AudioDevice::create(); + continue; } }