Bug 1708422: part 16) Rename `mozInlineSpellChecker::SpellCheckerTimeSlice` to `mozIn...
[gecko.git] / dom / media / MediaManager.h
blob2e0274f63b077cab09f21ed3ccf4882c658cf195
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 "MediaEngine.h"
9 #include "MediaEnginePrefs.h"
10 #include "MediaEventSource.h"
11 #include "mozilla/dom/GetUserMediaRequest.h"
12 #include "mozilla/Unused.h"
13 #include "nsIMediaDevice.h"
14 #include "nsIMediaManager.h"
16 #include "nsHashKeys.h"
17 #include "nsClassHashtable.h"
18 #include "nsRefPtrHashtable.h"
19 #include "nsIMemoryReporter.h"
20 #include "nsIObserver.h"
22 #include "nsXULAppAPI.h"
23 #include "mozilla/Attributes.h"
24 #include "mozilla/Preferences.h"
25 #include "mozilla/StaticMutex.h"
26 #include "mozilla/StaticPtr.h"
27 #include "mozilla/dom/MediaStreamBinding.h"
28 #include "mozilla/dom/MediaStreamTrackBinding.h"
29 #include "mozilla/dom/MediaStreamError.h"
30 #include "mozilla/dom/NavigatorBinding.h"
31 #include "mozilla/media/MediaChild.h"
32 #include "mozilla/media/MediaParent.h"
33 #include "mozilla/Logging.h"
34 #include "mozilla/UniquePtr.h"
35 #include "DOMMediaStream.h"
37 #ifdef MOZ_WEBRTC
38 # include "transport/runnable_utils.h"
39 #endif
41 class nsIPrefBranch;
43 namespace mozilla {
44 class TaskQueue;
45 class MediaTimer;
46 namespace dom {
47 struct AudioOutputOptions;
48 struct MediaStreamConstraints;
49 struct MediaTrackConstraints;
50 struct MediaTrackConstraintSet;
51 enum class CallerType : uint32_t;
52 enum class MediaDeviceKind : uint8_t;
53 } // namespace dom
55 namespace ipc {
56 class PrincipalInfo;
59 class GetUserMediaTask;
60 class GetUserMediaWindowListener;
61 class MediaManager;
62 class DeviceListener;
64 class MediaDevice : public nsIMediaDevice {
65 public:
66 NS_DECL_THREADSAFE_ISUPPORTS
67 NS_DECL_NSIMEDIADEVICE
69 MediaDevice(const RefPtr<MediaEngineSource>& aSource, const nsString& aName,
70 const nsString& aID, const nsString& aGroupID,
71 const nsString& aRawID);
73 MediaDevice(const RefPtr<AudioDeviceInfo>& aAudioDeviceInfo,
74 const nsString& aID, const nsString& aGroupID,
75 const nsString& aRawID = u""_ns);
77 MediaDevice(const RefPtr<MediaDevice>& aOther, const nsString& aID,
78 const nsString& aGroupID, const nsString& aRawID,
79 const nsString& aRawGroupID);
81 MediaDevice(const RefPtr<MediaDevice>& aOther, const nsString& aID,
82 const nsString& aGroupID, const nsString& aRawID,
83 const nsString& aRawGroupID, const nsString& aName);
85 uint32_t GetBestFitnessDistance(
86 const nsTArray<const NormalizedConstraintSet*>& aConstraintSets,
87 dom::CallerType aCallerType);
89 nsresult Allocate(const dom::MediaTrackConstraints& aConstraints,
90 const MediaEnginePrefs& aPrefs, uint64_t aWindowId,
91 const char** aOutBadConstraint);
92 void SetTrack(const RefPtr<MediaTrack>& aTrack,
93 const PrincipalHandle& aPrincipal);
94 nsresult Start();
95 nsresult Reconfigure(const dom::MediaTrackConstraints& aConstraints,
96 const MediaEnginePrefs& aPrefs,
97 const char** aOutBadConstraint);
98 nsresult FocusOnSelectedSource();
99 nsresult Stop();
100 nsresult Deallocate();
102 void GetSettings(dom::MediaTrackSettings& aOutSettings) const;
104 dom::MediaSourceEnum GetMediaSource() const;
106 protected:
107 virtual ~MediaDevice() = default;
109 static uint32_t FitnessDistance(
110 nsString aN,
111 const dom::OwningStringOrStringSequenceOrConstrainDOMStringParameters&
112 aConstraint);
114 private:
115 static bool StringsContain(const dom::OwningStringOrStringSequence& aStrings,
116 nsString aN);
117 static uint32_t FitnessDistance(
118 nsString aN, const dom::ConstrainDOMStringParameters& aParams);
120 public:
121 const RefPtr<MediaEngineSource> mSource;
122 const RefPtr<AudioDeviceInfo> mSinkInfo;
123 const dom::MediaDeviceKind mKind;
124 const bool mScary;
125 const bool mIsFake;
126 const nsString mType;
127 const nsString mName;
128 const nsString mID;
129 const nsString mGroupID;
130 const nsString mRawID;
131 const nsString mRawGroupID;
132 const nsString mRawName;
135 typedef nsRefPtrHashtable<nsUint64HashKey, GetUserMediaWindowListener>
136 WindowTable;
137 typedef MozPromise<RefPtr<AudioDeviceInfo>, nsresult, true> SinkInfoPromise;
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>;
228 using BadConstraintsPromise =
229 MozPromise<const char*, RefPtr<MediaMgrError>, true>;
231 RefPtr<StreamPromise> GetUserMedia(
232 nsPIDOMWindowInner* aWindow,
233 const dom::MediaStreamConstraints& aConstraints,
234 dom::CallerType aCallerType);
236 RefPtr<DeviceSetPromise> EnumerateDevices(nsPIDOMWindowInner* aWindow,
237 dom::CallerType aCallerType);
239 nsresult EnumerateDevices(nsPIDOMWindowInner* aWindow,
240 dom::Promise& aPromise);
242 RefPtr<DevicePromise> SelectAudioOutput(
243 nsPIDOMWindowInner* aWindow, const dom::AudioOutputOptions& aOptions,
244 dom::CallerType aCallerType);
245 // Get the sink that corresponds to the given device id.
246 // It is resposible to check if an application is
247 // authorized to play audio through the requested device.
248 // The returned promise will be resolved with the device
249 // information if the device id matches one and operation is
250 // allowed. The default device is always allowed. Non default
251 // devices are allowed only in secure context. It is pending to
252 // implement an user authorization model. The promise will be
253 // rejected in the following cases:
254 // NS_ERROR_NOT_AVAILABLE: Device id does not exist.
255 // NS_ERROR_DOM_MEDIA_NOT_ALLOWED_ERR:
256 // The requested device exists but it is not allowed to be used.
257 // Currently, this happens only on non-default default devices
258 // and non https connections. TODO, authorization model to allow
259 // an application to play audio through the device (Bug 1493982).
260 // NS_ERROR_ABORT: General error.
261 RefPtr<SinkInfoPromise> GetSinkDevice(nsPIDOMWindowInner* aWindow,
262 const nsString& aDeviceId);
264 void OnNavigation(uint64_t aWindowID);
265 void OnCameraMute(bool aMute);
266 void OnMicrophoneMute(bool aMute);
267 bool IsActivelyCapturingOrHasAPermission(uint64_t aWindowId);
269 MediaEventSource<void>& DeviceListChangeEvent() {
270 return mDeviceListChangeEvent;
273 MediaEnginePrefs mPrefs;
275 private:
276 static nsresult GenerateUUID(nsAString& aResult);
277 static nsresult AnonymizeId(nsAString& aId, const nsACString& aOriginKey);
279 public: // TODO: make private once we upgrade to GCC 4.8+ on linux.
280 static void AnonymizeDevices(MediaDeviceSet& aDevices,
281 const nsACString& aOriginKey,
282 const uint64_t aWindowId);
285 * This function tries to guess the group id for a video device in aDevices
286 * based on the device name. If the name of only one audio device in aAudios
287 * contains the name of the video device, then, this video device will take
288 * the group id of the audio device. Since this is a guess we try to minimize
289 * the probability of false positive. If we fail to find a correlation we
290 * leave the video group id untouched. In that case the group id will be the
291 * video device name.
293 static void GuessVideoDeviceGroupIDs(MediaDeviceSet& aDevices,
294 const MediaDeviceSet& aAudios);
296 private:
297 enum class DeviceEnumerationType : uint8_t {
298 Normal, // Enumeration should not return loopback or fake devices
299 Fake, // Enumeration should return fake device(s)
300 Loopback /* Enumeration should return loopback device(s) (possibly in
301 addition to normal devices) */
304 RefPtr<MgrPromise> EnumerateRawDevices(
305 uint64_t aWindowId, dom::MediaSourceEnum aVideoInputType,
306 dom::MediaSourceEnum aAudioInputType, MediaSinkEnum aAudioOutputType,
307 DeviceEnumerationType aVideoInputEnumType,
308 DeviceEnumerationType aAudioInputEnumType, bool aForceNoPermRequest,
309 const RefPtr<MediaDeviceSetRefCnt>& aOutDevices);
311 RefPtr<MgrPromise> EnumerateDevicesImpl(
312 nsPIDOMWindowInner* aWindow, dom::MediaSourceEnum aVideoInputType,
313 dom::MediaSourceEnum aAudioInputType, MediaSinkEnum aAudioOutputType,
314 DeviceEnumerationType aVideoInputEnumType,
315 DeviceEnumerationType aAudioInputEnumType, bool aForceNoPermRequest,
316 const RefPtr<MediaDeviceSetRefCnt>& aOutDevices);
318 RefPtr<BadConstraintsPromise> SelectSettings(
319 const dom::MediaStreamConstraints& aConstraints,
320 dom::CallerType aCallerType,
321 const RefPtr<MediaDeviceSetRefCnt>& aSources);
323 void GetPref(nsIPrefBranch* aBranch, const char* aPref, const char* aData,
324 int32_t* aVal);
325 void GetPrefBool(nsIPrefBranch* aBranch, const char* aPref, const char* aData,
326 bool* aVal);
327 void GetPrefs(nsIPrefBranch* aBranch, const char* aData);
329 // Make private because we want only one instance of this class
330 explicit MediaManager(already_AddRefed<TaskQueue> aMediaThread);
332 ~MediaManager() = default;
333 void Shutdown();
335 void StopScreensharing(uint64_t aWindowID);
337 void RemoveMediaDevicesCallback(uint64_t aWindowID);
338 void DeviceListChanged();
340 // Returns the number of incomplete tasks associated with this window,
341 // including the newly added task.
342 size_t AddTaskAndGetCount(uint64_t aWindowID, const nsAString& aCallID,
343 RefPtr<GetUserMediaTask> aTask);
344 // Finds the task corresponding to aCallID and removes it from tracking.
345 RefPtr<GetUserMediaTask> TakeGetUserMediaTask(const nsAString& aCallID);
346 // Intended for use with "media.navigator.permission.disabled" to bypass the
347 // permission prompt and use the first appropriate device.
348 void NotifyAllowed(const nsString& aCallID, const MediaDeviceSet& aDevices);
350 MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf);
352 struct nsStringHasher {
353 using Key = nsString;
354 using Lookup = nsString;
356 static HashNumber hash(const Lookup& aLookup) {
357 return HashString(aLookup.get());
360 static bool match(const Key& aKey, const Lookup& aLookup) {
361 return aKey == aLookup;
365 // ONLY access from MainThread so we don't need to lock
366 WindowTable mActiveWindows;
367 nsRefPtrHashtable<nsStringHashKey, GetUserMediaTask> mActiveCallbacks;
368 nsClassHashtable<nsUint64HashKey, nsTArray<nsString>> mCallIds;
369 nsTArray<RefPtr<dom::GetUserMediaRequest>> mPendingGUMRequest;
370 using DeviceIdSet = HashSet<nsString, nsStringHasher, InfallibleAllocPolicy>;
371 DeviceIdSet mDeviceIDs;
372 RefPtr<MediaTimer> mDeviceChangeTimer;
373 bool mCamerasMuted = false;
374 bool mMicrophonesMuted = false;
376 // Always exists
377 const RefPtr<TaskQueue> mMediaThread;
378 nsCOMPtr<nsIAsyncShutdownBlocker> mShutdownBlocker;
380 // ONLY accessed from MediaManagerThread
381 RefPtr<MediaEngine> mBackend;
383 static StaticRefPtr<MediaManager> sSingleton;
384 static StaticMutex sSingletonMutex;
386 // Connect/Disconnect on media thread only
387 MediaEventListener mDeviceListChangeListener;
389 MediaEventProducer<void> mDeviceListChangeEvent;
391 public:
392 RefPtr<media::Parent<media::NonE10s>> mNonE10sParent;
395 } // namespace mozilla
397 #endif // MOZILLA_MEDIAMANAGER_H