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"
37 # include "transport/runnable_utils.h"
40 class AudioDeviceInfo
;
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;
62 class GetUserMediaTask
;
63 class GetUserMediaWindowListener
;
67 class MediaDevice
: public nsIMediaDevice
{
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
);
96 nsresult
Reconfigure(const dom::MediaTrackConstraints
& aConstraints
,
97 const MediaEnginePrefs
& aPrefs
,
98 const char** aOutBadConstraint
);
99 nsresult
FocusOnSelectedSource();
101 nsresult
Deallocate();
103 void GetSettings(dom::MediaTrackSettings
& aOutSettings
) const;
105 dom::MediaSourceEnum
GetMediaSource() const;
108 virtual ~MediaDevice() = default;
110 static uint32_t FitnessDistance(
112 const dom::OwningStringOrStringSequenceOrConstrainDOMStringParameters
&
116 static bool StringsContain(const dom::OwningStringOrStringSequence
& aStrings
,
118 static uint32_t FitnessDistance(
119 nsString aN
, const dom::ConstrainDOMStringParameters
& aParams
);
122 const RefPtr
<MediaEngineSource
> mSource
;
123 const RefPtr
<AudioDeviceInfo
> mSinkInfo
;
124 const dom::MediaDeviceKind mKind
;
127 const nsString mType
;
128 const nsString mName
;
130 const nsString mGroupID
;
131 const nsString mRawID
;
132 const nsString mRawGroupID
;
133 const nsString mRawName
;
136 typedef nsRefPtrHashtable
<nsUint64HashKey
, GetUserMediaWindowListener
>
139 class MediaManager final
: public nsIMediaManagerService
,
140 public nsIMemoryReporter
,
142 friend DeviceListener
;
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
162 template <typename MozPromiseType
, typename FunctionType
>
163 static RefPtr
<MozPromiseType
> Dispatch(const char* aName
,
164 FunctionType
&& aFunction
);
167 static bool IsInMediaThread();
170 static bool Exists() { return !!GetIfExists(); }
172 static nsresult
NotifyRecordingStatusChange(nsPIDOMWindowInner
* aWindow
);
174 NS_DECL_THREADSAFE_ISUPPORTS
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
;
212 static void CallOnError(GetUserMediaErrorCallback
& aCallback
,
213 dom::MediaStreamError
& aError
);
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
;
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
283 static void GuessVideoDeviceGroupIDs(MediaDeviceSet
& aDevices
,
284 const MediaDeviceSet
& aAudios
);
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
,
299 void GetPrefBool(nsIPrefBranch
* aBranch
, const char* aPref
, const char* aData
,
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;
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;
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
;
366 RefPtr
<media::Parent
<media::NonE10s
>> mNonE10sParent
;
369 } // namespace mozilla
371 #endif // MOZILLA_MEDIAMANAGER_H