tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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