Bug 1839170 - Refactor Snap pulling, Add Firefox Snap Core22 and GNOME 42 SDK symbols...
[gecko.git] / dom / media / MediaManager.h
blob5a1679deecb68419b8b5bbdf6857486b11f74b5d
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #ifndef MOZILLA_MEDIAMANAGER_H
6 #define MOZILLA_MEDIAMANAGER_H
8 #include "MediaEnginePrefs.h"
9 #include "MediaEventSource.h"
10 #include "mozilla/dom/GetUserMediaRequest.h"
11 #include "mozilla/Unused.h"
12 #include "nsIMediaDevice.h"
13 #include "nsIMediaManager.h"
15 #include "nsHashKeys.h"
16 #include "nsClassHashtable.h"
17 #include "nsRefPtrHashtable.h"
18 #include "nsIMemoryReporter.h"
19 #include "nsIObserver.h"
21 #include "nsXULAppAPI.h"
22 #include "mozilla/Attributes.h"
23 #include "mozilla/Preferences.h"
24 #include "mozilla/StaticPtr.h"
25 #include "mozilla/dom/MediaStreamBinding.h"
26 #include "mozilla/dom/MediaStreamTrackBinding.h"
27 #include "mozilla/dom/MediaStreamError.h"
28 #include "mozilla/dom/NavigatorBinding.h"
29 #include "mozilla/media/MediaChild.h"
30 #include "mozilla/media/MediaParent.h"
31 #include "mozilla/Logging.h"
32 #include "mozilla/UniquePtr.h"
33 #include "DOMMediaStream.h"
34 #include "PerformanceRecorder.h"
36 #ifdef MOZ_WEBRTC
37 # include "transport/runnable_utils.h"
38 #endif
40 class AudioDeviceInfo;
41 class nsIPrefBranch;
43 namespace mozilla {
44 class MediaEngine;
45 class MediaEngineSource;
46 class TaskQueue;
47 class MediaTimer;
48 class MediaTrack;
49 namespace dom {
50 struct AudioOutputOptions;
51 struct MediaStreamConstraints;
52 struct MediaTrackConstraints;
53 struct MediaTrackConstraintSet;
54 struct MediaTrackSettings;
55 enum class CallerType : uint32_t;
56 enum class MediaDeviceKind : uint8_t;
57 } // namespace dom
59 namespace ipc {
60 class PrincipalInfo;
63 class GetUserMediaTask;
64 class GetUserMediaWindowListener;
65 class MediaManager;
66 class DeviceListener;
68 /**
69 * Device info that is independent of any Window.
70 * MediaDevices can be shared, unlike LocalMediaDevices.
72 class MediaDevice final {
73 public:
74 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDevice)
76 /**
77 * Whether source device does end-run around cross origin restrictions.
79 enum class IsScary { No, Yes };
81 /**
82 * Whether source device can use OS level selection prompt
84 enum class OsPromptable { No, Yes };
86 MediaDevice(MediaEngine* aEngine, dom::MediaSourceEnum aMediaSource,
87 const nsString& aRawName, const nsString& aRawID,
88 const nsString& aRawGroupID, IsScary aIsScary,
89 const OsPromptable canRequestOsLevelPrompt);
91 MediaDevice(MediaEngine* aEngine,
92 const RefPtr<AudioDeviceInfo>& aAudioDeviceInfo,
93 const nsString& aRawID);
95 static RefPtr<MediaDevice> CopyWithNewRawGroupId(
96 const RefPtr<MediaDevice>& aOther, const nsString& aRawGroupID);
98 dom::MediaSourceEnum GetMediaSource() const;
100 protected:
101 ~MediaDevice();
103 public:
104 const RefPtr<MediaEngine> mEngine;
105 const RefPtr<AudioDeviceInfo> mAudioDeviceInfo;
106 const dom::MediaSourceEnum mMediaSource;
107 const dom::MediaDeviceKind mKind;
108 const bool mScary;
109 const bool mCanRequestOsLevelPrompt;
110 const bool mIsFake;
111 const nsString mType;
112 const nsString mRawID;
113 const nsString mRawGroupID;
114 const nsString mRawName;
118 * Device info that is specific to a particular Window. If the device is a
119 * source device, then a single corresponding MediaEngineSource is provided,
120 * which can provide a maximum of one capture stream. LocalMediaDevices are
121 * not shared, but APIs returning LocalMediaDevices return a new object each
122 * call.
124 class LocalMediaDevice final : public nsIMediaDevice {
125 public:
126 NS_DECL_THREADSAFE_ISUPPORTS
127 NS_DECL_NSIMEDIADEVICE
129 LocalMediaDevice(RefPtr<const MediaDevice> aRawDevice, const nsString& aID,
130 const nsString& aGroupID, const nsString& aName);
132 uint32_t GetBestFitnessDistance(
133 const nsTArray<const NormalizedConstraintSet*>& aConstraintSets,
134 dom::CallerType aCallerType);
136 nsresult Allocate(const dom::MediaTrackConstraints& aConstraints,
137 const MediaEnginePrefs& aPrefs, uint64_t aWindowId,
138 const char** aOutBadConstraint);
139 void SetTrack(const RefPtr<MediaTrack>& aTrack,
140 const nsMainThreadPtrHandle<nsIPrincipal>& aPrincipal);
141 nsresult Start();
142 nsresult Reconfigure(const dom::MediaTrackConstraints& aConstraints,
143 const MediaEnginePrefs& aPrefs,
144 const char** aOutBadConstraint);
145 nsresult FocusOnSelectedSource();
146 nsresult Stop();
147 nsresult Deallocate();
149 void GetSettings(dom::MediaTrackSettings& aOutSettings);
150 MediaEngineSource* Source();
151 const TrackingId& GetTrackingId() const;
152 // Returns null if not a physical audio device.
153 AudioDeviceInfo* GetAudioDeviceInfo() const {
154 return mRawDevice->mAudioDeviceInfo;
156 dom::MediaSourceEnum GetMediaSource() const {
157 return mRawDevice->GetMediaSource();
159 dom::MediaDeviceKind Kind() const { return mRawDevice->mKind; }
160 bool IsFake() const { return mRawDevice->mIsFake; }
161 const nsString& RawID() { return mRawDevice->mRawID; }
163 private:
164 virtual ~LocalMediaDevice() = default;
166 static uint32_t FitnessDistance(
167 nsString aN,
168 const dom::OwningStringOrStringSequenceOrConstrainDOMStringParameters&
169 aConstraint);
171 static bool StringsContain(const dom::OwningStringOrStringSequence& aStrings,
172 nsString aN);
173 static uint32_t FitnessDistance(
174 nsString aN, const dom::ConstrainDOMStringParameters& aParams);
176 public:
177 const RefPtr<const MediaDevice> mRawDevice;
178 const nsString mName;
179 const nsString mID;
180 const nsString mGroupID;
182 private:
183 RefPtr<MediaEngineSource> mSource;
186 typedef nsRefPtrHashtable<nsUint64HashKey, GetUserMediaWindowListener>
187 WindowTable;
189 class MediaManager final : public nsIMediaManagerService,
190 public nsIMemoryReporter,
191 public nsIObserver {
192 friend DeviceListener;
194 public:
195 static already_AddRefed<MediaManager> GetInstance();
197 // NOTE: never NS_DispatchAndSpinEventLoopUntilComplete to the MediaManager
198 // thread from the MainThread, as we NS_DispatchAndSpinEventLoopUntilComplete
199 // to MainThread from MediaManager thread.
200 static MediaManager* Get();
201 static MediaManager* GetIfExists();
202 static void StartupInit();
203 static void Dispatch(already_AddRefed<Runnable> task);
206 * Posts an async operation to the media manager thread.
207 * FunctionType must be a function that takes a `MozPromiseHolder&`.
209 * The returned promise is resolved or rejected by aFunction on the media
210 * manager thread.
212 template <typename MozPromiseType, typename FunctionType>
213 static RefPtr<MozPromiseType> Dispatch(const char* aName,
214 FunctionType&& aFunction);
216 #ifdef DEBUG
217 static bool IsInMediaThread();
218 #endif
220 static bool Exists() { return !!GetIfExists(); }
222 static nsresult NotifyRecordingStatusChange(nsPIDOMWindowInner* aWindow);
224 NS_DECL_THREADSAFE_ISUPPORTS
225 NS_DECL_NSIOBSERVER
226 NS_DECL_NSIMEMORYREPORTER
227 NS_DECL_NSIMEDIAMANAGERSERVICE
229 media::Parent<media::NonE10s>* GetNonE10sParent();
231 // If the window has not been destroyed, then return the
232 // GetUserMediaWindowListener for this window.
233 // If the window has been destroyed, then return null.
234 RefPtr<GetUserMediaWindowListener> GetOrMakeWindowListener(
235 nsPIDOMWindowInner* aWindow);
236 WindowTable* GetActiveWindows() {
237 MOZ_ASSERT(NS_IsMainThread());
238 return &mActiveWindows;
240 GetUserMediaWindowListener* GetWindowListener(uint64_t aWindowId) {
241 MOZ_ASSERT(NS_IsMainThread());
242 return mActiveWindows.GetWeak(aWindowId);
244 void AddWindowID(uint64_t aWindowId,
245 RefPtr<GetUserMediaWindowListener> aListener);
246 void RemoveWindowID(uint64_t aWindowId);
247 void SendPendingGUMRequest();
248 bool IsWindowStillActive(uint64_t aWindowId) {
249 return !!GetWindowListener(aWindowId);
251 bool IsWindowListenerStillActive(
252 const RefPtr<GetUserMediaWindowListener>& aListener);
254 static bool IsOn(const dom::OwningBooleanOrMediaTrackConstraints& aUnion) {
255 return !aUnion.IsBoolean() || aUnion.GetAsBoolean();
257 using GetUserMediaSuccessCallback = dom::NavigatorUserMediaSuccessCallback;
258 using GetUserMediaErrorCallback = dom::NavigatorUserMediaErrorCallback;
260 MOZ_CAN_RUN_SCRIPT
261 static void CallOnError(GetUserMediaErrorCallback& aCallback,
262 dom::MediaStreamError& aError);
263 MOZ_CAN_RUN_SCRIPT
264 static void CallOnSuccess(GetUserMediaSuccessCallback& aCallback,
265 DOMMediaStream& aTrack);
267 using MediaDeviceSet = nsTArray<RefPtr<MediaDevice>>;
268 using MediaDeviceSetRefCnt = media::Refcountable<MediaDeviceSet>;
269 using LocalMediaDeviceSet = nsTArray<RefPtr<LocalMediaDevice>>;
270 using LocalMediaDeviceSetRefCnt = media::Refcountable<LocalMediaDeviceSet>;
272 using StreamPromise =
273 MozPromise<RefPtr<DOMMediaStream>, RefPtr<MediaMgrError>, true>;
274 using DeviceSetPromise =
275 MozPromise<RefPtr<MediaDeviceSetRefCnt>, RefPtr<MediaMgrError>, true>;
276 using ConstDeviceSetPromise = MozPromise<RefPtr<const MediaDeviceSetRefCnt>,
277 RefPtr<MediaMgrError>, true>;
278 using LocalDevicePromise =
279 MozPromise<RefPtr<LocalMediaDevice>, RefPtr<MediaMgrError>, true>;
280 using LocalDeviceSetPromise = MozPromise<RefPtr<LocalMediaDeviceSetRefCnt>,
281 RefPtr<MediaMgrError>, true>;
282 using MgrPromise = MozPromise<bool, RefPtr<MediaMgrError>, true>;
284 RefPtr<StreamPromise> GetUserMedia(
285 nsPIDOMWindowInner* aWindow,
286 const dom::MediaStreamConstraints& aConstraints,
287 dom::CallerType aCallerType);
289 RefPtr<LocalDevicePromise> SelectAudioOutput(
290 nsPIDOMWindowInner* aWindow, const dom::AudioOutputOptions& aOptions,
291 dom::CallerType aCallerType);
293 // Return the list of microphone, camera, and speaker devices.
294 // MediaDeviceSets provided on promise resolution are shared between
295 // callers and so cannot be modified.
296 RefPtr<ConstDeviceSetPromise> GetPhysicalDevices();
298 void OnNavigation(uint64_t aWindowID);
299 void OnCameraMute(bool aMute);
300 void OnMicrophoneMute(bool aMute);
301 bool IsActivelyCapturingOrHasAPermission(uint64_t aWindowId);
303 MediaEventSource<void>& DeviceListChangeEvent() {
304 return mDeviceListChangeEvent;
306 RefPtr<LocalDeviceSetPromise> AnonymizeDevices(
307 nsPIDOMWindowInner* aWindow, RefPtr<const MediaDeviceSetRefCnt> aDevices);
309 MediaEnginePrefs mPrefs;
311 private:
312 static nsresult GenerateUUID(nsAString& aResult);
314 public:
316 * This function tries to guess the group id for a video device in aDevices
317 * based on the device name. If the name of only one audio device in aAudios
318 * contains the name of the video device, then, this video device will take
319 * the group id of the audio device. Since this is a guess we try to minimize
320 * the probability of false positive. If we fail to find a correlation we
321 * leave the video group id untouched. In that case the group id will be the
322 * video device name.
324 static void GuessVideoDeviceGroupIDs(MediaDeviceSet& aDevices,
325 const MediaDeviceSet& aAudios);
327 private:
328 enum class EnumerationFlag {
329 AllowPermissionRequest,
330 EnumerateAudioOutputs,
331 ForceFakes,
333 using EnumerationFlags = EnumSet<EnumerationFlag>;
334 RefPtr<LocalDeviceSetPromise> EnumerateDevicesImpl(
335 nsPIDOMWindowInner* aWindow, dom::MediaSourceEnum aVideoInputType,
336 dom::MediaSourceEnum aAudioInputType, EnumerationFlags aFlags);
338 RefPtr<DeviceSetPromise> EnumerateRawDevices(
339 dom::MediaSourceEnum aVideoInputType,
340 dom::MediaSourceEnum aAudioInputType, EnumerationFlags aFlags);
342 RefPtr<LocalDeviceSetPromise> SelectSettings(
343 const dom::MediaStreamConstraints& aConstraints,
344 dom::CallerType aCallerType, RefPtr<LocalMediaDeviceSetRefCnt> aDevices);
346 void GetPref(nsIPrefBranch* aBranch, const char* aPref, const char* aData,
347 int32_t* aVal);
348 void GetPrefBool(nsIPrefBranch* aBranch, const char* aPref, const char* aData,
349 bool* aVal);
350 void GetPrefs(nsIPrefBranch* aBranch, const char* aData);
352 // Make private because we want only one instance of this class
353 explicit MediaManager(already_AddRefed<TaskQueue> aMediaThread);
355 ~MediaManager() = default;
356 void Shutdown();
358 void StopScreensharing(uint64_t aWindowID);
360 void RemoveMediaDevicesCallback(uint64_t aWindowID);
361 void DeviceListChanged();
362 void InvalidateDeviceCache();
363 void HandleDeviceListChanged();
365 // Returns the number of incomplete tasks associated with this window,
366 // including the newly added task.
367 size_t AddTaskAndGetCount(uint64_t aWindowID, const nsAString& aCallID,
368 RefPtr<GetUserMediaTask> aTask);
369 // Finds the task corresponding to aCallID and removes it from tracking.
370 RefPtr<GetUserMediaTask> TakeGetUserMediaTask(const nsAString& aCallID);
371 // Intended for use with "media.navigator.permission.disabled" to bypass the
372 // permission prompt and use the first appropriate device.
373 void NotifyAllowed(const nsString& aCallID,
374 const LocalMediaDeviceSet& aDevices);
376 // Media thread only
377 MediaEngine* GetBackend();
379 MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf);
381 // ONLY access from MainThread so we don't need to lock
382 WindowTable mActiveWindows;
383 nsRefPtrHashtable<nsStringHashKey, GetUserMediaTask> mActiveCallbacks;
384 nsClassHashtable<nsUint64HashKey, nsTArray<nsString>> mCallIds;
385 nsTArray<RefPtr<dom::GetUserMediaRequest>> mPendingGUMRequest;
386 // non-null if a device enumeration is in progress and was started after the
387 // last device-change invalidation
388 RefPtr<media::Refcountable<nsTArray<MozPromiseHolder<ConstDeviceSetPromise>>>>
389 mPendingDevicesPromises;
390 RefPtr<MediaDeviceSetRefCnt> mPhysicalDevices;
391 TimeStamp mUnhandledDeviceChangeTime;
392 RefPtr<MediaTimer> mDeviceChangeTimer;
393 bool mCamerasMuted = false;
394 bool mMicrophonesMuted = false;
396 public:
397 // Always exists
398 const RefPtr<TaskQueue> mMediaThread;
400 private:
401 nsCOMPtr<nsIAsyncShutdownBlocker> mShutdownBlocker;
403 // ONLY accessed from MediaManagerThread
404 RefPtr<MediaEngine> mBackend;
406 // Accessed only on main thread and mMediaThread.
407 // Set before mMediaThread is created, and cleared on main thread after last
408 // mMediaThread task is run.
409 static StaticRefPtr<MediaManager> sSingleton;
411 // Connect/Disconnect on media thread only
412 MediaEventListener mDeviceListChangeListener;
414 MediaEventProducer<void> mDeviceListChangeEvent;
416 public:
417 RefPtr<media::Parent<media::NonE10s>> mNonE10sParent;
420 } // namespace mozilla
422 #endif // MOZILLA_MEDIAMANAGER_H