浏览代码

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.
Timothy Flynn 2 年之前
父节点
当前提交
33dbfa3281
共有 1 个文件被更改,包括 55 次插入6 次删除
  1. 55 6
      Ladybird/AudioCodecPluginLadybird.cpp

+ 55 - 6
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<QAudioSink>(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<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 const& device_info = devices->defaultAudioOutput();
+        auto audio_device = AudioDevice::create();
 
-        auto format = device_info.preferredFormat();
-        format.setChannelCount(2);
-
-        auto audio_output = make<QAudioSink>(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;
                 }
             }