From a4eb4517f2bdeb6591c05a09109b4b543b83fef1 Mon Sep 17 00:00:00 2001 From: Jan Grulich Date: Thu, 5 Sep 2024 16:04:48 +0000 Subject: [PATCH] Bug 1830275 - Add missing support for device change notifications r=pehrsons,webrtc-reviewers Registers each DeviceInfoPipeWire in PipeWireSession we use and calls DeviceChange() for each once there is a new camera added or removed to invoke OnDeviceChange() for every registered VideoInputFeedback. Differential Revision: https://phabricator.services.mozilla.com/D219218 --- .../linux/device_info_pipewire.cc | 10 +++- .../video_capture/linux/pipewire_session.cc | 47 ++++++++++++++++++- .../video_capture/linux/pipewire_session.h | 26 +++++++++- 3 files changed, 79 insertions(+), 4 deletions(-) diff --git a/third_party/libwebrtc/modules/video_capture/linux/device_info_pipewire.cc b/third_party/libwebrtc/modules/video_capture/linux/device_info_pipewire.cc index db2a3c7099..a0607b4aba 100644 --- a/third_party/libwebrtc/modules/video_capture/linux/device_info_pipewire.cc +++ b/third_party/libwebrtc/modules/video_capture/linux/device_info_pipewire.cc @@ -29,13 +29,19 @@ namespace webrtc { namespace videocapturemodule { DeviceInfoPipeWire::DeviceInfoPipeWire(VideoCaptureOptions* options) - : DeviceInfoImpl(), pipewire_session_(options->pipewire_session()) {} + : DeviceInfoImpl(), pipewire_session_(options->pipewire_session()) { + const bool ret = pipewire_session_->RegisterDeviceInfo(this); + RTC_CHECK(ret); +} int32_t DeviceInfoPipeWire::Init() { return 0; } -DeviceInfoPipeWire::~DeviceInfoPipeWire() = default; +DeviceInfoPipeWire::~DeviceInfoPipeWire() { + const bool ret = pipewire_session_->DeRegisterDeviceInfo(this); + RTC_CHECK(ret); +} uint32_t DeviceInfoPipeWire::NumberOfDevices() { RTC_CHECK(pipewire_session_); diff --git a/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.cc b/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.cc index ac12d04372..0b78c16df2 100644 --- a/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.cc +++ b/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.cc @@ -9,6 +9,7 @@ */ #include "modules/video_capture/linux/pipewire_session.h" +#include "modules/video_capture/linux/device_info_pipewire.h" #include #include @@ -274,6 +275,28 @@ void PipeWireSession::InitPipeWire(int fd) { Finish(VideoCaptureOptions::Status::ERROR); } +bool PipeWireSession::RegisterDeviceInfo(DeviceInfoPipeWire* device_info) { + RTC_CHECK(device_info); + MutexLock lock(&device_info_lock_); + auto it = std::find(device_info_list_.begin(), device_info_list_.end(), device_info); + if (it == device_info_list_.end()) { + device_info_list_.push_back(device_info); + return true; + } + return false; +} + +bool PipeWireSession::DeRegisterDeviceInfo(DeviceInfoPipeWire* device_info) { + RTC_CHECK(device_info); + MutexLock lock(&device_info_lock_); + auto it = std::find(device_info_list_.begin(), device_info_list_.end(), device_info); + if (it != device_info_list_.end()) { + device_info_list_.erase(it); + return true; + } + return false; +} + bool PipeWireSession::StartPipeWire(int fd) { pw_init(/*argc=*/nullptr, /*argv=*/nullptr); @@ -344,6 +367,21 @@ void PipeWireSession::PipeWireSync() { sync_seq_ = pw_core_sync(pw_core_, PW_ID_CORE, sync_seq_); } +void PipeWireSession::NotifyDeviceChange() { + RTC_LOG(LS_INFO) << "Notify about device list changes"; + MutexLock lock(&device_info_lock_); + + // It makes sense to notify about device changes only once we are + // properly initialized. + if (status_ != VideoCaptureOptions::Status::SUCCESS) { + return; + } + + for (auto* deviceInfo : device_info_list_) { + deviceInfo->DeviceChange(); + } +} + // static void PipeWireSession::OnCoreError(void* data, uint32_t id, @@ -401,6 +439,8 @@ void PipeWireSession::OnRegistryGlobal(void* data, that->nodes_.push_back(PipeWireNode::Create(that, id, props)); that->PipeWireSync(); + + that->NotifyDeviceChange(); } // static @@ -412,10 +452,15 @@ void PipeWireSession::OnRegistryGlobalRemove(void* data, uint32_t id) { return node->id() == id; }); that->nodes_.erase(it, that->nodes_.end()); + + that->NotifyDeviceChange(); } void PipeWireSession::Finish(VideoCaptureOptions::Status status) { - status_ = status; + { + MutexLock lock(&device_info_lock_); + status_ = status; + } webrtc::MutexLock lock(&callback_lock_); diff --git a/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.h b/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.h index 84273ea695..1f3a00614f 100644 --- a/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.h +++ b/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.h @@ -29,6 +29,7 @@ namespace webrtc { namespace videocapturemodule { +class DeviceInfoPipeWire; class PipeWireSession; class VideoCaptureModulePipeWire; @@ -97,6 +98,21 @@ class PipeWireSession : public rtc::RefCountedNonVirtual { void Init(VideoCaptureOptions::Callback* callback, int fd = kInvalidPipeWireFd); + + // [De]Register DeviceInfo for device change updates + // These methods will add or remove references to DeviceInfo + // objects that we want to notify about device changes. + // NOTE: We do not take ownership of these objects and + // they should never be released by us. All the instances + // of DeviceInfoPipeWire must outlive their registration. + + // Returns true when DeviceInfo was successfuly registered + // or false otherwise, when it was already registered before. + bool RegisterDeviceInfo(DeviceInfoPipeWire* device_info); + // Returns true when DeviceInfo was successfuly unregistered + // or false otherwise, when it was not previously registered. + bool DeRegisterDeviceInfo(DeviceInfoPipeWire* device_info); + const std::deque& nodes() const { return nodes_; } @@ -111,6 +127,8 @@ class PipeWireSession : public rtc::RefCountedNonVirtual { void StopPipeWire(); void PipeWireSync(); + void NotifyDeviceChange(); + static void OnCoreError(void* data, uint32_t id, int seq, @@ -133,7 +151,13 @@ class PipeWireSession : public rtc::RefCountedNonVirtual { VideoCaptureOptions::Callback* callback_ RTC_GUARDED_BY(&callback_lock_) = nullptr; - VideoCaptureOptions::Status status_; + webrtc::Mutex device_info_lock_; + std::vector device_info_list_ + RTC_GUARDED_BY(device_info_lock_); + // Guard with device_info_lock, because currently it's the only place where + // we use this status information. + VideoCaptureOptions::Status status_ + RTC_GUARDED_BY(device_info_lock_); struct pw_thread_loop* pw_main_loop_ = nullptr; struct pw_context* pw_context_ = nullptr;