1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
|
From: Jan Grulich <jgrulich@redhat.com>
Date: Thu, 5 Sep 2024 16:04:00 +0000
Subject: 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
Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/60eb5ef11c8df7eb6e0d616cb76885d9109f114d
---
.../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/modules/video_capture/linux/device_info_pipewire.cc b/modules/video_capture/linux/device_info_pipewire.cc
index db2a3c7099..a0607b4aba 100644
--- a/modules/video_capture/linux/device_info_pipewire.cc
+++ b/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/modules/video_capture/linux/pipewire_session.cc b/modules/video_capture/linux/pipewire_session.cc
index 990bfde912..25c4dfae4e 100644
--- a/modules/video_capture/linux/pipewire_session.cc
+++ b/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 <spa/monitor/device.h>
#include <spa/param/format-utils.h>
@@ -286,6 +287,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;
+}
+
RTC_NO_SANITIZE("cfi-icall")
bool PipeWireSession::StartPipeWire(int fd) {
pw_init(/*argc=*/nullptr, /*argv=*/nullptr);
@@ -358,6 +381,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,
@@ -416,6 +454,8 @@ void PipeWireSession::OnRegistryGlobal(void* data,
that->nodes_.push_back(PipeWireNode::Create(that, id, props));
that->PipeWireSync();
+
+ that->NotifyDeviceChange();
}
// static
@@ -427,10 +467,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/modules/video_capture/linux/pipewire_session.h b/modules/video_capture/linux/pipewire_session.h
index aec268e008..7dbba23691 100644
--- a/modules/video_capture/linux/pipewire_session.h
+++ b/modules/video_capture/linux/pipewire_session.h
@@ -28,6 +28,7 @@
namespace webrtc {
namespace videocapturemodule {
+class DeviceInfoPipeWire;
class PipeWireSession;
class VideoCaptureModulePipeWire;
@@ -96,6 +97,21 @@ class PipeWireSession : public webrtc::RefCountedNonVirtual<PipeWireSession> {
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<PipeWireNode::PipeWireNodePtr>& nodes() const {
return nodes_;
}
@@ -110,6 +126,8 @@ class PipeWireSession : public webrtc::RefCountedNonVirtual<PipeWireSession> {
void StopPipeWire();
void PipeWireSync();
+ void NotifyDeviceChange();
+
static void OnCoreError(void* data,
uint32_t id,
int seq,
@@ -132,7 +150,13 @@ class PipeWireSession : public webrtc::RefCountedNonVirtual<PipeWireSession> {
VideoCaptureOptions::Callback* callback_ RTC_GUARDED_BY(&callback_lock_) =
nullptr;
- VideoCaptureOptions::Status status_;
+ webrtc::Mutex device_info_lock_;
+ std::vector<DeviceInfoPipeWire*> 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;
|