Bug 1744350 consistently provide device sets by return value instead of side-effects...
[gecko.git] / dom / media / MediaManager.h
blob3f932e239e9bc337c9a0a36314193ad47f666dc9
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/StaticMutex.h"
25 #include "mozilla/StaticPtr.h"
26 #include "mozilla/dom/MediaStreamBinding.h"
27 #include "mozilla/dom/MediaStreamTrackBinding.h"
28 #include "mozilla/dom/MediaStreamError.h"
29 #include "mozilla/dom/NavigatorBinding.h"
30 #include "mozilla/media/MediaChild.h"
31 #include "mozilla/media/MediaParent.h"
32 #include "mozilla/Logging.h"
33 #include "mozilla/UniquePtr.h"
34 #include "DOMMediaStream.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 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 class MediaDevice : public nsIMediaDevice {
68 public:
69 NS_DECL_THREADSAFE_ISUPPORTS
70 NS_DECL_NSIMEDIADEVICE
72 MediaDevice(const RefPtr<MediaEngineSource>& aSource,
73 const nsString& aRawName, const nsString& aRawID,
74 const nsString& aRawGroupID);
76 MediaDevice(const RefPtr<AudioDeviceInfo>& aAudioDeviceInfo,
77 const nsString& aRawID, const nsString& aRawGroupID);
79 static RefPtr<MediaDevice> CopyWithNewRawGroupId(
80 const RefPtr<MediaDevice>& aOther, const nsString& aRawGroupID);
82 MediaDevice(const RefPtr<MediaDevice>& aOther, const nsString& aID,
83 const nsString& aGroupID, const nsString& aRawID,
84 const nsString& aRawGroupID, const nsString& aName);
86 uint32_t GetBestFitnessDistance(
87 const nsTArray<const NormalizedConstraintSet*>& aConstraintSets,
88 dom::CallerType aCallerType);
90 nsresult Allocate(const dom::MediaTrackConstraints& aConstraints,
91 const MediaEnginePrefs& aPrefs, uint64_t aWindowId,
92 const char** aOutBadConstraint);
93 void SetTrack(const RefPtr<MediaTrack>& aTrack,
94 const nsMainThreadPtrHandle<nsIPrincipal>& aPrincipal);
95 nsresult Start();
96 nsresult Reconfigure(const dom::MediaTrackConstraints& aConstraints,
97 const MediaEnginePrefs& aPrefs,
98 const char** aOutBadConstraint);
99 nsresult FocusOnSelectedSource();
100 nsresult Stop();
101 nsresult Deallocate();
103 void GetSettings(dom::MediaTrackSettings& aOutSettings) const;
105 dom::MediaSourceEnum GetMediaSource() const;
107 protected:
108 virtual ~MediaDevice() = default;
110 static uint32_t FitnessDistance(
111 nsString aN,
112 const dom::OwningStringOrStringSequenceOrConstrainDOMStringParameters&
113 aConstraint);
115 private:
116 static bool StringsContain(const dom::OwningStringOrStringSequence& aStrings,
117 nsString aN);
118 static uint32_t FitnessDistance(
119 nsString aN, const dom::ConstrainDOMStringParameters& aParams);
121 public:
122 const RefPtr<MediaEngineSource> mSource;
123 const RefPtr<AudioDeviceInfo> mSinkInfo;
124 const dom::MediaDeviceKind mKind;
125 const bool mScary;
126 const bool mIsFake;
127 const nsString mType;
128 const nsString mName;
129 const nsString mID;
130 const nsString mGroupID;
131 const nsString mRawID;
132 const nsString mRawGroupID;
133 const nsString mRawName;
136 typedef nsRefPtrHashtable<nsUint64HashKey, GetUserMediaWindowListener>
137 WindowTable;
139 class MediaManager final : public nsIMediaManagerService,
140 public nsIMemoryReporter,
141 public nsIObserver {
142 friend DeviceListener;
144 public:
145 static already_AddRefed<MediaManager> GetInstance();
147 // NOTE: never Dispatch(....,NS_DISPATCH_SYNC) to the MediaManager
148 // thread from the MainThread, as we NS_DISPATCH_SYNC to MainThread
149 // from MediaManager thread.
150 static MediaManager* Get();
151 static MediaManager* GetIfExists();
152 static void StartupInit();
153 static void Dispatch(already_AddRefed<Runnable> task);
156 * Posts an async operation to the media manager thread.
157 * FunctionType must be a function that takes a `MozPromiseHolder&`.
159 * The returned promise is resolved or rejected by aFunction on the media
160 * manager thread.
162 template <typename MozPromiseType, typename FunctionType>
163 static RefPtr<MozPromiseType> Dispatch(const char* aName,
164 FunctionType&& aFunction);
166 #ifdef DEBUG
167 static bool IsInMediaThread();
168 #endif
170 static bool Exists() { return !!GetIfExists(); }
172 static nsresult NotifyRecordingStatusChange(nsPIDOMWindowInner* aWindow);
174 NS_DECL_THREADSAFE_ISUPPORTS
175 NS_DECL_NSIOBSERVER
176 NS_DECL_NSIMEMORYREPORTER
177 NS_DECL_NSIMEDIAMANAGERSERVICE
179 media::Parent<media::NonE10s>* GetNonE10sParent();
180 MediaEngine* GetBackend();
182 // If the window has not been destroyed, then return the
183 // GetUserMediaWindowListener for this window.
184 // If the window has been destroyed, then return null.
185 RefPtr<GetUserMediaWindowListener> GetOrMakeWindowListener(
186 nsPIDOMWindowInner* aWindow);
187 WindowTable* GetActiveWindows() {
188 MOZ_ASSERT(NS_IsMainThread());
189 return &mActiveWindows;
191 GetUserMediaWindowListener* GetWindowListener(uint64_t aWindowId) {
192 MOZ_ASSERT(NS_IsMainThread());
193 return mActiveWindows.GetWeak(aWindowId);
195 void AddWindowID(uint64_t aWindowId,
196 RefPtr<GetUserMediaWindowListener> aListener);
197 void RemoveWindowID(uint64_t aWindowId);
198 void SendPendingGUMRequest();
199 bool IsWindowStillActive(uint64_t aWindowId) {
200 return !!GetWindowListener(aWindowId);
202 bool IsWindowListenerStillActive(
203 const RefPtr<GetUserMediaWindowListener>& aListener);
205 static bool IsOn(const dom::OwningBooleanOrMediaTrackConstraints& aUnion) {
206 return !aUnion.IsBoolean() || aUnion.GetAsBoolean();
208 using GetUserMediaSuccessCallback = dom::NavigatorUserMediaSuccessCallback;
209 using GetUserMediaErrorCallback = dom::NavigatorUserMediaErrorCallback;
211 MOZ_CAN_RUN_SCRIPT
212 static void CallOnError(GetUserMediaErrorCallback& aCallback,
213 dom::MediaStreamError& aError);
214 MOZ_CAN_RUN_SCRIPT
215 static void CallOnSuccess(GetUserMediaSuccessCallback& aCallback,
216 DOMMediaStream& aTrack);
218 using MediaDeviceSet = nsTArray<RefPtr<MediaDevice>>;
219 using MediaDeviceSetRefCnt = media::Refcountable<MediaDeviceSet>;
221 using StreamPromise =
222 MozPromise<RefPtr<DOMMediaStream>, RefPtr<MediaMgrError>, true>;
223 using DevicePromise =
224 MozPromise<RefPtr<MediaDevice>, RefPtr<MediaMgrError>, true>;
225 using DeviceSetPromise =
226 MozPromise<RefPtr<MediaDeviceSetRefCnt>, RefPtr<MediaMgrError>, true>;
227 using MgrPromise = MozPromise<bool, RefPtr<MediaMgrError>, true>;
229 RefPtr<StreamPromise> GetUserMedia(
230 nsPIDOMWindowInner* aWindow,
231 const dom::MediaStreamConstraints& aConstraints,
232 dom::CallerType aCallerType);
234 RefPtr<DeviceSetPromise> EnumerateDevices(nsPIDOMWindowInner* aWindow);
236 enum class DeviceEnumerationType : uint8_t {
237 Normal, // Enumeration should not return loopback or fake devices
238 Fake, // Enumeration should return fake device(s)
239 Loopback /* Enumeration should return loopback device(s) (possibly in
240 addition to normal devices) */
242 enum class EnumerationFlag { AllowPermissionRequest, EnumerateAudioOutputs };
243 using EnumerationFlags = EnumSet<EnumerationFlag>;
244 RefPtr<DeviceSetPromise> EnumerateDevicesImpl(
245 nsPIDOMWindowInner* aWindow, dom::MediaSourceEnum aVideoInputType,
246 dom::MediaSourceEnum aAudioInputType,
247 DeviceEnumerationType aVideoInputEnumType,
248 DeviceEnumerationType aAudioInputEnumType, EnumerationFlags aFlags);
250 RefPtr<DevicePromise> SelectAudioOutput(
251 nsPIDOMWindowInner* aWindow, const dom::AudioOutputOptions& aOptions,
252 dom::CallerType aCallerType);
254 void OnNavigation(uint64_t aWindowID);
255 void OnCameraMute(bool aMute);
256 void OnMicrophoneMute(bool aMute);
257 bool IsActivelyCapturingOrHasAPermission(uint64_t aWindowId);
259 MediaEventSource<void>& DeviceListChangeEvent() {
260 return mDeviceListChangeEvent;
263 MediaEnginePrefs mPrefs;
265 private:
266 static nsresult GenerateUUID(nsAString& aResult);
267 static nsresult AnonymizeId(nsAString& aId, const nsACString& aOriginKey);
269 public: // TODO: make private once we upgrade to GCC 4.8+ on linux.
270 static void AnonymizeDevices(MediaDeviceSet& aDevices,
271 const nsACString& aOriginKey,
272 const uint64_t aWindowId);
275 * This function tries to guess the group id for a video device in aDevices
276 * based on the device name. If the name of only one audio device in aAudios
277 * contains the name of the video device, then, this video device will take
278 * the group id of the audio device. Since this is a guess we try to minimize
279 * the probability of false positive. If we fail to find a correlation we
280 * leave the video group id untouched. In that case the group id will be the
281 * video device name.
283 static void GuessVideoDeviceGroupIDs(MediaDeviceSet& aDevices,
284 const MediaDeviceSet& aAudios);
286 private:
287 RefPtr<DeviceSetPromise> EnumerateRawDevices(
288 dom::MediaSourceEnum aVideoInputType,
289 dom::MediaSourceEnum aAudioInputType,
290 DeviceEnumerationType aVideoInputEnumType,
291 DeviceEnumerationType aAudioInputEnumType, EnumerationFlags aFlags);
293 RefPtr<DeviceSetPromise> SelectSettings(
294 const dom::MediaStreamConstraints& aConstraints,
295 dom::CallerType aCallerType, RefPtr<MediaDeviceSetRefCnt> aDevices);
297 void GetPref(nsIPrefBranch* aBranch, const char* aPref, const char* aData,
298 int32_t* aVal);
299 void GetPrefBool(nsIPrefBranch* aBranch, const char* aPref, const char* aData,
300 bool* aVal);
301 void GetPrefs(nsIPrefBranch* aBranch, const char* aData);
303 // Make private because we want only one instance of this class
304 explicit MediaManager(already_AddRefed<TaskQueue> aMediaThread);
306 ~MediaManager() = default;
307 void Shutdown();
309 void StopScreensharing(uint64_t aWindowID);
311 void RemoveMediaDevicesCallback(uint64_t aWindowID);
312 void DeviceListChanged();
314 // Returns the number of incomplete tasks associated with this window,
315 // including the newly added task.
316 size_t AddTaskAndGetCount(uint64_t aWindowID, const nsAString& aCallID,
317 RefPtr<GetUserMediaTask> aTask);
318 // Finds the task corresponding to aCallID and removes it from tracking.
319 RefPtr<GetUserMediaTask> TakeGetUserMediaTask(const nsAString& aCallID);
320 // Intended for use with "media.navigator.permission.disabled" to bypass the
321 // permission prompt and use the first appropriate device.
322 void NotifyAllowed(const nsString& aCallID, const MediaDeviceSet& aDevices);
324 MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf);
326 struct nsStringHasher {
327 using Key = nsString;
328 using Lookup = nsString;
330 static HashNumber hash(const Lookup& aLookup) {
331 return HashString(aLookup.get());
334 static bool match(const Key& aKey, const Lookup& aLookup) {
335 return aKey == aLookup;
339 // ONLY access from MainThread so we don't need to lock
340 WindowTable mActiveWindows;
341 nsRefPtrHashtable<nsStringHashKey, GetUserMediaTask> mActiveCallbacks;
342 nsClassHashtable<nsUint64HashKey, nsTArray<nsString>> mCallIds;
343 nsTArray<RefPtr<dom::GetUserMediaRequest>> mPendingGUMRequest;
344 using DeviceIdSet = HashSet<nsString, nsStringHasher, InfallibleAllocPolicy>;
345 DeviceIdSet mDeviceIDs;
346 RefPtr<MediaTimer> mDeviceChangeTimer;
347 bool mCamerasMuted = false;
348 bool mMicrophonesMuted = false;
350 // Always exists
351 const RefPtr<TaskQueue> mMediaThread;
352 nsCOMPtr<nsIAsyncShutdownBlocker> mShutdownBlocker;
354 // ONLY accessed from MediaManagerThread
355 RefPtr<MediaEngine> mBackend;
357 static StaticRefPtr<MediaManager> sSingleton;
358 static StaticMutex sSingletonMutex;
360 // Connect/Disconnect on media thread only
361 MediaEventListener mDeviceListChangeListener;
363 MediaEventProducer<void> mDeviceListChangeEvent;
365 public:
366 RefPtr<media::Parent<media::NonE10s>> mNonE10sParent;
369 } // namespace mozilla
371 #endif // MOZILLA_MEDIAMANAGER_H