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.
This commit is contained in:
Timothy Flynn 2023-06-21 10:16:42 -04:00 committed by Andreas Kling
parent 8f927eaa68
commit 33dbfa3281

View file

@ -27,6 +27,7 @@ struct AudioTask {
Pause, Pause,
Seek, Seek,
Volume, Volume,
RecreateAudioDevice,
}; };
Type type; Type type;
@ -82,20 +83,64 @@ private:
No, No,
}; };
void run() override struct AudioDevice {
static AudioDevice create()
{ {
auto devices = make<QMediaDevices>(); auto const& device_info = QMediaDevices::defaultAudioOutput();
auto const& device_info = devices->defaultAudioOutput();
auto format = device_info.preferredFormat(); auto format = device_info.preferredFormat();
format.setChannelCount(2); format.setChannelCount(2);
auto audio_output = make<QAudioSink>(device_info, format); auto audio_output = make<QAudioSink>(device_info, format);
auto* io_device = audio_output->start(); 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<QAudioSink> audio_output;
QIODevice* io_device { nullptr };
private:
explicit AudioDevice(NonnullOwnPtr<QAudioSink> output)
: audio_output(move(output))
{
io_device = audio_output->start();
}
};
void run() override
{
auto devices = make<QMediaDevices>();
auto audio_device = AudioDevice::create();
connect(devices, &QMediaDevices::audioOutputsChanged, this, [this]() {
queue_task({ AudioTask::Type::RecreateAudioDevice }).release_value_but_fixme_should_propagate_errors();
});
auto paused = Paused::Yes; auto paused = Paused::Yes;
while (true) { 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()) { if (auto result = m_task_queue.dequeue(); result.is_error()) {
VERIFY(result.error() == AudioTaskQueue::QueueStatus::Empty); VERIFY(result.error() == AudioTaskQueue::QueueStatus::Empty);
} else { } else {
@ -136,6 +181,10 @@ private:
VERIFY(task.data.has_value()); VERIFY(task.data.has_value());
audio_output->setVolume(*task.data); audio_output->setVolume(*task.data);
break; break;
case AudioTask::Type::RecreateAudioDevice:
audio_device = AudioDevice::create();
continue;
} }
} }