CamerasParent.h (12960B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set sw=2 ts=8 et ft=cpp : */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_CamerasParent_h 8 #define mozilla_CamerasParent_h 9 10 #include "api/video/video_sink_interface.h" 11 #include "modules/video_capture/video_capture.h" 12 #include "modules/video_capture/video_capture_defines.h" 13 #include "mozilla/ShmemPool.h" 14 #include "mozilla/camera/PCamerasParent.h" 15 #include "mozilla/dom/MediaStreamTrackBinding.h" 16 #include "mozilla/ipc/Shmem.h" 17 #include "mozilla/media/MediaUtils.h" 18 19 class WebrtcLogSinkHandle; 20 class nsIThread; 21 22 namespace mozilla { 23 class VideoCaptureFactory; 24 } 25 26 namespace mozilla::camera { 27 28 class CamerasParent; 29 class VideoEngine; 30 31 // Class that manages sharing of VideoCaptureImpl instances on top of 32 // VideoEngine. Sharing is needed as access to most sources is exclusive 33 // system-wide. 34 // 35 // There is at most one AggregateCapturer instance per unique source, as defined 36 // by its unique capture ID. 37 // 38 // There can be multiple requests for a stream from a source, as defined by 39 // unique stream IDs. 40 // 41 // Stream IDs and capture IDs use the same ID space. With capture happening in 42 // the parent process, application-wide uniqueness is guaranteed. 43 // 44 // When multiple stream requests have been made for a source, even across 45 // multiple CamerasParent instances, this class distributes a single frame to 46 // each CamerasParent instance that has requested a stream. Distribution to the 47 // various stream requests happens in CamerasChild::RecvDeliverFrame. 48 // 49 // This class similarly handles capture-ended events, and distributes them to 50 // the correct CamerasParent instances, with distribution to streams happening 51 // in CamerasChild::RecvCaptureEnded. 52 class AggregateCapturer final 53 : public webrtc::VideoSinkInterface<webrtc::VideoFrame> { 54 public: 55 static std::unique_ptr<AggregateCapturer> Create( 56 nsISerialEventTarget* aVideoCaptureThread, CaptureEngine aCapEng, 57 VideoEngine* aEngine, const nsCString& aUniqueId, uint64_t aWindowId, 58 nsTArray<webrtc::VideoCaptureCapability>&& aCapabilities, 59 CamerasParent* aParent); 60 61 ~AggregateCapturer(); 62 63 void AddStream(CamerasParent* aParent, int aStreamId, uint64_t aWindowId); 64 struct RemoveStreamResult { 65 size_t mNumRemainingStreams; 66 size_t mNumRemainingStreamsForParent; 67 }; 68 RemoveStreamResult RemoveStream(int aStreamId); 69 RemoveStreamResult RemoveStreamsFor(CamerasParent* aParent); 70 Maybe<int> CaptureIdFor(int aStreamId); 71 void SetConfigurationFor(int aStreamId, 72 const webrtc::VideoCaptureCapability& aCapability, 73 const NormalizedConstraints& aConstraints, 74 const dom::VideoResizeModeEnum& aResizeMode, 75 bool aStarted); 76 webrtc::VideoCaptureCapability CombinedCapability(); 77 78 void OnCaptureEnded(); 79 void OnFrame(const webrtc::VideoFrame& aVideoFrame) override; 80 81 struct Configuration { 82 webrtc::VideoCaptureCapability mCapability; 83 NormalizedConstraints mConstraints; 84 // This is the effective resize mode, i.e. based on mConstraints and with 85 // defaults factored in. 86 dom::VideoResizeModeEnum mResizeMode{}; 87 }; 88 // Representation of a stream request for the source of this AggregateCapturer 89 // instance. 90 struct Stream { 91 // The CamerasParent instance that requested this stream. mParent is 92 // responsible for the lifetime of this stream. 93 CamerasParent* const mParent; 94 // The id that identifies this stream. This is unique within the application 95 // session, in the same set of IDs as AggregateCapturer::mCaptureId. 96 const int mId{-1}; 97 // The id of the window where the request for this stream originated. 98 const uint64_t mWindowId{}; 99 // The configuration applied to this stream. 100 Configuration mConfiguration; 101 // Whether the stream has been started and not stopped. As opposed to 102 // allocated and not deallocated, which controls the presence of this stream 103 // altogether. 104 bool mStarted{false}; 105 // The timestamp of the last frame sent to mParent for this stream. 106 media::TimeUnit mLastFrameTime{media::TimeUnit::FromNegativeInfinity()}; 107 }; 108 // The video capture thread is where all access to this class must happen. 109 const nsCOMPtr<nsISerialEventTarget> mVideoCaptureThread; 110 // The identifier for which VideoEngine instance we are using, i.e. which type 111 // of source we're associated with. 112 const CaptureEngine mCapEngine; 113 // The (singleton from sEngines) VideoEngine instance that mCaptureId is valid 114 // in. 115 const RefPtr<VideoEngine> mEngine; 116 // The unique ID string of the associated device. 117 const nsCString mUniqueId; 118 // The id that identifies the capturer instance of the associated source 119 // device in VideoEngine. 120 const int mCaptureId; 121 // Tracking ID of the capturer for profiler markers. 122 const TrackingId mTrackingId; 123 // The (immutable) list of capabilities offered by the associated source 124 // device. 125 const nsTArray<webrtc::VideoCaptureCapability> mCapabilities; 126 // The list of streams that have been requested from all CamerasParent 127 // instances for the associated source device. 128 DataMutex<nsTArray<std::unique_ptr<Stream>>> mStreams; 129 130 private: 131 AggregateCapturer(nsISerialEventTarget* aVideoCaptureThread, 132 CaptureEngine aCapEng, VideoEngine* aEngine, 133 const nsCString& aUniqueId, int aCaptureId, 134 nsTArray<webrtc::VideoCaptureCapability>&& aCapabilities); 135 136 MediaEventListener mCaptureEndedListener; 137 }; 138 139 class DeliverFrameRunnable; 140 141 class CamerasParent final : public PCamerasParent { 142 public: 143 using ShutdownMozPromise = media::ShutdownBlockingTicket::ShutdownMozPromise; 144 145 using CameraAccessRequestPromise = MozPromise<CamerasAccessStatus, void_t, 146 /* IsExclusive = */ false>; 147 148 NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DELETE_ON_EVENT_TARGET( 149 CamerasParent, mPBackgroundEventTarget) 150 151 class VideoEngineArray; 152 friend DeliverFrameRunnable; 153 154 static already_AddRefed<CamerasParent> Create(); 155 156 /** 157 * Request camera access 158 * Currently only used on desktop. If @value 159 * aAllowPermissionRequest is true, a request for full camera access may be 160 * made and the returned promise may be blocked on user input on a modal 161 * dialog. If @value aAllowPermissionRequest is false, only a request to 162 * check camera device presence will be made. If any camera device is 163 * present, we will enumerate a single placeholder device until a successful 164 * RequestCameraAccess with a true aAllowPermissionRequest. 165 * The returned promise will never be rejected. 166 */ 167 static RefPtr<CameraAccessRequestPromise> RequestCameraAccess( 168 bool aAllowPermissionRequest); 169 170 // Messages received from the child. These run on the IPC/PBackground thread. 171 mozilla::ipc::IPCResult RecvPCamerasConstructor(); 172 mozilla::ipc::IPCResult RecvAllocateCapture( 173 const CaptureEngine& aCapEngine, const nsACString& aUniqueIdUTF8, 174 const uint64_t& aWindowID) override; 175 mozilla::ipc::IPCResult RecvReleaseCapture(const CaptureEngine& aCapEngine, 176 const int& aStreamId) override; 177 mozilla::ipc::IPCResult RecvNumberOfCaptureDevices( 178 const CaptureEngine& aCapEngine) override; 179 mozilla::ipc::IPCResult RecvNumberOfCapabilities( 180 const CaptureEngine& aCapEngine, const nsACString& aUniqueId) override; 181 mozilla::ipc::IPCResult RecvGetCaptureCapability( 182 const CaptureEngine& aCapEngine, const nsACString& aUniqueId, 183 const int& aIndex) override; 184 mozilla::ipc::IPCResult RecvGetCaptureDevice( 185 const CaptureEngine& aCapEngine, const int& aDeviceIndex) override; 186 mozilla::ipc::IPCResult RecvStartCapture( 187 const CaptureEngine& aCapEngine, const int& aStreamId, 188 const VideoCaptureCapability& aIpcCaps, 189 const NormalizedConstraints& aConstraints, 190 const dom::VideoResizeModeEnum& aResizeMode) override; 191 mozilla::ipc::IPCResult RecvFocusOnSelectedSource( 192 const CaptureEngine& aCapEngine, const int& aStreamId) override; 193 mozilla::ipc::IPCResult RecvStopCapture(const CaptureEngine& aCapEngine, 194 const int& aStreamId) override; 195 mozilla::ipc::IPCResult RecvReleaseFrame( 196 const int& aCaptureId, mozilla::ipc::Shmem&& aShmem) override; 197 void ActorDestroy(ActorDestroyReason aWhy) override; 198 mozilla::ipc::IPCResult RecvEnsureInitialized( 199 const CaptureEngine& aCapEngine) override; 200 201 bool IsWindowCapturing(uint64_t aWindowId, const nsACString& aUniqueId) const; 202 nsIEventTarget* GetBackgroundEventTarget() { 203 return mPBackgroundEventTarget; 204 }; 205 bool IsShuttingDown() { 206 // the first 2 are pBackground only, the last is atomic 207 MOZ_ASSERT(mPBackgroundEventTarget->IsOnCurrentThread()); 208 return mDestroyed; 209 }; 210 ShmemBuffer GetBuffer(int aCaptureId, size_t aSize); 211 212 // helper to forward to the PBackground thread 213 int DeliverFrameOverIPC(CaptureEngine aCapEngine, int aCaptureId, 214 const Span<const int>& aStreamId, 215 const TrackingId& aTrackingId, 216 Variant<ShmemBuffer, webrtc::VideoFrame>&& aBuffer, 217 const VideoFrameProperties& aProps); 218 219 CamerasParent(); 220 221 private: 222 virtual ~CamerasParent(); 223 224 struct GetOrCreateCapturerResult { 225 AggregateCapturer* mCapturer{}; 226 int mStreamId{}; 227 }; 228 GetOrCreateCapturerResult GetOrCreateCapturer( 229 CaptureEngine aEngine, uint64_t aWindowId, const nsCString& aUniqueId, 230 nsTArray<webrtc::VideoCaptureCapability>&& aCapabilities); 231 AggregateCapturer* GetCapturer(CaptureEngine aEngine, int aStreamId); 232 int ReleaseStream(CaptureEngine aEngine, int aStreamId); 233 234 nsTArray<webrtc::VideoCaptureCapability> const* EnsureCapabilitiesPopulated( 235 CaptureEngine aEngine, const nsCString& aUniqueId); 236 237 void OnDeviceChange(); 238 239 // Creates a new DeviceInfo or returns an existing DeviceInfo for given 240 // capture engine. Returns a nullptr in case capture engine failed to be 241 // initialized. Video capture thread only. 242 std::shared_ptr<webrtc::VideoCaptureModule::DeviceInfo> GetDeviceInfo( 243 int aEngine); 244 VideoEngine* EnsureInitialized(int aEngine); 245 246 // Stops any ongoing capturing and releases resources. Called on 247 // mVideoCaptureThread. Idempotent. 248 void CloseEngines(); 249 250 void OnShutdown(); 251 252 // If existent, blocks xpcom shutdown while alive. 253 // Note that this makes a reference cycle that gets broken in ActorDestroy(). 254 const UniquePtr<media::ShutdownBlockingTicket> mShutdownBlocker; 255 // Tracks the mShutdownBlocker shutdown handler. mPBackgroundEventTarget only. 256 MozPromiseRequestHolder<ShutdownMozPromise> mShutdownRequest; 257 258 // Local copy of sVideoCaptureThread. Guaranteed alive if non-null. 259 const nsCOMPtr<nsISerialEventTarget> mVideoCaptureThread; 260 261 // Reference to same VideoEngineArray as sEngines. Video capture thread only. 262 const RefPtr<VideoEngineArray> mEngines; 263 264 // Reference to same array of AggregateCapturers as sCapturers. There is one 265 // AggregateCapturer per allocated video source. It tracks the mapping from 266 // source to streamIds and CamerasParent instances. Video capture thread only. 267 const RefPtr< 268 media::Refcountable<nsTArray<std::unique_ptr<AggregateCapturer>>>> 269 mCapturers; 270 271 // Reference to same VideoCaptureFactory as sVideoCaptureFactory. Video 272 // capture thread only. 273 const RefPtr<VideoCaptureFactory> mVideoCaptureFactory; 274 275 // Image buffers. One pool per CamerasParent instance and capture id (i.e. 276 // unique source). Multiple CamerasParent instances capturing the same source 277 // need distinct ShmemPools as ShmemBuffers are tied to the IPC channel. 278 // Access is on the PBackground thread for mutations and 279 // allocating shmem buffers, and on the callback thread (varies by capture 280 // backend) for querying an existing pool for an available buffer. 281 DataMutex<std::map<int, ShmemPool>> mShmemPools; 282 283 // PBackgroundParent thread 284 const nsCOMPtr<nsISerialEventTarget> mPBackgroundEventTarget; 285 286 // Set to true in ActorDestroy. PBackground only. 287 bool mDestroyed; 288 289 std::map<nsCString, nsTArray<webrtc::VideoCaptureCapability>> 290 mAllCandidateCapabilities; 291 292 // Listener for the camera VideoEngine::DeviceChangeEvent(). Video capture 293 // thread only. 294 MediaEventListener mDeviceChangeEventListener; 295 bool mDeviceChangeEventListenerConnected = false; 296 297 // While alive, ensure webrtc logging is hooked up to MOZ_LOG. Main thread 298 // only. 299 nsMainThreadPtrHandle<WebrtcLogSinkHandle> mLogHandle; 300 }; 301 302 } // namespace mozilla::camera 303 304 #endif // mozilla_CameraParent_h