Browse Source

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 năm trước cách đây
mục cha
commit
33dbfa3281
1 tập tin đã thay đổi với 55 bổ sung6 xóa
  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;
                 }
             }