Bug 1753316 remove unnecessary sSingletonMutex r=jib
[gecko.git] / dom / media / MediaManager.h
blob3b470c305a4163e850fafb9465ac4cdee1b8a2fa
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"
35 #ifdef MOZ_WEBRTC
36 # include "transport/runnable_utils.h"
37 #endif
39 class AudioDeviceInfo;
40 class nsIPrefBranch;
42 namespace mozilla {
43 class MediaEngine;
44 class MediaEngineSource;
45 class TaskQueue;
46 class MediaTimer;
47 class MediaTrack;
48 namespace dom {
49 struct AudioOutputOptions;
50 struct MediaStreamConstraints;
51 struct MediaTrackConstraints;
52 struct MediaTrackConstraintSet;
53 struct MediaTrackSettings;
54 enum class CallerType : uint32_t;
55 enum class MediaDeviceKind : uint8_t;
56 } // namespace dom
58 namespace ipc {
59 class PrincipalInfo;
62 class GetUserMediaTask;
63 class GetUserMediaWindowListener;
64 class MediaManager;
65 class DeviceListener;
67 /**
68 * Device info that is independent of any Window.
69 * MediaDevices can be shared, unlike LocalMediaDevices.
71 class MediaDevice final {
72 public:
73 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDevice)
75 /**
76 * Whether source device does end-run around cross origin restrictions.
78 enum class IsScary { No, Yes };
79 MediaDevice(MediaEngine* aEngine, dom::MediaSourceEnum aMediaSource,
80 const nsString& aRawName, const nsString& aRawID,
81 const nsString& aRawGroupID, IsScary aIsScary);
83 MediaDevice(MediaEngine* aEngine,
84 const RefPtr<AudioDeviceInfo>& aAudioDeviceInfo,
85 const nsString& aRawID);
87 static RefPtr<MediaDevice> CopyWithNewRawGroupId(
88 const RefPtr<MediaDevice>& aOther, const nsString& aRawGroupID);
90 dom::MediaSourceEnum GetMediaSource() const;
92 protected:
93 ~MediaDevice();
95 public:
96 const RefPtr<MediaEngine> mEngine;
97 const RefPtr<AudioDeviceInfo> mAudioDeviceInfo;
98 const dom::MediaSourceEnum mMediaSource;
99 const dom::MediaDeviceKind mKind;
100 const bool mScary;
101 const bool mIsFake;
102 const nsString mType;
103 const nsString mRawID;
104 const nsString mRawGroupID;
105 const nsString mRawName;
109 * Device info that is specific to a particular Window. If the device is a
110 * source device, then a single corresponding MediaEngineSource is provided,
111 * which can provide a maximum of one capture stream. LocalMediaDevices are
112 * not shared, but APIs returning LocalMediaDevices return a new object each
113 * call.
115 class LocalMediaDevice final : public nsIMediaDevice {
116 public:
117 NS_DECL_THREADSAFE_ISUPPORTS
118 NS_DECL_NSIMEDIADEVICE
120 LocalMediaDevice(RefPtr<const MediaDevice> aRawDevice, const nsString& aID,
121 const nsString& aGroupID, const nsString& aName);
123 uint32_t GetBestFitnessDistance(
124 const nsTArray<const NormalizedConstraintSet*>& aConstraintSets,
125 dom::CallerType aCallerType);
127 nsresult Allocate(const dom::MediaTrackConstraints& aConstraints,
128 const MediaEnginePrefs& aPrefs, uint64_t aWindowId,
129 const char** aOutBadConstraint);
130 void SetTrack(const RefPtr<MediaTrack>& aTrack,
131 const nsMainThreadPtrHandle<nsIPrincipal>& aPrincipal);
132 nsresult Start();
133 nsresult Reconfigure(const dom::MediaTrackConstraints& aConstraints,
134 const MediaEnginePrefs& aPrefs,
135 const char** aOutBadConstraint);
136 nsresult FocusOnSelectedSource();
137 nsresult Stop();
138 nsresult Deallocate();
140 void GetSettings(dom::MediaTrackSettings& aOutSettings);
141 MediaEngineSource* Source();
142 // Returns null if not a physical audio device.
143 AudioDeviceInfo* GetAudioDeviceInfo() const {
144 return mRawDevice->mAudioDeviceInfo;
146 dom::MediaSourceEnum GetMediaSource() const {
147 return mRawDevice->GetMediaSource();
149 dom::MediaDeviceKind Kind() const { return mRawDevice->mKind; }
150 bool IsFake() const { return mRawDevice->mIsFake; }
151 const nsString& RawID() { return mRawDevice->mRawID; }
153 private:
154 virtual ~LocalMediaDevice() = default;
156 static uint32_t FitnessDistance(
157 nsString aN,
158 const dom::OwningStringOrStringSequenceOrConstrainDOMStringParameters&
159 aConstraint);
161 static bool StringsContain(const dom::OwningStringOrStringSequence& aStrings,
162 nsString aN);
163 static uint32_t FitnessDistance(
164 nsString aN, const dom::ConstrainDOMStringParameters& aParams);
166 public:
167 const RefPtr<const MediaDevice> mRawDevice;
168 const nsString mName;
169 const nsString mID;
170 const nsString mGroupID;
172 private:
173 RefPtr<MediaEngineSource> mSource;
176 typedef nsRefPtrHashtable<nsUint64HashKey, GetUserMediaWindowListener>
177 WindowTable;
179 class MediaManager final : public nsIMediaManagerService,
180 public nsIMemoryReporter,
181 public nsIObserver {
182 friend DeviceListener;
184 public:
185 static already_AddRefed<MediaManager> GetInstance();
187 // NOTE: never Dispatch(....,NS_DISPATCH_SYNC) to the MediaManager
188 // thread from the MainThread, as we NS_DISPATCH_SYNC to MainThread
189 // from MediaManager thread.
190 static MediaManager* Get();
191 static MediaManager* GetIfExists();
192 static void StartupInit();
193 static void Dispatch(already_AddRefed<Runnable> task);
196 * Posts an async operation to the media manager thread.
197 * FunctionType must be a function that takes a `MozPromiseHolder&`.
199 * The returned promise is resolved or rejected by aFunction on the media
200 * manager thread.
202 template <typename MozPromiseType, typename FunctionType>
203 static RefPtr<MozPromiseType> Dispatch(const char* aName,
204 FunctionType&& aFunction);
206 #ifdef DEBUG
207 static bool IsInMediaThread();
208 #endif
210 static bool Exists() { return !!GetIfExists(); }
212 static nsresult NotifyRecordingStatusChange(nsPIDOMWindowInner* aWindow);
214 NS_DECL_THREADSAFE_ISUPPORTS
215 NS_DECL_NSIOBSERVER
216 NS_DECL_NSIMEMORYREPORTER
217 NS_DECL_NSIMEDIAMANAGERSERVICE
219 media::Parent<media::NonE10s>* GetNonE10sParent();
221 // If the window has not been destroyed, then return the
222 // GetUserMediaWindowListener for this window.
223 // If the window has been destroyed, then return null.
224 RefPtr<GetUserMediaWindowListener> GetOrMakeWindowListener(
225 nsPIDOMWindowInner* aWindow);
226 WindowTable* GetActiveWindows() {
227 MOZ_ASSERT(NS_IsMainThread());
228 return &mActiveWindows;
230 GetUserMediaWindowListener* GetWindowListener(uint64_t aWindowId) {
231 MOZ_ASSERT(NS_IsMainThread());
232 return mActiveWindows.GetWeak(aWindowId);
234 void AddWindowID(uint64_t aWindowId,
235 RefPtr<GetUserMediaWindowListener> aListener);
236 void RemoveWindowID(uint64_t aWindowId);
237 void SendPendingGUMRequest();
238 bool IsWindowStillActive(uint64_t aWindowId) {
239 return !!GetWindowListener(aWindowId);
241 bool IsWindowListenerStillActive(
242 const RefPtr<GetUserMediaWindowListener>& aListener);
244 static bool IsOn(const dom::OwningBooleanOrMediaTrackConstraints& aUnion) {
245 return !aUnion.IsBoolean() || aUnion.GetAsBoolean();
247 using GetUserMediaSuccessCallback = dom::NavigatorUserMediaSuccessCallback;
248 using GetUserMediaErrorCallback = dom::NavigatorUserMediaErrorCallback;
250 MOZ_CAN_RUN_SCRIPT
251 static void CallOnError(GetUserMediaErrorCallback& aCallback,
252 dom::MediaStreamError& aError);
253 MOZ_CAN_RUN_SCRIPT
254 static void CallOnSuccess(GetUserMediaSuccessCallback& aCallback,
255 DOMMediaStream& aTrack);
257 using MediaDeviceSet = nsTArray<RefPtr<MediaDevice>>;
258 using MediaDeviceSetRefCnt = media::Refcountable<MediaDeviceSet>;
259 using LocalMediaDeviceSet = nsTArray<RefPtr<LocalMediaDevice>>;
260 using LocalMediaDeviceSetRefCnt = media::Refcountable<LocalMediaDeviceSet>;
262 using StreamPromise =
263 MozPromise<RefPtr<DOMMediaStream>, RefPtr<MediaMgrError>, true>;
264 using DeviceSetPromise =
265 MozPromise<RefPtr<MediaDeviceSetRefCnt>, RefPtr<MediaMgrError>, true>;
266 using ConstDeviceSetPromise = MozPromise<RefPtr<const MediaDeviceSetRefCnt>,
267 RefPtr<MediaMgrError>, true>;
268 using LocalDevicePromise =
269 MozPromise<RefPtr<LocalMediaDevice>, RefPtr<MediaMgrError>, true>;
270 using LocalDeviceSetPromise = MozPromise<RefPtr<LocalMediaDeviceSetRefCnt>,
271 RefPtr<MediaMgrError>, true>;
272 using MgrPromise = MozPromise<bool, RefPtr<MediaMgrError>, true>;
274 RefPtr<StreamPromise> GetUserMedia(
275 nsPIDOMWindowInner* aWindow,
276 const dom::MediaStreamConstraints& aConstraints,
277 dom::CallerType aCallerType);
279 RefPtr<LocalDevicePromise> SelectAudioOutput(
280 nsPIDOMWindowInner* aWindow, const dom::AudioOutputOptions& aOptions,
281 dom::CallerType aCallerType);
283 // Return the list of microphone, camera, and speaker devices.
284 // MediaDeviceSets provided on promise resolution are shared between
285 // callers and so cannot be modified.
286 RefPtr<ConstDeviceSetPromise> GetPhysicalDevices();
288 void OnNavigation(uint64_t aWindowID);
289 void OnCameraMute(bool aMute);
290 void OnMicrophoneMute(bool aMute);
291 bool IsActivelyCapturingOrHasAPermission(uint64_t aWindowId);
293 MediaEventSource<void>& DeviceListChangeEvent() {
294 return mDeviceListChangeEvent;
296 RefPtr<LocalDeviceSetPromise> AnonymizeDevices(
297 nsPIDOMWindowInner* aWindow, RefPtr<const MediaDeviceSetRefCnt> aDevices);
299 MediaEnginePrefs mPrefs;
301 private:
302 static nsresult GenerateUUID(nsAString& aResult);
303 static nsresult AnonymizeId(nsAString& aId, const nsACString& aOriginKey);
305 public:
307 * This function tries to guess the group id for a video device in aDevices
308 * based on the device name. If the name of only one audio device in aAudios
309 * contains the name of the video device, then, this video device will take
310 * the group id of the audio device. Since this is a guess we try to minimize
311 * the probability of false positive. If we fail to find a correlation we
312 * leave the video group id untouched. In that case the group id will be the
313 * video device name.
315 static void GuessVideoDeviceGroupIDs(MediaDeviceSet& aDevices,
316 const MediaDeviceSet& aAudios);
318 private:
319 enum class EnumerationFlag {
320 AllowPermissionRequest,
321 EnumerateAudioOutputs,
322 ForceFakes,
324 using EnumerationFlags = EnumSet<EnumerationFlag>;
325 RefPtr<LocalDeviceSetPromise> EnumerateDevicesImpl(
326 nsPIDOMWindowInner* aWindow, dom::MediaSourceEnum aVideoInputType,
327 dom::MediaSourceEnum aAudioInputType, EnumerationFlags aFlags);
329 RefPtr<DeviceSetPromise> EnumerateRawDevices(
330 dom::MediaSourceEnum aVideoInputType,
331 dom::MediaSourceEnum aAudioInputType, EnumerationFlags aFlags);
333 RefPtr<LocalDeviceSetPromise> SelectSettings(
334 const dom::MediaStreamConstraints& aConstraints,
335 dom::CallerType aCallerType, RefPtr<LocalMediaDeviceSetRefCnt> aDevices);
337 void GetPref(nsIPrefBranch* aBranch, const char* aPref, const char* aData,
338 int32_t* aVal);
339 void GetPrefBool(nsIPrefBranch* aBranch, const char* aPref, const char* aData,
340 bool* aVal);
341 void GetPrefs(nsIPrefBranch* aBranch, const char* aData);
343 // Make private because we want only one instance of this class
344 explicit MediaManager(already_AddRefed<TaskQueue> aMediaThread);
346 ~MediaManager() = default;
347 void Shutdown();
349 void StopScreensharing(uint64_t aWindowID);
351 void RemoveMediaDevicesCallback(uint64_t aWindowID);
352 void DeviceListChanged();
353 void InvalidateDeviceCache();
354 void HandleDeviceListChanged();
356 // Returns the number of incomplete tasks associated with this window,
357 // including the newly added task.
358 size_t AddTaskAndGetCount(uint64_t aWindowID, const nsAString& aCallID,
359 RefPtr<GetUserMediaTask> aTask);
360 // Finds the task corresponding to aCallID and removes it from tracking.
361 RefPtr<GetUserMediaTask> TakeGetUserMediaTask(const nsAString& aCallID);
362 // Intended for use with "media.navigator.permission.disabled" to bypass the
363 // permission prompt and use the first appropriate device.
364 void NotifyAllowed(const nsString& aCallID,
365 const LocalMediaDeviceSet& aDevices);
367 // Media thread only
368 MediaEngine* GetBackend();
370 MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf);
372 // ONLY access from MainThread so we don't need to lock
373 WindowTable mActiveWindows;
374 nsRefPtrHashtable<nsStringHashKey, GetUserMediaTask> mActiveCallbacks;
375 nsClassHashtable<nsUint64HashKey, nsTArray<nsString>> mCallIds;
376 nsTArray<RefPtr<dom::GetUserMediaRequest>> mPendingGUMRequest;
377 // non-null if a device enumeration is in progress and was started after the
378 // last device-change invalidation
379 RefPtr<media::Refcountable<nsTArray<MozPromiseHolder<ConstDeviceSetPromise>>>>
380 mPendingDevicesPromises;
381 RefPtr<MediaDeviceSetRefCnt> mPhysicalDevices;
382 TimeStamp mUnhandledDeviceChangeTime;
383 RefPtr<MediaTimer> mDeviceChangeTimer;
384 bool mCamerasMuted = false;
385 bool mMicrophonesMuted = false;
387 // Always exists
388 const RefPtr<TaskQueue> mMediaThread;
389 nsCOMPtr<nsIAsyncShutdownBlocker> mShutdownBlocker;
391 // ONLY accessed from MediaManagerThread
392 RefPtr<MediaEngine> mBackend;
394 // Accessed only on main thread and mMediaThread.
395 // Set before mMediaThread is created, and cleared on main thread after last
396 // mMediaThread task is run.
397 static StaticRefPtr<MediaManager> sSingleton;
399 // Connect/Disconnect on media thread only
400 MediaEventListener mDeviceListChangeListener;
402 MediaEventProducer<void> mDeviceListChangeEvent;
404 public:
405 RefPtr<media::Parent<media::NonE10s>> mNonE10sParent;
408 } // namespace mozilla
410 #endif // MOZILLA_MEDIAMANAGER_H