Bug 1856663 - Add more chunks for Android mochitest-plain. r=jmaher,taskgraph-reviewe...
[gecko.git] / dom / media / MediaManager.h
blob413fccf607c5f10ed7f8c279336b062bba300b53
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 Dispatch(already_AddRefed<Runnable> task);
205 * Posts an async operation to the media manager thread.
206 * FunctionType must be a function that takes a `MozPromiseHolder&`.
208 * The returned promise is resolved or rejected by aFunction on the media
209 * manager thread.
211 template <typename MozPromiseType, typename FunctionType>
212 static RefPtr<MozPromiseType> Dispatch(const char* aName,
213 FunctionType&& aFunction);
215 #ifdef DEBUG
216 static bool IsInMediaThread();
217 #endif
219 static bool Exists() { return !!GetIfExists(); }
221 static nsresult NotifyRecordingStatusChange(nsPIDOMWindowInner* aWindow);
223 NS_DECL_THREADSAFE_ISUPPORTS
224 NS_DECL_NSIOBSERVER
225 NS_DECL_NSIMEMORYREPORTER
226 NS_DECL_NSIMEDIAMANAGERSERVICE
228 media::Parent<media::NonE10s>* GetNonE10sParent();
230 // If the window has not been destroyed, then return the
231 // GetUserMediaWindowListener for this window.
232 // If the window has been destroyed, then return null.
233 RefPtr<GetUserMediaWindowListener> GetOrMakeWindowListener(
234 nsPIDOMWindowInner* aWindow);
235 WindowTable* GetActiveWindows() {
236 MOZ_ASSERT(NS_IsMainThread());
237 return &mActiveWindows;
239 GetUserMediaWindowListener* GetWindowListener(uint64_t aWindowId) {
240 MOZ_ASSERT(NS_IsMainThread());
241 return mActiveWindows.GetWeak(aWindowId);
243 void AddWindowID(uint64_t aWindowId,
244 RefPtr<GetUserMediaWindowListener> aListener);
245 void RemoveWindowID(uint64_t aWindowId);
246 void SendPendingGUMRequest();
247 bool IsWindowStillActive(uint64_t aWindowId) {
248 return !!GetWindowListener(aWindowId);
250 bool IsWindowListenerStillActive(
251 const RefPtr<GetUserMediaWindowListener>& aListener);
253 static bool IsOn(const dom::OwningBooleanOrMediaTrackConstraints& aUnion) {
254 return !aUnion.IsBoolean() || aUnion.GetAsBoolean();
256 using GetUserMediaSuccessCallback = dom::NavigatorUserMediaSuccessCallback;
257 using GetUserMediaErrorCallback = dom::NavigatorUserMediaErrorCallback;
259 MOZ_CAN_RUN_SCRIPT
260 static void CallOnError(GetUserMediaErrorCallback& aCallback,
261 dom::MediaStreamError& aError);
262 MOZ_CAN_RUN_SCRIPT
263 static void CallOnSuccess(GetUserMediaSuccessCallback& aCallback,
264 DOMMediaStream& aTrack);
266 using MediaDeviceSet = nsTArray<RefPtr<MediaDevice>>;
267 using MediaDeviceSetRefCnt = media::Refcountable<MediaDeviceSet>;
268 using LocalMediaDeviceSet = nsTArray<RefPtr<LocalMediaDevice>>;
269 using LocalMediaDeviceSetRefCnt = media::Refcountable<LocalMediaDeviceSet>;
271 using StreamPromise =
272 MozPromise<RefPtr<DOMMediaStream>, RefPtr<MediaMgrError>, true>;
273 using DeviceSetPromise =
274 MozPromise<RefPtr<MediaDeviceSetRefCnt>, RefPtr<MediaMgrError>, true>;
275 using ConstDeviceSetPromise = MozPromise<RefPtr<const MediaDeviceSetRefCnt>,
276 RefPtr<MediaMgrError>, true>;
277 using LocalDevicePromise =
278 MozPromise<RefPtr<LocalMediaDevice>, RefPtr<MediaMgrError>, true>;
279 using LocalDeviceSetPromise = MozPromise<RefPtr<LocalMediaDeviceSetRefCnt>,
280 RefPtr<MediaMgrError>, true>;
281 using MgrPromise = MozPromise<bool, RefPtr<MediaMgrError>, true>;
283 RefPtr<StreamPromise> GetUserMedia(
284 nsPIDOMWindowInner* aWindow,
285 const dom::MediaStreamConstraints& aConstraints,
286 dom::CallerType aCallerType);
288 RefPtr<LocalDevicePromise> SelectAudioOutput(
289 nsPIDOMWindowInner* aWindow, const dom::AudioOutputOptions& aOptions,
290 dom::CallerType aCallerType);
292 // Return the list of microphone, camera, and speaker devices.
293 // MediaDeviceSets provided on promise resolution are shared between
294 // callers and so cannot be modified.
295 RefPtr<ConstDeviceSetPromise> GetPhysicalDevices();
297 void OnNavigation(uint64_t aWindowID);
298 void OnCameraMute(bool aMute);
299 void OnMicrophoneMute(bool aMute);
300 bool IsActivelyCapturingOrHasAPermission(uint64_t aWindowId);
302 MediaEventSource<void>& DeviceListChangeEvent() {
303 return mDeviceListChangeEvent;
305 RefPtr<LocalDeviceSetPromise> AnonymizeDevices(
306 nsPIDOMWindowInner* aWindow, RefPtr<const MediaDeviceSetRefCnt> aDevices);
308 MediaEnginePrefs mPrefs;
310 private:
311 static nsresult GenerateUUID(nsAString& aResult);
313 public:
315 * This function tries to guess the group id for a video device in aDevices
316 * based on the device name. If the name of only one audio device in aAudios
317 * contains the name of the video device, then, this video device will take
318 * the group id of the audio device. Since this is a guess we try to minimize
319 * the probability of false positive. If we fail to find a correlation we
320 * leave the video group id untouched. In that case the group id will be the
321 * video device name.
323 static void GuessVideoDeviceGroupIDs(MediaDeviceSet& aDevices,
324 const MediaDeviceSet& aAudios);
326 private:
327 enum class EnumerationFlag {
328 AllowPermissionRequest,
329 EnumerateAudioOutputs,
330 ForceFakes,
332 using EnumerationFlags = EnumSet<EnumerationFlag>;
333 RefPtr<LocalDeviceSetPromise> EnumerateDevicesImpl(
334 nsPIDOMWindowInner* aWindow, dom::MediaSourceEnum aVideoInputType,
335 dom::MediaSourceEnum aAudioInputType, EnumerationFlags aFlags);
337 RefPtr<DeviceSetPromise> EnumerateRawDevices(
338 dom::MediaSourceEnum aVideoInputType,
339 dom::MediaSourceEnum aAudioInputType, EnumerationFlags aFlags);
341 RefPtr<LocalDeviceSetPromise> SelectSettings(
342 const dom::MediaStreamConstraints& aConstraints,
343 dom::CallerType aCallerType, RefPtr<LocalMediaDeviceSetRefCnt> aDevices);
345 void GetPref(nsIPrefBranch* aBranch, const char* aPref, const char* aData,
346 int32_t* aVal);
347 void GetPrefBool(nsIPrefBranch* aBranch, const char* aPref, const char* aData,
348 bool* aVal);
349 void GetPrefs(nsIPrefBranch* aBranch, const char* aData);
351 // Make private because we want only one instance of this class
352 explicit MediaManager(already_AddRefed<TaskQueue> aMediaThread);
354 ~MediaManager() = default;
355 void Shutdown();
357 void StopScreensharing(uint64_t aWindowID);
359 void RemoveMediaDevicesCallback(uint64_t aWindowID);
360 void DeviceListChanged();
361 void InvalidateDeviceCache();
362 void HandleDeviceListChanged();
364 // Returns the number of incomplete tasks associated with this window,
365 // including the newly added task.
366 size_t AddTaskAndGetCount(uint64_t aWindowID, const nsAString& aCallID,
367 RefPtr<GetUserMediaTask> aTask);
368 // Finds the task corresponding to aCallID and removes it from tracking.
369 RefPtr<GetUserMediaTask> TakeGetUserMediaTask(const nsAString& aCallID);
370 // Intended for use with "media.navigator.permission.disabled" to bypass the
371 // permission prompt and use the first appropriate device.
372 void NotifyAllowed(const nsString& aCallID,
373 const LocalMediaDeviceSet& aDevices);
375 // Media thread only
376 MediaEngine* GetBackend();
378 MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf);
380 // ONLY access from MainThread so we don't need to lock
381 WindowTable mActiveWindows;
382 nsRefPtrHashtable<nsStringHashKey, GetUserMediaTask> mActiveCallbacks;
383 nsClassHashtable<nsUint64HashKey, nsTArray<nsString>> mCallIds;
384 nsTArray<RefPtr<dom::GetUserMediaRequest>> mPendingGUMRequest;
385 // non-null if a device enumeration is in progress and was started after the
386 // last device-change invalidation
387 RefPtr<media::Refcountable<nsTArray<MozPromiseHolder<ConstDeviceSetPromise>>>>
388 mPendingDevicesPromises;
389 RefPtr<MediaDeviceSetRefCnt> mPhysicalDevices;
390 TimeStamp mUnhandledDeviceChangeTime;
391 RefPtr<MediaTimer> mDeviceChangeTimer;
392 bool mCamerasMuted = false;
393 bool mMicrophonesMuted = false;
395 public:
396 // Always exists
397 const RefPtr<TaskQueue> mMediaThread;
399 private:
400 nsCOMPtr<nsIAsyncShutdownBlocker> mShutdownBlocker;
402 // ONLY accessed from MediaManagerThread
403 RefPtr<MediaEngine> mBackend;
405 // Accessed only on main thread and mMediaThread.
406 // Set before mMediaThread is created, and cleared on main thread after last
407 // mMediaThread task is run.
408 static StaticRefPtr<MediaManager> sSingleton;
410 // Connect/Disconnect on media thread only
411 MediaEventListener mDeviceListChangeListener;
413 MediaEventProducer<void> mDeviceListChangeEvent;
415 public:
416 RefPtr<media::Parent<media::NonE10s>> mNonE10sParent;
419 } // namespace mozilla
421 #endif // MOZILLA_MEDIAMANAGER_H