2014-03-06 05:58:13 +04:00
|
|
|
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
|
|
|
/* vim: set ts=2 et sw=2 tw=80: */
|
2012-06-03 11:35:15 +04:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
|
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
#include "MediaManager.h"
|
|
|
|
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
#include "AllocationHandle.h"
|
2012-06-03 11:35:15 +04:00
|
|
|
#include "MediaStreamGraph.h"
|
2017-11-17 21:56:00 +03:00
|
|
|
#include "MediaTimer.h"
|
2014-08-27 09:03:50 +04:00
|
|
|
#include "mozilla/dom/MediaStreamTrack.h"
|
2018-07-16 12:29:12 +03:00
|
|
|
#include "mozilla/dom/MediaDeviceInfo.h"
|
2016-06-30 10:07:48 +03:00
|
|
|
#include "MediaStreamListener.h"
|
2016-10-14 20:06:27 +03:00
|
|
|
#include "nsArray.h"
|
2016-02-17 00:55:33 +03:00
|
|
|
#include "nsContentUtils.h"
|
2017-11-14 13:50:07 +03:00
|
|
|
#include "nsGlobalWindow.h"
|
2013-10-23 15:10:42 +04:00
|
|
|
#include "nsHashPropertyBag.h"
|
2012-06-03 11:35:15 +04:00
|
|
|
#include "nsIEventTarget.h"
|
2012-10-06 04:20:47 +04:00
|
|
|
#include "nsIUUIDGenerator.h"
|
2012-06-03 11:35:15 +04:00
|
|
|
#include "nsIScriptGlobalObject.h"
|
2014-02-25 15:50:42 +04:00
|
|
|
#include "nsIPermissionManager.h"
|
2013-02-28 00:36:06 +04:00
|
|
|
#include "nsIDocShell.h"
|
2013-05-18 00:17:53 +04:00
|
|
|
#include "nsIDocument.h"
|
2013-08-15 22:17:48 +04:00
|
|
|
#include "nsISupportsPrimitives.h"
|
|
|
|
#include "nsIInterfaceRequestorUtils.h"
|
2014-07-31 01:03:20 +04:00
|
|
|
#include "nsIIDNService.h"
|
2015-07-07 05:17:00 +03:00
|
|
|
#include "nsNetCID.h"
|
2014-07-11 00:14:57 +04:00
|
|
|
#include "nsNetUtil.h"
|
2015-03-03 17:51:05 +03:00
|
|
|
#include "nsICryptoHash.h"
|
|
|
|
#include "nsICryptoHMAC.h"
|
|
|
|
#include "nsIKeyModule.h"
|
2015-03-03 17:51:05 +03:00
|
|
|
#include "nsAppDirectoryServiceDefs.h"
|
|
|
|
#include "nsIInputStream.h"
|
|
|
|
#include "nsILineInputStream.h"
|
2018-02-23 12:05:42 +03:00
|
|
|
#include "nsIWeakReferenceUtils.h"
|
2017-11-14 13:50:07 +03:00
|
|
|
#include "nsPIDOMWindow.h"
|
2018-01-11 01:59:55 +03:00
|
|
|
#include "mozilla/EventStateManager.h"
|
2018-02-16 13:55:27 +03:00
|
|
|
#include "mozilla/MozPromise.h"
|
2018-07-17 22:37:48 +03:00
|
|
|
#include "mozilla/NullPrincipal.h"
|
2015-09-17 15:44:50 +03:00
|
|
|
#include "mozilla/Telemetry.h"
|
2014-04-18 22:00:16 +04:00
|
|
|
#include "mozilla/Types.h"
|
2014-05-01 14:51:00 +04:00
|
|
|
#include "mozilla/PeerIdentity.h"
|
2017-02-01 23:43:38 +03:00
|
|
|
#include "mozilla/dom/BindingDeclarations.h"
|
2013-11-26 10:22:16 +04:00
|
|
|
#include "mozilla/dom/ContentChild.h"
|
2017-10-04 12:24:35 +03:00
|
|
|
#include "mozilla/dom/Element.h"
|
2014-10-08 20:15:23 +04:00
|
|
|
#include "mozilla/dom/File.h"
|
2014-04-04 13:54:25 +04:00
|
|
|
#include "mozilla/dom/MediaStreamBinding.h"
|
2013-09-16 10:34:57 +04:00
|
|
|
#include "mozilla/dom/MediaStreamTrackBinding.h"
|
|
|
|
#include "mozilla/dom/GetUserMediaRequestBinding.h"
|
2016-02-17 00:55:33 +03:00
|
|
|
#include "mozilla/dom/Promise.h"
|
2016-08-11 20:04:49 +03:00
|
|
|
#include "mozilla/dom/MediaDevices.h"
|
2015-03-03 17:51:05 +03:00
|
|
|
#include "mozilla/Base64.h"
|
2015-03-29 20:43:43 +03:00
|
|
|
#include "mozilla/ipc/BackgroundChild.h"
|
2015-03-03 17:51:05 +03:00
|
|
|
#include "mozilla/media/MediaChild.h"
|
2015-11-19 06:40:41 +03:00
|
|
|
#include "mozilla/media/MediaTaskUtils.h"
|
2014-04-18 23:16:08 +04:00
|
|
|
#include "MediaTrackConstraints.h"
|
2015-03-03 17:51:05 +03:00
|
|
|
#include "VideoUtils.h"
|
2018-01-23 13:31:22 +03:00
|
|
|
#include "ThreadSafeRefcountingWithMainThreadDestruction.h"
|
2013-10-26 02:13:42 +04:00
|
|
|
#include "Latency.h"
|
2015-04-14 20:59:59 +03:00
|
|
|
#include "nsProxyRelease.h"
|
2015-10-07 18:17:42 +03:00
|
|
|
#include "nsVariant.h"
|
2013-10-26 02:13:42 +04:00
|
|
|
|
2016-02-17 22:23:39 +03:00
|
|
|
// For snprintf
|
2016-08-15 09:43:21 +03:00
|
|
|
#include "mozilla/Sprintf.h"
|
2012-10-06 04:20:47 +04:00
|
|
|
|
2012-06-03 11:35:15 +04:00
|
|
|
#include "nsJSUtils.h"
|
2012-06-11 03:44:50 +04:00
|
|
|
#include "nsGlobalWindow.h"
|
2015-02-23 19:50:48 +03:00
|
|
|
#include "nsIUUIDGenerator.h"
|
|
|
|
#include "nspr.h"
|
|
|
|
#include "nss.h"
|
|
|
|
#include "pk11pub.h"
|
2012-06-03 11:35:15 +04:00
|
|
|
|
2012-07-12 15:53:08 +04:00
|
|
|
/* Using WebRTC backend on Desktops (Mac, Windows, Linux), otherwise default */
|
2012-09-29 02:26:00 +04:00
|
|
|
#include "MediaEngineDefault.h"
|
2012-07-12 15:53:08 +04:00
|
|
|
#if defined(MOZ_WEBRTC)
|
|
|
|
#include "MediaEngineWebRTC.h"
|
2014-06-09 22:45:14 +04:00
|
|
|
#include "browser_logging/WebRtcLog.h"
|
2012-07-12 15:53:08 +04:00
|
|
|
#endif
|
|
|
|
|
2014-08-02 08:30:50 +04:00
|
|
|
#if defined (XP_WIN)
|
|
|
|
#include "mozilla/WindowsVersion.h"
|
2018-03-20 00:31:40 +03:00
|
|
|
#include <objbase.h>
|
2016-01-07 22:57:42 +03:00
|
|
|
#include <winsock2.h>
|
|
|
|
#include <iphlpapi.h>
|
|
|
|
#include <tchar.h>
|
2014-08-02 08:30:50 +04:00
|
|
|
#endif
|
|
|
|
|
2013-05-03 09:07:37 +04:00
|
|
|
// GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
|
|
|
|
// GetTickCount() and conflicts with MediaStream::GetCurrentTime.
|
|
|
|
#ifdef GetCurrentTime
|
|
|
|
#undef GetCurrentTime
|
|
|
|
#endif
|
|
|
|
|
2014-05-11 13:47:11 +04:00
|
|
|
// XXX Workaround for bug 986974 to maintain the existing broken semantics
|
|
|
|
template<>
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
struct nsIMediaDevice::COMTypeInfo<mozilla::MediaDevice, void> {
|
2014-06-02 16:08:24 +04:00
|
|
|
static const nsIID kIID;
|
2014-05-11 13:47:11 +04:00
|
|
|
};
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
const nsIID nsIMediaDevice::COMTypeInfo<mozilla::MediaDevice, void>::kIID = NS_IMEDIADEVICE_IID;
|
2014-05-11 13:47:11 +04:00
|
|
|
|
2018-07-28 07:40:26 +03:00
|
|
|
// A specialization of nsMainThreadPtrHolder for
|
|
|
|
// mozilla::dom::CallbackObjectHolder. See documentation for
|
|
|
|
// nsMainThreadPtrHolder in nsProxyRelease.h. This specialization lets us avoid
|
|
|
|
// wrapping the CallbackObjectHolder into a separate refcounted object.
|
|
|
|
template<class WebIDLCallbackT, class XPCOMCallbackT>
|
|
|
|
class nsMainThreadPtrHolder<mozilla::dom::CallbackObjectHolder<WebIDLCallbackT,
|
|
|
|
XPCOMCallbackT>> final
|
|
|
|
{
|
|
|
|
typedef mozilla::dom::CallbackObjectHolder<WebIDLCallbackT,
|
|
|
|
XPCOMCallbackT> Holder;
|
|
|
|
public:
|
|
|
|
nsMainThreadPtrHolder(const char* aName, Holder&& aHolder)
|
|
|
|
: mHolder(std::move(aHolder))
|
|
|
|
#ifndef RELEASE_OR_BETA
|
|
|
|
, mName(aName)
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
// We can be released on any thread.
|
|
|
|
~nsMainThreadPtrHolder()
|
|
|
|
{
|
|
|
|
if (NS_IsMainThread()) {
|
|
|
|
mHolder.Reset();
|
|
|
|
} else if (mHolder.GetISupports()) {
|
|
|
|
nsCOMPtr<nsIEventTarget> target = do_GetMainThread();
|
|
|
|
MOZ_ASSERT(target);
|
|
|
|
NS_ProxyRelease(
|
|
|
|
#ifdef RELEASE_OR_BETA
|
|
|
|
nullptr,
|
|
|
|
#else
|
|
|
|
mName,
|
|
|
|
#endif
|
|
|
|
target, mHolder.Forget());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
Holder* get()
|
|
|
|
{
|
|
|
|
// Nobody should be touching the raw pointer off-main-thread.
|
|
|
|
if (MOZ_UNLIKELY(!NS_IsMainThread())) {
|
|
|
|
NS_ERROR("Can't dereference nsMainThreadPtrHolder off main thread");
|
|
|
|
MOZ_CRASH();
|
|
|
|
}
|
|
|
|
return &mHolder;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator!() const
|
|
|
|
{
|
|
|
|
return !mHolder;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsMainThreadPtrHolder<Holder>)
|
|
|
|
|
|
|
|
private:
|
|
|
|
// Our holder.
|
|
|
|
Holder mHolder;
|
|
|
|
|
|
|
|
#ifndef RELEASE_OR_BETA
|
|
|
|
const char* mName = nullptr;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Copy constructor and operator= not implemented. Once constructed, the
|
|
|
|
// holder is immutable.
|
|
|
|
Holder& operator=(const nsMainThreadPtrHolder& aOther) = delete;
|
|
|
|
nsMainThreadPtrHolder(const nsMainThreadPtrHolder& aOther) = delete;
|
|
|
|
};
|
|
|
|
|
2015-11-18 23:42:16 +03:00
|
|
|
namespace {
|
|
|
|
already_AddRefed<nsIAsyncShutdownClient> GetShutdownPhase() {
|
2016-02-17 00:55:33 +03:00
|
|
|
nsCOMPtr<nsIAsyncShutdownService> svc = mozilla::services::GetAsyncShutdown();
|
2015-11-18 23:42:16 +03:00
|
|
|
MOZ_RELEASE_ASSERT(svc);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIAsyncShutdownClient> shutdownPhase;
|
|
|
|
nsresult rv = svc->GetProfileBeforeChange(getter_AddRefs(shutdownPhase));
|
|
|
|
if (!shutdownPhase) {
|
2016-06-02 01:05:53 +03:00
|
|
|
// We are probably in a content process. We need to do cleanup at
|
|
|
|
// XPCOM shutdown in leakchecking builds.
|
|
|
|
rv = svc->GetXpcomWillShutdown(getter_AddRefs(shutdownPhase));
|
2015-11-18 23:42:16 +03:00
|
|
|
}
|
|
|
|
MOZ_RELEASE_ASSERT(shutdownPhase);
|
|
|
|
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
|
|
|
|
return shutdownPhase.forget();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-03 11:35:15 +04:00
|
|
|
namespace mozilla {
|
|
|
|
|
2013-01-25 06:45:36 +04:00
|
|
|
#ifdef LOG
|
|
|
|
#undef LOG
|
|
|
|
#endif
|
|
|
|
|
2015-11-15 16:49:01 +03:00
|
|
|
LogModule*
|
2012-10-30 03:32:10 +04:00
|
|
|
GetMediaManagerLog()
|
|
|
|
{
|
2015-11-15 16:49:01 +03:00
|
|
|
static LazyLogModule sLog("MediaManager");
|
2012-10-30 03:32:10 +04:00
|
|
|
return sLog;
|
|
|
|
}
|
2015-06-04 01:25:57 +03:00
|
|
|
#define LOG(msg) MOZ_LOG(GetMediaManagerLog(), mozilla::LogLevel::Debug, msg)
|
2012-10-07 09:34:30 +04:00
|
|
|
|
2016-09-16 16:19:28 +03:00
|
|
|
using dom::BasicTrackSource;
|
2016-02-17 00:55:33 +03:00
|
|
|
using dom::ConstrainDOMStringParameters;
|
2015-05-18 16:52:26 +03:00
|
|
|
using dom::File;
|
2016-02-17 00:55:33 +03:00
|
|
|
using dom::GetUserMediaRequest;
|
|
|
|
using dom::MediaSourceEnum;
|
2015-02-21 01:06:26 +03:00
|
|
|
using dom::MediaStreamConstraints;
|
2014-10-27 22:42:56 +03:00
|
|
|
using dom::MediaStreamError;
|
2016-02-17 00:55:33 +03:00
|
|
|
using dom::MediaStreamTrack;
|
2016-04-06 15:46:56 +03:00
|
|
|
using dom::MediaStreamTrackSource;
|
2016-02-17 00:55:33 +03:00
|
|
|
using dom::MediaTrackConstraints;
|
|
|
|
using dom::MediaTrackConstraintSet;
|
2014-04-18 22:00:16 +04:00
|
|
|
using dom::OwningBooleanOrMediaTrackConstraints;
|
2016-02-17 00:55:33 +03:00
|
|
|
using dom::OwningStringOrStringSequence;
|
|
|
|
using dom::OwningStringOrStringSequenceOrConstrainDOMStringParameters;
|
|
|
|
using dom::Promise;
|
|
|
|
using dom::Sequence;
|
2015-06-18 18:46:36 +03:00
|
|
|
using media::NewRunnableFrom;
|
|
|
|
using media::NewTaskFrom;
|
2016-02-17 00:55:33 +03:00
|
|
|
using media::Pledge;
|
|
|
|
using media::Refcountable;
|
2013-09-16 10:34:57 +04:00
|
|
|
|
2017-11-02 18:27:33 +03:00
|
|
|
static Atomic<bool> sHasShutdown;
|
2015-05-29 21:28:03 +03:00
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
struct DeviceState {
|
|
|
|
DeviceState(const RefPtr<MediaDevice>& aDevice, bool aOffWhileDisabled)
|
|
|
|
: mOffWhileDisabled(aOffWhileDisabled)
|
|
|
|
, mDevice(aDevice)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(mDevice);
|
|
|
|
}
|
|
|
|
|
|
|
|
// true if we have stopped mDevice, this is a terminal state.
|
|
|
|
// MainThread only.
|
|
|
|
bool mStopped = false;
|
|
|
|
|
|
|
|
// true if mDevice is currently enabled, i.e., turned on and capturing.
|
|
|
|
// MainThread only.
|
2018-02-16 13:55:27 +03:00
|
|
|
bool mDeviceEnabled = false;
|
2017-11-17 21:56:00 +03:00
|
|
|
|
|
|
|
// true if the application has currently enabled mDevice.
|
|
|
|
// MainThread only.
|
2018-02-16 13:55:27 +03:00
|
|
|
bool mTrackEnabled = false;
|
2018-02-14 18:35:45 +03:00
|
|
|
|
2018-02-14 18:35:45 +03:00
|
|
|
// Time when the application last enabled mDevice.
|
|
|
|
// MainThread only.
|
|
|
|
TimeStamp mTrackEnabledTime;
|
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
// true if an operation to Start() or Stop() mDevice has been dispatched to
|
|
|
|
// the media thread and is not finished yet.
|
|
|
|
// MainThread only.
|
|
|
|
bool mOperationInProgress = false;
|
|
|
|
|
|
|
|
// true if we are allowed to turn off the underlying source while all tracks
|
|
|
|
// are disabled.
|
|
|
|
// MainThread only.
|
|
|
|
bool mOffWhileDisabled = false;
|
|
|
|
|
|
|
|
// Timer triggered by a MediaStreamTrackSource signaling that all tracks got
|
|
|
|
// disabled. When the timer fires we initiate Stop()ing mDevice.
|
|
|
|
// If set we allow dynamically stopping and starting mDevice.
|
|
|
|
// Any thread.
|
2018-02-16 13:55:27 +03:00
|
|
|
const RefPtr<MediaTimer> mDisableTimer = new MediaTimer();
|
2017-11-17 21:56:00 +03:00
|
|
|
|
|
|
|
// The underlying device we keep state for. Always non-null.
|
|
|
|
// Threadsafe access, but see method declarations for individual constraints.
|
|
|
|
const RefPtr<MediaDevice> mDevice;
|
|
|
|
};
|
|
|
|
|
2017-11-17 22:13:06 +03:00
|
|
|
/**
|
|
|
|
* This mimics the capture state from nsIMediaManagerService.
|
|
|
|
*/
|
|
|
|
enum class CaptureState : uint16_t {
|
|
|
|
Off = nsIMediaManagerService::STATE_NOCAPTURE,
|
|
|
|
Enabled = nsIMediaManagerService::STATE_CAPTURE_ENABLED,
|
|
|
|
Disabled = nsIMediaManagerService::STATE_CAPTURE_DISABLED,
|
|
|
|
};
|
|
|
|
|
|
|
|
static CaptureState
|
|
|
|
CombineCaptureState(CaptureState aFirst, CaptureState aSecond)
|
|
|
|
{
|
|
|
|
if (aFirst == CaptureState::Enabled || aSecond == CaptureState::Enabled) {
|
|
|
|
return CaptureState::Enabled;
|
|
|
|
}
|
|
|
|
if (aFirst == CaptureState::Disabled || aSecond == CaptureState::Disabled) {
|
|
|
|
return CaptureState::Disabled;
|
|
|
|
}
|
|
|
|
MOZ_ASSERT(aFirst == CaptureState::Off);
|
|
|
|
MOZ_ASSERT(aSecond == CaptureState::Off);
|
|
|
|
return CaptureState::Off;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint16_t
|
|
|
|
FromCaptureState(CaptureState aState)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(aState == CaptureState::Off ||
|
|
|
|
aState == CaptureState::Enabled ||
|
|
|
|
aState == CaptureState::Disabled);
|
|
|
|
return static_cast<uint16_t>(aState);
|
|
|
|
}
|
|
|
|
|
2018-07-28 07:40:26 +03:00
|
|
|
static void
|
|
|
|
CallOnError(MediaManager::GetUserMediaErrorCallback* aCallback,
|
|
|
|
MediaStreamError& aError)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(aCallback);
|
|
|
|
if (aCallback->HasWebIDLCallback()) {
|
|
|
|
aCallback->GetWebIDLCallback()->Call(aError);
|
|
|
|
} else {
|
|
|
|
aCallback->GetXPCOMCallback()->OnError(&aError);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
CallOnSuccess(MediaManager::GetUserMediaSuccessCallback* aCallback,
|
|
|
|
DOMMediaStream& aStream)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(aCallback);
|
|
|
|
if (aCallback->HasWebIDLCallback()) {
|
|
|
|
aCallback->GetWebIDLCallback()->Call(aStream);
|
|
|
|
} else {
|
|
|
|
aCallback->GetXPCOMCallback()->OnSuccess(&aStream);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-23 13:31:22 +03:00
|
|
|
/**
|
|
|
|
* SourceListener has threadsafe refcounting for use across the main, media and
|
|
|
|
* MSG threads. But it has a non-threadsafe SupportsWeakPtr for WeakPtr usage
|
|
|
|
* only from main thread, to ensure that garbage- and cycle-collected objects
|
|
|
|
* don't hold a reference to it during late shutdown.
|
|
|
|
*
|
|
|
|
* There's also a hard reference to the SourceListener through its
|
|
|
|
* SourceStreamListener and the MediaStreamGraph. MediaStreamGraph
|
|
|
|
* clears this on XPCOM_WILL_SHUTDOWN, before MediaManager enters shutdown.
|
|
|
|
*/
|
|
|
|
class SourceListener : public SupportsWeakPtr<SourceListener> {
|
2016-06-30 10:07:48 +03:00
|
|
|
public:
|
2018-02-23 12:05:42 +03:00
|
|
|
typedef MozPromise<bool /* aIgnored */, Maybe<nsString>, true> ApplyConstraintsPromise;
|
2018-02-16 13:55:27 +03:00
|
|
|
typedef MozPromise<bool /* aIgnored */, RefPtr<MediaMgrError>, true> InitPromise;
|
|
|
|
|
2018-01-23 13:31:22 +03:00
|
|
|
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(SourceListener)
|
2018-08-31 18:24:09 +03:00
|
|
|
NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION_AND_RECORDING(SourceListener,
|
|
|
|
recordreplay::Behavior::Preserve)
|
2018-01-23 13:31:22 +03:00
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
SourceListener();
|
2016-06-30 10:07:48 +03:00
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
/**
|
|
|
|
* Registers this source listener as belonging to the given window listener.
|
|
|
|
*/
|
|
|
|
void Register(GetUserMediaWindowListener* aListener);
|
2016-06-30 10:07:48 +03:00
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
/**
|
|
|
|
* Marks this listener as active and adds itself as a listener to aStream.
|
|
|
|
*/
|
|
|
|
void Activate(SourceMediaStream* aStream,
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
MediaDevice* aAudioDevice,
|
|
|
|
MediaDevice* aVideoDevice);
|
2017-04-26 12:13:40 +03:00
|
|
|
|
2018-02-16 13:55:27 +03:00
|
|
|
/**
|
|
|
|
* Posts a task to initialize and start all associated devices.
|
|
|
|
*/
|
|
|
|
RefPtr<InitPromise> InitializeAsync();
|
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
/**
|
|
|
|
* Stops all live tracks, finishes the associated MediaStream and cleans up.
|
|
|
|
*/
|
|
|
|
void Stop();
|
2016-06-30 10:07:48 +03:00
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
/**
|
|
|
|
* Removes this SourceListener from its associated MediaStream and marks it
|
|
|
|
* removed. Also removes the weak reference to the associated window listener.
|
|
|
|
*/
|
|
|
|
void Remove();
|
2016-06-30 10:07:48 +03:00
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
/**
|
|
|
|
* Posts a task to stop the device associated with aTrackID and notifies the
|
|
|
|
* associated window listener that a track was stopped.
|
|
|
|
* Should this track be the last live one to be stopped, we'll also clean up.
|
|
|
|
*/
|
|
|
|
void StopTrack(TrackID aTrackID);
|
2016-06-30 10:07:48 +03:00
|
|
|
|
2017-11-10 17:55:42 +03:00
|
|
|
/**
|
2017-11-17 21:56:00 +03:00
|
|
|
* Gets the main thread MediaTrackSettings from the MediaEngineSource
|
|
|
|
* associated with aTrackID.
|
2017-11-10 17:55:42 +03:00
|
|
|
*/
|
2017-11-17 21:56:00 +03:00
|
|
|
void GetSettingsFor(TrackID aTrackID, dom::MediaTrackSettings& aOutSettings) const;
|
2017-11-10 17:55:42 +03:00
|
|
|
|
|
|
|
/**
|
2017-11-17 21:56:00 +03:00
|
|
|
* Posts a task to set the enabled state of the device associated with
|
|
|
|
* aTrackID to aEnabled and notifies the associated window listener that a
|
|
|
|
* track's state has changed.
|
|
|
|
*
|
|
|
|
* Turning the hardware off while the device is disabled is supported for:
|
|
|
|
* - Camera (enabled by default, controlled by pref
|
|
|
|
* "media.getusermedia.camera.off_while_disabled.enabled")
|
|
|
|
* - Microphone (disabled by default, controlled by pref
|
|
|
|
* "media.getusermedia.microphone.off_while_disabled.enabled")
|
|
|
|
* Screen-, app-, or windowsharing is not supported at this time.
|
|
|
|
*
|
|
|
|
* The behavior is also different between disabling and enabling a device.
|
|
|
|
* While enabling is immediate, disabling only happens after a delay.
|
|
|
|
* This is now defaulting to 3 seconds but can be overriden by prefs:
|
|
|
|
* - "media.getusermedia.camera.off_while_disabled.delay_ms" and
|
|
|
|
* - "media.getusermedia.microphone.off_while_disabled.delay_ms".
|
|
|
|
*
|
|
|
|
* The delay is in place to prevent misuse by malicious sites. If a track is
|
|
|
|
* re-enabled before the delay has passed, the device will not be touched
|
|
|
|
* until another disable followed by the full delay happens.
|
2017-11-10 17:55:42 +03:00
|
|
|
*/
|
2017-11-17 21:56:00 +03:00
|
|
|
void SetEnabledFor(TrackID aTrackID, bool aEnabled);
|
2017-11-10 17:55:42 +03:00
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
/**
|
|
|
|
* Stops all screen/app/window/audioCapture sharing, but not camera or
|
|
|
|
* microphone.
|
|
|
|
*/
|
|
|
|
void StopSharing();
|
2017-04-26 12:13:40 +03:00
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
MediaStream* Stream() const
|
2017-05-03 14:14:18 +03:00
|
|
|
{
|
2017-04-26 12:13:40 +03:00
|
|
|
return mStream;
|
2017-05-03 14:14:18 +03:00
|
|
|
}
|
2017-04-26 12:13:40 +03:00
|
|
|
|
|
|
|
SourceMediaStream* GetSourceStream();
|
|
|
|
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
MediaDevice* GetAudioDevice() const
|
2017-05-03 14:14:18 +03:00
|
|
|
{
|
2017-11-17 21:56:00 +03:00
|
|
|
return mAudioDeviceState ? mAudioDeviceState->mDevice.get() : nullptr;
|
2017-05-03 14:14:18 +03:00
|
|
|
}
|
2017-04-26 12:13:40 +03:00
|
|
|
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
MediaDevice* GetVideoDevice() const
|
2017-04-27 01:21:54 +03:00
|
|
|
{
|
2017-11-17 21:56:00 +03:00
|
|
|
return mVideoDeviceState ? mVideoDeviceState->mDevice.get() : nullptr;
|
2017-04-27 01:21:54 +03:00
|
|
|
}
|
2016-06-30 10:07:48 +03:00
|
|
|
|
2018-01-23 13:31:22 +03:00
|
|
|
/**
|
|
|
|
* Called on MediaStreamGraph thread when MSG asks us for more data from
|
|
|
|
* input devices.
|
|
|
|
*/
|
2017-04-26 12:13:40 +03:00
|
|
|
void NotifyPull(MediaStreamGraph* aGraph,
|
2018-01-23 13:31:22 +03:00
|
|
|
StreamTime aDesiredTime);
|
2016-06-30 10:07:48 +03:00
|
|
|
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
/**
|
|
|
|
* Called on main thread after MediaStreamGraph notifies us that our
|
|
|
|
* MediaStream was marked finish in the graph.
|
|
|
|
*/
|
2017-04-26 12:13:40 +03:00
|
|
|
void NotifyFinished();
|
2016-06-30 10:07:48 +03:00
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
/**
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
* Called on main thread after MediaStreamGraph notifies us that we
|
|
|
|
* were removed as listener from the MediaStream in the graph.
|
2017-04-26 12:13:40 +03:00
|
|
|
*/
|
|
|
|
void NotifyRemoved();
|
2017-04-26 12:13:40 +03:00
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
bool Activated() const
|
2017-05-03 14:14:18 +03:00
|
|
|
{
|
2017-10-02 16:13:15 +03:00
|
|
|
return mStream;
|
2017-05-03 14:14:18 +03:00
|
|
|
}
|
2017-04-26 12:13:40 +03:00
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
bool Stopped() const
|
2017-05-03 14:14:18 +03:00
|
|
|
{
|
2017-04-26 12:13:40 +03:00
|
|
|
return mStopped;
|
2017-05-03 14:14:18 +03:00
|
|
|
}
|
2017-04-27 01:21:54 +03:00
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
bool CapturingVideo() const;
|
2017-04-26 12:13:40 +03:00
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
bool CapturingAudio() const;
|
2017-05-03 14:14:18 +03:00
|
|
|
|
2017-11-17 22:13:06 +03:00
|
|
|
CaptureState CapturingSource(MediaSourceEnum aSource) const;
|
2017-05-03 14:14:18 +03:00
|
|
|
|
2018-02-23 12:05:42 +03:00
|
|
|
RefPtr<ApplyConstraintsPromise>
|
2017-04-26 12:13:40 +03:00
|
|
|
ApplyConstraintsToTrack(nsPIDOMWindowInner* aWindow,
|
|
|
|
TrackID aTrackID,
|
|
|
|
const dom::MediaTrackConstraints& aConstraints,
|
|
|
|
dom::CallerType aCallerType);
|
|
|
|
|
|
|
|
PrincipalHandle GetPrincipalHandle() const;
|
|
|
|
|
|
|
|
private:
|
2018-01-23 13:31:22 +03:00
|
|
|
/**
|
|
|
|
* Wrapper class for the MediaStreamListener part of SourceListener.
|
|
|
|
*
|
|
|
|
* This is required since MediaStreamListener and SupportsWeakPtr
|
|
|
|
* both implement refcounting.
|
|
|
|
*/
|
|
|
|
class SourceStreamListener : public MediaStreamListener {
|
|
|
|
public:
|
|
|
|
explicit SourceStreamListener(SourceListener* aSourceListener)
|
|
|
|
: mSourceListener(aSourceListener)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void NotifyPull(MediaStreamGraph* aGraph,
|
|
|
|
StreamTime aDesiredTime) override
|
|
|
|
{
|
|
|
|
mSourceListener->NotifyPull(aGraph, aDesiredTime);
|
|
|
|
}
|
|
|
|
|
|
|
|
void NotifyEvent(MediaStreamGraph* aGraph,
|
|
|
|
MediaStreamGraphEvent aEvent) override
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIEventTarget> target;
|
|
|
|
|
|
|
|
switch (aEvent) {
|
|
|
|
case MediaStreamGraphEvent::EVENT_FINISHED:
|
|
|
|
target = GetMainThreadEventTarget();
|
|
|
|
if (NS_WARN_IF(!target)) {
|
|
|
|
NS_ASSERTION(false, "Mainthread not available; running on current thread");
|
|
|
|
// Ensure this really *was* MainThread (NS_GetCurrentThread won't work)
|
|
|
|
MOZ_RELEASE_ASSERT(mSourceListener->mMainThreadCheck == GetCurrentVirtualThread());
|
|
|
|
mSourceListener->NotifyFinished();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
target->Dispatch(NewRunnableMethod("SourceListener::NotifyFinished",
|
|
|
|
mSourceListener,
|
|
|
|
&SourceListener::NotifyFinished),
|
|
|
|
NS_DISPATCH_NORMAL);
|
|
|
|
break;
|
|
|
|
case MediaStreamGraphEvent::EVENT_REMOVED:
|
|
|
|
target = GetMainThreadEventTarget();
|
|
|
|
if (NS_WARN_IF(!target)) {
|
|
|
|
NS_ASSERTION(false, "Mainthread not available; running on current thread");
|
|
|
|
// Ensure this really *was* MainThread (NS_GetCurrentThread won't work)
|
|
|
|
MOZ_RELEASE_ASSERT(mSourceListener->mMainThreadCheck == GetCurrentVirtualThread());
|
|
|
|
mSourceListener->NotifyRemoved();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
target->Dispatch(NewRunnableMethod("SourceListener::NotifyRemoved",
|
|
|
|
mSourceListener,
|
|
|
|
&SourceListener::NotifyRemoved),
|
|
|
|
NS_DISPATCH_NORMAL);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
RefPtr<SourceListener> mSourceListener;
|
|
|
|
};
|
|
|
|
|
|
|
|
virtual ~SourceListener() = default;
|
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
/**
|
|
|
|
* Returns a pointer to the device state for aTrackID.
|
|
|
|
*
|
|
|
|
* This is intended for internal use where we need to figure out which state
|
|
|
|
* corresponds to aTrackID, not for availability checks. As such, we assert
|
|
|
|
* that the device does indeed exist.
|
|
|
|
*
|
|
|
|
* Since this is a raw pointer and the state lifetime depends on the
|
|
|
|
* SourceListener's lifetime, it's internal use only.
|
|
|
|
*/
|
|
|
|
DeviceState& GetDeviceStateFor(TrackID aTrackID) const;
|
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
// true after this listener has had all devices stopped. MainThread only.
|
2016-06-30 10:07:48 +03:00
|
|
|
bool mStopped;
|
|
|
|
|
|
|
|
// true after the stream this listener is listening to has finished in the
|
|
|
|
// MediaStreamGraph. MainThread only.
|
|
|
|
bool mFinished;
|
|
|
|
|
|
|
|
// true after this listener has been removed from its MediaStream.
|
|
|
|
// MainThread only.
|
|
|
|
bool mRemoved;
|
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
// never ever indirect off this; just for assertions
|
|
|
|
PRThread* mMainThreadCheck;
|
2017-04-26 12:13:40 +03:00
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
// Set in Register() on main thread, then read from any thread.
|
|
|
|
PrincipalHandle mPrincipalHandle;
|
|
|
|
|
|
|
|
// Weak pointer to the window listener that owns us. MainThread only.
|
|
|
|
GetUserMediaWindowListener* mWindowListener;
|
2016-09-21 16:17:23 +03:00
|
|
|
|
2016-06-30 10:07:48 +03:00
|
|
|
// Accessed from MediaStreamGraph thread, MediaManager thread, and MainThread
|
2017-11-17 21:56:00 +03:00
|
|
|
// No locking needed as they're set on Activate() and never assigned to again.
|
|
|
|
UniquePtr<DeviceState> mAudioDeviceState;
|
|
|
|
UniquePtr<DeviceState> mVideoDeviceState;
|
2016-06-30 10:07:48 +03:00
|
|
|
RefPtr<SourceMediaStream> mStream; // threadsafe refcnt
|
2018-01-23 13:31:22 +03:00
|
|
|
RefPtr<SourceStreamListener> mStreamListener; // threadsafe refcnt
|
2016-06-30 10:07:48 +03:00
|
|
|
};
|
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
/**
|
|
|
|
* This class represents a WindowID and handles all MediaStreamListeners
|
|
|
|
* (here subclassed as SourceListeners) used to feed GetUserMedia source
|
|
|
|
* streams. It proxies feedback from them into messages for browser chrome.
|
|
|
|
* The SourceListeners are used to Start() and Stop() the underlying
|
|
|
|
* MediaEngineSource when MediaStreams are assigned and deassigned in content.
|
|
|
|
*/
|
|
|
|
class GetUserMediaWindowListener
|
2015-09-17 05:44:14 +03:00
|
|
|
{
|
2017-04-26 12:13:40 +03:00
|
|
|
friend MediaManager;
|
2015-09-17 05:44:14 +03:00
|
|
|
public:
|
2017-04-26 12:13:40 +03:00
|
|
|
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GetUserMediaWindowListener)
|
|
|
|
|
|
|
|
// Create in an inactive state
|
|
|
|
GetUserMediaWindowListener(base::Thread *aThread,
|
2015-09-17 05:44:14 +03:00
|
|
|
uint64_t aWindowID,
|
2017-04-26 12:13:40 +03:00
|
|
|
const PrincipalHandle& aPrincipalHandle)
|
|
|
|
: mMediaThread(aThread)
|
2015-09-17 05:44:14 +03:00
|
|
|
, mWindowID(aWindowID)
|
2017-04-26 12:13:40 +03:00
|
|
|
, mPrincipalHandle(aPrincipalHandle)
|
|
|
|
, mChromeNotificationTaskPosted(false)
|
2015-09-17 05:44:14 +03:00
|
|
|
{}
|
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
/**
|
|
|
|
* Registers an inactive gUM source listener for this WindowListener.
|
|
|
|
*/
|
|
|
|
void Register(SourceListener* aListener)
|
2017-04-26 12:13:40 +03:00
|
|
|
{
|
2017-04-26 12:13:40 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2017-11-17 21:56:00 +03:00
|
|
|
MOZ_ASSERT(aListener);
|
|
|
|
MOZ_ASSERT(!aListener->Activated());
|
|
|
|
MOZ_ASSERT(!mInactiveListeners.Contains(aListener), "Already registered");
|
|
|
|
MOZ_ASSERT(!mActiveListeners.Contains(aListener), "Already activated");
|
2017-04-26 12:13:40 +03:00
|
|
|
|
|
|
|
aListener->Register(this);
|
|
|
|
mInactiveListeners.AppendElement(aListener);
|
2017-04-26 12:13:40 +03:00
|
|
|
}
|
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
/**
|
|
|
|
* Activates an already registered and inactive gUM source listener for this
|
|
|
|
* WindowListener.
|
|
|
|
*/
|
|
|
|
void Activate(SourceListener* aListener,
|
|
|
|
SourceMediaStream* aStream,
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
MediaDevice* aAudioDevice,
|
|
|
|
MediaDevice* aVideoDevice)
|
2017-04-26 12:13:40 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2017-11-17 21:56:00 +03:00
|
|
|
MOZ_ASSERT(aListener);
|
|
|
|
MOZ_ASSERT(!aListener->Activated());
|
|
|
|
MOZ_ASSERT(mInactiveListeners.Contains(aListener), "Must be registered to activate");
|
|
|
|
MOZ_ASSERT(!mActiveListeners.Contains(aListener), "Already activated");
|
2017-04-26 12:13:40 +03:00
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
mInactiveListeners.RemoveElement(aListener);
|
|
|
|
aListener->Activate(aStream, aAudioDevice, aVideoDevice);
|
|
|
|
mActiveListeners.AppendElement(do_AddRef(aListener));
|
2017-04-26 12:13:40 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Can be invoked from EITHER MainThread or MSG thread
|
|
|
|
void Stop()
|
2017-04-26 12:13:40 +03:00
|
|
|
{
|
2017-04-26 12:13:40 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread");
|
2017-04-26 12:13:40 +03:00
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
for (auto& source : mActiveListeners) {
|
|
|
|
source->Stop();
|
|
|
|
}
|
2017-04-26 12:13:40 +03:00
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
// Once all tracks have stopped, that will trigger the chrome notification
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Removes all SourceListeners from this window listener.
|
|
|
|
* Removes this window listener from the list of active windows, so callers
|
|
|
|
* need to make sure to hold a strong reference.
|
|
|
|
*/
|
|
|
|
void RemoveAll()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
|
|
|
// Shallow copy since SourceListener::Remove() will modify the arrays.
|
|
|
|
nsTArray<RefPtr<SourceListener>> listeners(mInactiveListeners.Length()
|
|
|
|
+ mActiveListeners.Length());
|
|
|
|
listeners.AppendElements(mInactiveListeners);
|
|
|
|
listeners.AppendElements(mActiveListeners);
|
|
|
|
for (auto& l : listeners) {
|
|
|
|
Remove(l);
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_ASSERT(mInactiveListeners.Length() == 0);
|
|
|
|
MOZ_ASSERT(mActiveListeners.Length() == 0);
|
|
|
|
|
2017-09-29 22:06:51 +03:00
|
|
|
MediaManager* mgr = MediaManager::GetIfExists();
|
2017-04-26 12:13:40 +03:00
|
|
|
if (!mgr) {
|
|
|
|
MOZ_ASSERT(false, "MediaManager should stay until everything is removed");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
GetUserMediaWindowListener* windowListener =
|
|
|
|
mgr->GetWindowListener(mWindowID);
|
2017-04-26 12:13:40 +03:00
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
if (!windowListener) {
|
|
|
|
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
2017-11-06 21:09:35 +03:00
|
|
|
auto* globalWindow = nsGlobalWindowInner::GetInnerWindowWithId(mWindowID);
|
2017-04-26 12:13:40 +03:00
|
|
|
if (globalWindow) {
|
|
|
|
RefPtr<GetUserMediaRequest> req =
|
|
|
|
new GetUserMediaRequest(globalWindow->AsInner(),
|
2017-09-22 07:35:46 +03:00
|
|
|
VoidString(), VoidString());
|
2017-04-26 12:13:40 +03:00
|
|
|
obs->NotifyObservers(req, "recording-device-stopped", nullptr);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_ASSERT(windowListener == this,
|
|
|
|
"There should only be one window listener per window ID");
|
|
|
|
|
|
|
|
LOG(("GUMWindowListener %p removing windowID %" PRIu64, this, mWindowID));
|
|
|
|
mgr->RemoveWindowID(mWindowID);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Remove(SourceListener* aListener)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
|
|
|
if (!mInactiveListeners.RemoveElement(aListener) &&
|
|
|
|
!mActiveListeners.RemoveElement(aListener)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_ASSERT(!mInactiveListeners.Contains(aListener),
|
|
|
|
"A SourceListener should only be once in one of "
|
|
|
|
"mInactiveListeners and mActiveListeners");
|
|
|
|
MOZ_ASSERT(!mActiveListeners.Contains(aListener),
|
|
|
|
"A SourceListener should only be once in one of "
|
|
|
|
"mInactiveListeners and mActiveListeners");
|
|
|
|
|
|
|
|
LOG(("GUMWindowListener %p removing SourceListener %p.", this, aListener));
|
|
|
|
aListener->Remove();
|
|
|
|
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
if (MediaDevice* removedDevice = aListener->GetVideoDevice()) {
|
2017-04-26 12:13:40 +03:00
|
|
|
bool revokeVideoPermission = true;
|
|
|
|
nsString removedRawId;
|
|
|
|
nsString removedSourceType;
|
|
|
|
removedDevice->GetRawId(removedRawId);
|
|
|
|
removedDevice->GetMediaSource(removedSourceType);
|
|
|
|
for (const auto& l : mActiveListeners) {
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
if (MediaDevice* device = l->GetVideoDevice()) {
|
2017-04-26 12:13:40 +03:00
|
|
|
nsString rawId;
|
|
|
|
device->GetRawId(rawId);
|
|
|
|
if (removedRawId.Equals(rawId)) {
|
|
|
|
revokeVideoPermission = false;
|
|
|
|
break;
|
|
|
|
}
|
2017-05-03 14:14:18 +03:00
|
|
|
}
|
2017-04-26 12:13:40 +03:00
|
|
|
}
|
2017-04-26 12:13:40 +03:00
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
if (revokeVideoPermission) {
|
|
|
|
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
2017-11-06 21:09:35 +03:00
|
|
|
auto* globalWindow = nsGlobalWindowInner::GetInnerWindowWithId(mWindowID);
|
2017-04-26 12:13:40 +03:00
|
|
|
nsPIDOMWindowInner* window = globalWindow ? globalWindow->AsInner()
|
|
|
|
: nullptr;
|
|
|
|
RefPtr<GetUserMediaRequest> req =
|
|
|
|
new GetUserMediaRequest(window, removedRawId, removedSourceType);
|
|
|
|
obs->NotifyObservers(req, "recording-device-stopped", nullptr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
if (MediaDevice* removedDevice = aListener->GetAudioDevice()) {
|
2017-04-26 12:13:40 +03:00
|
|
|
bool revokeAudioPermission = true;
|
|
|
|
nsString removedRawId;
|
|
|
|
nsString removedSourceType;
|
|
|
|
removedDevice->GetRawId(removedRawId);
|
|
|
|
removedDevice->GetMediaSource(removedSourceType);
|
|
|
|
for (const auto& l : mActiveListeners) {
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
if (MediaDevice* device = l->GetAudioDevice()) {
|
2017-04-26 12:13:40 +03:00
|
|
|
nsString rawId;
|
|
|
|
device->GetRawId(rawId);
|
|
|
|
if (removedRawId.Equals(rawId)) {
|
|
|
|
revokeAudioPermission = false;
|
|
|
|
break;
|
2017-05-03 14:14:18 +03:00
|
|
|
}
|
|
|
|
}
|
2017-04-26 12:13:40 +03:00
|
|
|
}
|
2017-04-26 12:13:40 +03:00
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
if (revokeAudioPermission) {
|
|
|
|
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
2017-11-06 21:09:35 +03:00
|
|
|
auto* globalWindow = nsGlobalWindowInner::GetInnerWindowWithId(mWindowID);
|
2017-04-26 12:13:40 +03:00
|
|
|
nsPIDOMWindowInner* window = globalWindow ? globalWindow->AsInner()
|
|
|
|
: nullptr;
|
|
|
|
RefPtr<GetUserMediaRequest> req =
|
|
|
|
new GetUserMediaRequest(window, removedRawId, removedSourceType);
|
|
|
|
obs->NotifyObservers(req, "recording-device-stopped", nullptr);
|
|
|
|
}
|
2017-04-26 12:13:40 +03:00
|
|
|
}
|
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
if (mInactiveListeners.Length() == 0 &&
|
|
|
|
mActiveListeners.Length() == 0) {
|
|
|
|
LOG(("GUMWindowListener %p Removed the last SourceListener. "
|
|
|
|
"Cleaning up.", this));
|
|
|
|
RemoveAll();
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2017-04-26 12:13:40 +03:00
|
|
|
}
|
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
void StopSharing();
|
|
|
|
|
2017-07-27 11:51:24 +03:00
|
|
|
void StopRawID(const nsString& removedDeviceID);
|
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
/**
|
2017-11-14 13:50:07 +03:00
|
|
|
* Called by one of our SourceListeners when one of its tracks has changed so
|
|
|
|
* that chrome state is affected.
|
2017-04-26 12:13:40 +03:00
|
|
|
* Schedules an event for the next stable state to update chrome.
|
|
|
|
*/
|
2017-11-14 13:50:07 +03:00
|
|
|
void ChromeAffectingStateChanged();
|
2017-04-26 12:13:40 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Called in stable state to send a notification to update chrome.
|
|
|
|
*/
|
2017-11-14 13:50:07 +03:00
|
|
|
void NotifyChrome();
|
2017-04-26 12:13:40 +03:00
|
|
|
|
|
|
|
bool CapturingVideo() const
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
for (auto& l : mActiveListeners) {
|
|
|
|
if (l->CapturingVideo()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2017-11-17 22:13:06 +03:00
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
bool CapturingAudio() const
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
for (auto& l : mActiveListeners) {
|
|
|
|
if (l->CapturingAudio()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2017-11-17 22:13:06 +03:00
|
|
|
|
|
|
|
CaptureState CapturingSource(MediaSourceEnum aSource) const
|
2017-04-26 12:13:40 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2017-11-17 22:13:06 +03:00
|
|
|
CaptureState result = CaptureState::Off;
|
2017-04-26 12:13:40 +03:00
|
|
|
for (auto& l : mActiveListeners) {
|
2017-11-17 22:13:06 +03:00
|
|
|
result = CombineCaptureState(result, l->CapturingSource(aSource));
|
2017-04-26 12:13:40 +03:00
|
|
|
}
|
2017-11-17 22:13:06 +03:00
|
|
|
return result;
|
2017-04-26 12:13:40 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t WindowID() const
|
|
|
|
{
|
|
|
|
return mWindowID;
|
|
|
|
}
|
|
|
|
|
|
|
|
PrincipalHandle GetPrincipalHandle() const { return mPrincipalHandle; }
|
|
|
|
|
2015-09-17 05:44:14 +03:00
|
|
|
private:
|
2017-04-26 12:13:40 +03:00
|
|
|
~GetUserMediaWindowListener()
|
|
|
|
{
|
2017-11-06 17:27:36 +03:00
|
|
|
MOZ_ASSERT(mInactiveListeners.Length() == 0,
|
|
|
|
"Inactive listeners should already be removed");
|
|
|
|
MOZ_ASSERT(mActiveListeners.Length() == 0,
|
|
|
|
"Active listeners should already be removed");
|
2017-04-26 12:13:40 +03:00
|
|
|
Unused << mMediaThread;
|
|
|
|
// It's OK to release mStream on any thread; they have thread-safe
|
|
|
|
// refcounts.
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set at construction
|
|
|
|
base::Thread* mMediaThread;
|
|
|
|
|
2015-09-17 05:44:14 +03:00
|
|
|
uint64_t mWindowID;
|
2017-04-26 12:13:40 +03:00
|
|
|
const PrincipalHandle mPrincipalHandle;
|
|
|
|
|
|
|
|
// true if we have scheduled a task to notify chrome in the next stable state.
|
|
|
|
// The task will reset this to false. MainThread only.
|
|
|
|
bool mChromeNotificationTaskPosted;
|
|
|
|
|
|
|
|
nsTArray<RefPtr<SourceListener>> mInactiveListeners;
|
|
|
|
nsTArray<RefPtr<SourceListener>> mActiveListeners;
|
2015-09-17 05:44:14 +03:00
|
|
|
};
|
|
|
|
|
2015-02-23 19:50:48 +03:00
|
|
|
/**
|
2017-11-15 20:40:35 +03:00
|
|
|
* Send an error back to content. Do this only on the main thread.
|
2015-02-23 19:50:48 +03:00
|
|
|
*/
|
2016-04-26 03:23:21 +03:00
|
|
|
class ErrorCallbackRunnable : public Runnable
|
2015-03-29 08:42:32 +03:00
|
|
|
{
|
2015-02-23 19:50:48 +03:00
|
|
|
public:
|
2018-07-28 07:40:26 +03:00
|
|
|
ErrorCallbackRunnable(const nsMainThreadPtrHandle<MediaManager::GetUserMediaErrorCallback>& aOnFailure,
|
2017-06-12 22:34:10 +03:00
|
|
|
MediaMgrError& aError,
|
|
|
|
uint64_t aWindowID)
|
|
|
|
: Runnable("ErrorCallbackRunnable")
|
2017-11-15 20:40:35 +03:00
|
|
|
, mOnFailure(aOnFailure)
|
2017-06-12 22:34:10 +03:00
|
|
|
, mError(&aError)
|
2015-02-23 19:50:48 +03:00
|
|
|
, mWindowID(aWindowID)
|
|
|
|
, mManager(MediaManager::GetInstance())
|
|
|
|
{
|
|
|
|
}
|
2015-03-28 23:24:25 +03:00
|
|
|
|
2016-08-08 05:18:10 +03:00
|
|
|
NS_IMETHOD
|
|
|
|
Run() override
|
2015-02-23 19:50:48 +03:00
|
|
|
{
|
2015-09-30 09:08:22 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2015-03-29 05:57:17 +03:00
|
|
|
|
2015-02-23 19:50:48 +03:00
|
|
|
// Only run if the window is still active.
|
|
|
|
if (!(mManager->IsWindowStillActive(mWindowID))) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
// This is safe since we're on main-thread, and the windowlist can only
|
|
|
|
// be invalidated from the main-thread (see OnNavigation)
|
2017-11-06 21:09:35 +03:00
|
|
|
if (auto* window = nsGlobalWindowInner::GetInnerWindowWithId(mWindowID)) {
|
2016-01-30 20:05:36 +03:00
|
|
|
RefPtr<MediaStreamError> error =
|
|
|
|
new MediaStreamError(window->AsInner(), *mError);
|
2018-07-28 07:40:26 +03:00
|
|
|
CallOnError(mOnFailure, *error);
|
2015-02-23 19:50:48 +03:00
|
|
|
}
|
2013-12-06 01:30:50 +04:00
|
|
|
return NS_OK;
|
2012-06-03 11:35:15 +04:00
|
|
|
}
|
2015-02-23 19:50:48 +03:00
|
|
|
private:
|
2017-11-15 20:40:35 +03:00
|
|
|
~ErrorCallbackRunnable() override = default;
|
2015-02-23 19:50:48 +03:00
|
|
|
|
2018-07-28 07:40:26 +03:00
|
|
|
nsMainThreadPtrHandle<MediaManager::GetUserMediaErrorCallback> mOnFailure;
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<MediaMgrError> mError;
|
2015-02-23 19:50:48 +03:00
|
|
|
uint64_t mWindowID;
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<MediaManager> mManager; // get ref to this when creating the runnable
|
2015-02-23 19:50:48 +03:00
|
|
|
};
|
2012-06-03 11:35:15 +04:00
|
|
|
|
2012-09-20 23:54:00 +04:00
|
|
|
/**
|
|
|
|
* nsIMediaDevice implementation.
|
|
|
|
*/
|
2014-04-27 11:06:00 +04:00
|
|
|
NS_IMPL_ISUPPORTS(MediaDevice, nsIMediaDevice)
|
2012-09-20 23:54:00 +04:00
|
|
|
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
MediaDevice::MediaDevice(MediaEngineSource* aSource,
|
|
|
|
const nsString& aName,
|
|
|
|
const nsString& aID,
|
|
|
|
const nsString& aRawID)
|
|
|
|
: mSource(aSource)
|
2018-07-16 12:29:12 +03:00
|
|
|
, mKind((mSource && MediaEngineSource::IsVideo(mSource->GetMediaSource())) ?
|
|
|
|
dom::MediaDeviceKind::Videoinput : dom::MediaDeviceKind::Audioinput)
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
, mScary(mSource->GetScary())
|
2018-07-16 12:29:12 +03:00
|
|
|
, mType(NS_ConvertUTF8toUTF16(dom::MediaDeviceKindValues::strings[uint32_t(mKind)].value))
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
, mName(aName)
|
|
|
|
, mID(aID)
|
|
|
|
, mRawID(aRawID)
|
2015-07-03 01:01:52 +03:00
|
|
|
{
|
2018-07-16 12:29:12 +03:00
|
|
|
MOZ_ASSERT(mSource);
|
|
|
|
}
|
|
|
|
|
|
|
|
MediaDevice::MediaDevice(const nsString& aName,
|
|
|
|
const dom::MediaDeviceKind aKind,
|
|
|
|
const nsString& aID,
|
|
|
|
const nsString& aRawID)
|
|
|
|
: mSource(nullptr)
|
|
|
|
, mKind(aKind)
|
|
|
|
, mScary(false)
|
|
|
|
, mType(NS_ConvertUTF8toUTF16(dom::MediaDeviceKindValues::strings[uint32_t(mKind)].value))
|
|
|
|
, mName(aName)
|
|
|
|
, mID(aID)
|
|
|
|
, mRawID(aRawID)
|
|
|
|
{
|
|
|
|
// For now this ctor is used only for Audiooutput.
|
|
|
|
// It could be used for Audioinput and Videoinput
|
|
|
|
// when we do not instantiate a MediaEngineSource
|
|
|
|
// during EnumerateDevices.
|
|
|
|
MOZ_ASSERT(mKind == dom::MediaDeviceKind::Audiooutput);
|
|
|
|
}
|
|
|
|
|
|
|
|
MediaDevice::MediaDevice(const MediaDevice* aOther,
|
|
|
|
const nsString& aID,
|
|
|
|
const nsString& aRawID)
|
|
|
|
: mSource(aOther->mSource)
|
|
|
|
, mKind(aOther->mKind)
|
|
|
|
, mScary(aOther->mScary)
|
|
|
|
, mType(aOther->mType)
|
|
|
|
, mName(aOther->mName)
|
|
|
|
, mID(aID)
|
|
|
|
, mRawID(aRawID)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(aOther);
|
2014-04-18 23:15:10 +04:00
|
|
|
}
|
2013-09-16 10:34:57 +04:00
|
|
|
|
2014-09-24 19:17:33 +04:00
|
|
|
/**
|
|
|
|
* Helper functions that implement the constraints algorithm from
|
|
|
|
* http://dev.w3.org/2011/webrtc/editor/getusermedia.html#methods-5
|
|
|
|
*/
|
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
/* static */ bool
|
2015-07-03 01:01:52 +03:00
|
|
|
MediaDevice::StringsContain(const OwningStringOrStringSequence& aStrings,
|
|
|
|
nsString aN)
|
|
|
|
{
|
|
|
|
return aStrings.IsString() ? aStrings.GetAsString() == aN
|
|
|
|
: aStrings.GetAsStringSequence().Contains(aN);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ uint32_t
|
|
|
|
MediaDevice::FitnessDistance(nsString aN,
|
|
|
|
const ConstrainDOMStringParameters& aParams)
|
|
|
|
{
|
|
|
|
if (aParams.mExact.WasPassed() && !StringsContain(aParams.mExact.Value(), aN)) {
|
|
|
|
return UINT32_MAX;
|
|
|
|
}
|
|
|
|
if (aParams.mIdeal.WasPassed() && !StringsContain(aParams.mIdeal.Value(), aN)) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Binding code doesn't templatize well...
|
|
|
|
|
|
|
|
/* static */ uint32_t
|
|
|
|
MediaDevice::FitnessDistance(nsString aN,
|
|
|
|
const OwningStringOrStringSequenceOrConstrainDOMStringParameters& aConstraint)
|
|
|
|
{
|
|
|
|
if (aConstraint.IsString()) {
|
|
|
|
ConstrainDOMStringParameters params;
|
|
|
|
params.mIdeal.Construct();
|
|
|
|
params.mIdeal.Value().SetAsString() = aConstraint.GetAsString();
|
|
|
|
return FitnessDistance(aN, params);
|
|
|
|
} else if (aConstraint.IsStringSequence()) {
|
|
|
|
ConstrainDOMStringParameters params;
|
|
|
|
params.mIdeal.Construct();
|
|
|
|
params.mIdeal.Value().SetAsStringSequence() = aConstraint.GetAsStringSequence();
|
|
|
|
return FitnessDistance(aN, params);
|
|
|
|
} else {
|
|
|
|
return FitnessDistance(aN, aConstraint.GetAsConstrainDOMStringParameters());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-21 01:06:26 +03:00
|
|
|
uint32_t
|
2015-07-03 01:01:52 +03:00
|
|
|
MediaDevice::GetBestFitnessDistance(
|
2016-08-19 23:39:54 +03:00
|
|
|
const nsTArray<const NormalizedConstraintSet*>& aConstraintSets,
|
|
|
|
bool aIsChrome)
|
2014-09-24 19:17:33 +04:00
|
|
|
{
|
2017-11-17 21:56:00 +03:00
|
|
|
MOZ_ASSERT(MediaManager::IsInMediaThread());
|
2018-07-16 12:29:12 +03:00
|
|
|
MOZ_ASSERT(mSource);
|
2017-11-17 21:56:00 +03:00
|
|
|
|
2015-07-03 01:01:52 +03:00
|
|
|
nsString mediaSource;
|
|
|
|
GetMediaSource(mediaSource);
|
|
|
|
|
|
|
|
// This code is reused for audio, where the mediaSource constraint does
|
|
|
|
// not currently have a function, but because it defaults to "camera" in
|
|
|
|
// webidl, we ignore it for audio here.
|
|
|
|
if (!mediaSource.EqualsASCII("microphone")) {
|
|
|
|
for (const auto& constraint : aConstraintSets) {
|
2016-06-17 22:20:10 +03:00
|
|
|
if (constraint->mMediaSource.mIdeal.find(mediaSource) ==
|
|
|
|
constraint->mMediaSource.mIdeal.end()) {
|
2015-07-03 01:01:52 +03:00
|
|
|
return UINT32_MAX;
|
|
|
|
}
|
2014-09-24 19:17:33 +04:00
|
|
|
}
|
|
|
|
}
|
2014-09-25 03:00:02 +04:00
|
|
|
// Forward request to underlying object to interrogate per-mode capabilities.
|
2015-07-03 01:01:52 +03:00
|
|
|
// Pass in device's origin-specific id for deviceId constraint comparison.
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
const nsString& id = aIsChrome ? mRawID : mID;
|
2015-07-03 01:01:52 +03:00
|
|
|
return mSource->GetBestFitnessDistance(aConstraintSets, id);
|
2014-09-24 19:17:33 +04:00
|
|
|
}
|
|
|
|
|
2012-09-20 23:54:00 +04:00
|
|
|
NS_IMETHODIMP
|
|
|
|
MediaDevice::GetName(nsAString& aName)
|
|
|
|
{
|
2017-11-17 21:56:00 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2012-09-20 23:54:00 +04:00
|
|
|
aName.Assign(mName);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
MediaDevice::GetType(nsAString& aType)
|
|
|
|
{
|
2017-11-17 21:56:00 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
aType.Assign(mType);
|
2012-09-20 23:54:00 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-12-17 17:28:24 +04:00
|
|
|
NS_IMETHODIMP
|
|
|
|
MediaDevice::GetId(nsAString& aID)
|
|
|
|
{
|
2017-11-17 21:56:00 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2012-12-17 17:28:24 +04:00
|
|
|
aID.Assign(mID);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2016-08-18 07:01:00 +03:00
|
|
|
NS_IMETHODIMP
|
|
|
|
MediaDevice::GetRawId(nsAString& aID)
|
|
|
|
{
|
2017-11-17 21:56:00 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-08-18 07:01:00 +03:00
|
|
|
aID.Assign(mRawID);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2016-09-29 22:37:25 +03:00
|
|
|
NS_IMETHODIMP
|
|
|
|
MediaDevice::GetScary(bool* aScary)
|
|
|
|
{
|
|
|
|
*aScary = mScary;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2015-02-23 19:50:48 +03:00
|
|
|
void
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
MediaDevice::GetSettings(dom::MediaTrackSettings& aOutSettings) const
|
2015-02-23 19:50:48 +03:00
|
|
|
{
|
2017-11-17 21:56:00 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2018-07-16 12:29:12 +03:00
|
|
|
MOZ_ASSERT(mSource);
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
mSource->GetSettings(aOutSettings);
|
2016-08-18 07:01:00 +03:00
|
|
|
}
|
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
// Threadsafe since mSource is const.
|
2014-07-08 10:01:27 +04:00
|
|
|
NS_IMETHODIMP
|
|
|
|
MediaDevice::GetMediaSource(nsAString& aMediaSource)
|
|
|
|
{
|
2017-11-17 21:56:00 +03:00
|
|
|
aMediaSource.Assign(NS_ConvertUTF8toUTF16(
|
|
|
|
dom::MediaSourceEnumValues::strings[uint32_t(GetMediaSource())].value));
|
2014-07-08 10:01:27 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
nsresult
|
|
|
|
MediaDevice::Allocate(const dom::MediaTrackConstraints &aConstraints,
|
|
|
|
const MediaEnginePrefs &aPrefs,
|
|
|
|
const ipc::PrincipalInfo& aPrincipalInfo,
|
|
|
|
const char** aOutBadConstraint)
|
2014-04-18 23:15:10 +04:00
|
|
|
{
|
2017-11-17 21:56:00 +03:00
|
|
|
MOZ_ASSERT(MediaManager::IsInMediaThread());
|
2018-07-16 12:29:12 +03:00
|
|
|
MOZ_ASSERT(mSource);
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
return mSource->Allocate(aConstraints,
|
|
|
|
aPrefs,
|
|
|
|
mID,
|
|
|
|
aPrincipalInfo,
|
|
|
|
getter_AddRefs(mAllocationHandle),
|
|
|
|
aOutBadConstraint);
|
2014-04-18 23:15:10 +04:00
|
|
|
}
|
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
nsresult
|
|
|
|
MediaDevice::SetTrack(const RefPtr<SourceMediaStream>& aStream,
|
|
|
|
TrackID aTrackID,
|
|
|
|
const PrincipalHandle& aPrincipalHandle)
|
2017-12-18 18:19:33 +03:00
|
|
|
{
|
2017-11-17 21:56:00 +03:00
|
|
|
MOZ_ASSERT(MediaManager::IsInMediaThread());
|
2018-07-16 12:29:12 +03:00
|
|
|
MOZ_ASSERT(mSource);
|
2017-12-18 18:19:33 +03:00
|
|
|
return mSource->SetTrack(mAllocationHandle, aStream, aTrackID, aPrincipalHandle);
|
|
|
|
}
|
2012-09-20 23:54:00 +04:00
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
nsresult
|
|
|
|
MediaDevice::Start()
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
{
|
2017-11-17 21:56:00 +03:00
|
|
|
MOZ_ASSERT(MediaManager::IsInMediaThread());
|
2018-07-16 12:29:12 +03:00
|
|
|
MOZ_ASSERT(mSource);
|
2017-12-18 18:19:33 +03:00
|
|
|
return mSource->Start(mAllocationHandle);
|
2015-07-03 01:01:52 +03:00
|
|
|
}
|
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
nsresult
|
|
|
|
MediaDevice::Reconfigure(const dom::MediaTrackConstraints &aConstraints,
|
|
|
|
const MediaEnginePrefs &aPrefs,
|
|
|
|
const char** aOutBadConstraint)
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
{
|
2017-11-17 21:56:00 +03:00
|
|
|
MOZ_ASSERT(MediaManager::IsInMediaThread());
|
2018-07-16 12:29:12 +03:00
|
|
|
MOZ_ASSERT(mSource);
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
return mSource->Reconfigure(mAllocationHandle,
|
|
|
|
aConstraints,
|
|
|
|
aPrefs,
|
|
|
|
mID,
|
2016-06-16 02:25:07 +03:00
|
|
|
aOutBadConstraint);
|
2015-09-21 01:45:57 +03:00
|
|
|
}
|
|
|
|
|
2018-05-08 22:55:36 +03:00
|
|
|
nsresult
|
|
|
|
MediaDevice::FocusOnSelectedSource()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(MediaManager::IsInMediaThread());
|
2018-07-16 12:29:12 +03:00
|
|
|
MOZ_ASSERT(mSource);
|
2018-05-08 22:55:36 +03:00
|
|
|
return mSource->FocusOnSelectedSource(mAllocationHandle);
|
|
|
|
}
|
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
nsresult
|
|
|
|
MediaDevice::Stop()
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
{
|
2017-11-17 21:56:00 +03:00
|
|
|
MOZ_ASSERT(MediaManager::IsInMediaThread());
|
2018-07-16 12:29:12 +03:00
|
|
|
MOZ_ASSERT(mSource);
|
2017-12-18 18:19:33 +03:00
|
|
|
return mSource->Stop(mAllocationHandle);
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
}
|
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
nsresult
|
|
|
|
MediaDevice::Deallocate()
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
{
|
2017-11-17 21:56:00 +03:00
|
|
|
MOZ_ASSERT(MediaManager::IsInMediaThread());
|
2018-07-16 12:29:12 +03:00
|
|
|
MOZ_ASSERT(mSource);
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
return mSource->Deallocate(mAllocationHandle);
|
|
|
|
}
|
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
void
|
|
|
|
MediaDevice::Pull(const RefPtr<SourceMediaStream>& aStream,
|
|
|
|
TrackID aTrackID,
|
|
|
|
StreamTime aDesiredTime,
|
|
|
|
const PrincipalHandle& aPrincipal)
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
{
|
2017-11-17 21:56:00 +03:00
|
|
|
// This is on the graph thread, but mAllocationHandle is safe since we never
|
|
|
|
// change it after it's been set, which is guaranteed to happen before
|
|
|
|
// registering the listener for pulls.
|
2018-07-16 12:29:12 +03:00
|
|
|
MOZ_ASSERT(mSource);
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
mSource->Pull(mAllocationHandle, aStream, aTrackID, aDesiredTime, aPrincipal);
|
|
|
|
}
|
|
|
|
|
|
|
|
dom::MediaSourceEnum
|
|
|
|
MediaDevice::GetMediaSource() const
|
|
|
|
{
|
2017-11-17 21:56:00 +03:00
|
|
|
// Threadsafe because mSource is const. GetMediaSource() might have other
|
|
|
|
// requirements.
|
2018-07-16 12:29:12 +03:00
|
|
|
MOZ_ASSERT(mSource);
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
return mSource->GetMediaSource();
|
2015-09-21 01:45:57 +03:00
|
|
|
}
|
|
|
|
|
2015-11-25 07:42:26 +03:00
|
|
|
static bool
|
|
|
|
IsOn(const OwningBooleanOrMediaTrackConstraints &aUnion) {
|
|
|
|
return !aUnion.IsBoolean() || aUnion.GetAsBoolean();
|
|
|
|
}
|
|
|
|
|
|
|
|
static const MediaTrackConstraints&
|
|
|
|
GetInvariant(const OwningBooleanOrMediaTrackConstraints &aUnion) {
|
|
|
|
static const MediaTrackConstraints empty;
|
|
|
|
return aUnion.IsMediaTrackConstraints() ?
|
|
|
|
aUnion.GetAsMediaTrackConstraints() : empty;
|
|
|
|
}
|
|
|
|
|
2016-04-06 15:47:43 +03:00
|
|
|
/**
|
|
|
|
* This class is only needed since fake tracks are added dynamically.
|
|
|
|
* Instead of refactoring to add them explicitly we let the DOMMediaStream
|
|
|
|
* query us for the source as they become available.
|
|
|
|
* Since they are used only for testing the API surface, we make them very
|
|
|
|
* simple.
|
|
|
|
*/
|
|
|
|
class FakeTrackSourceGetter : public MediaStreamTrackSourceGetter
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
NS_DECL_ISUPPORTS_INHERITED
|
|
|
|
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FakeTrackSourceGetter,
|
|
|
|
MediaStreamTrackSourceGetter)
|
|
|
|
|
|
|
|
explicit FakeTrackSourceGetter(nsIPrincipal* aPrincipal)
|
|
|
|
: mPrincipal(aPrincipal) {}
|
|
|
|
|
|
|
|
already_AddRefed<dom::MediaStreamTrackSource>
|
|
|
|
GetMediaStreamTrackSource(TrackID aInputTrackID) override
|
|
|
|
{
|
|
|
|
NS_ASSERTION(kAudioTrack != aInputTrackID,
|
|
|
|
"Only fake tracks should appear dynamically");
|
|
|
|
NS_ASSERTION(kVideoTrack != aInputTrackID,
|
|
|
|
"Only fake tracks should appear dynamically");
|
2016-09-16 16:19:28 +03:00
|
|
|
return do_AddRef(new BasicTrackSource(mPrincipal));
|
2016-04-06 15:47:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual ~FakeTrackSourceGetter() {}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIPrincipal> mPrincipal;
|
|
|
|
};
|
|
|
|
|
|
|
|
NS_IMPL_ADDREF_INHERITED(FakeTrackSourceGetter, MediaStreamTrackSourceGetter)
|
|
|
|
NS_IMPL_RELEASE_INHERITED(FakeTrackSourceGetter, MediaStreamTrackSourceGetter)
|
2017-08-30 02:02:48 +03:00
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FakeTrackSourceGetter)
|
2016-04-06 15:47:43 +03:00
|
|
|
NS_INTERFACE_MAP_END_INHERITING(MediaStreamTrackSourceGetter)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_INHERITED(FakeTrackSourceGetter,
|
|
|
|
MediaStreamTrackSourceGetter,
|
|
|
|
mPrincipal)
|
|
|
|
|
2012-06-03 11:35:15 +04:00
|
|
|
/**
|
2012-07-12 15:53:08 +04:00
|
|
|
* Creates a MediaStream, attaches a listener and fires off a success callback
|
2012-09-20 23:54:00 +04:00
|
|
|
* to the DOM with the stream. We also pass in the error callback so it can
|
|
|
|
* be released correctly.
|
2012-07-12 15:53:08 +04:00
|
|
|
*
|
|
|
|
* All of this must be done on the main thread!
|
2012-10-16 00:41:46 +04:00
|
|
|
*
|
|
|
|
* Note that the various GetUserMedia Runnable classes currently allow for
|
|
|
|
* two streams. If we ever need to support getting more than two streams
|
2015-10-18 08:24:48 +03:00
|
|
|
* at once, we could convert everything to nsTArray<RefPtr<blah> >'s,
|
2012-10-25 03:21:15 +04:00
|
|
|
* though that would complicate the constructors some. Currently the
|
2012-10-16 00:41:46 +04:00
|
|
|
* GetUserMedia spec does not allow for more than 2 streams to be obtained in
|
|
|
|
* one call, to simplify handling of constraints.
|
2012-06-03 11:35:15 +04:00
|
|
|
*/
|
2016-04-26 03:23:21 +03:00
|
|
|
class GetUserMediaStreamRunnable : public Runnable
|
2012-06-03 11:35:15 +04:00
|
|
|
{
|
|
|
|
public:
|
2012-09-20 23:54:00 +04:00
|
|
|
GetUserMediaStreamRunnable(
|
2018-07-28 07:40:26 +03:00
|
|
|
const nsMainThreadPtrHandle<MediaManager::GetUserMediaSuccessCallback>& aOnSuccess,
|
|
|
|
const nsMainThreadPtrHandle<MediaManager::GetUserMediaErrorCallback>& aOnFailure,
|
2012-10-16 00:41:46 +04:00
|
|
|
uint64_t aWindowID,
|
2017-04-26 12:13:40 +03:00
|
|
|
GetUserMediaWindowListener* aWindowListener,
|
|
|
|
SourceListener* aSourceListener,
|
2017-01-28 20:29:13 +03:00
|
|
|
const ipc::PrincipalInfo& aPrincipalInfo,
|
2015-11-25 07:42:26 +03:00
|
|
|
const MediaStreamConstraints& aConstraints,
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
MediaDevice* aAudioDevice,
|
|
|
|
MediaDevice* aVideoDevice,
|
2018-05-08 22:55:36 +03:00
|
|
|
PeerIdentity* aPeerIdentity,
|
|
|
|
bool aIsChrome)
|
2017-06-12 22:34:10 +03:00
|
|
|
: Runnable("GetUserMediaStreamRunnable")
|
2017-11-15 20:40:35 +03:00
|
|
|
, mOnSuccess(aOnSuccess)
|
|
|
|
, mOnFailure(aOnFailure)
|
2017-06-12 22:34:10 +03:00
|
|
|
, mConstraints(aConstraints)
|
2015-11-25 07:42:26 +03:00
|
|
|
, mAudioDevice(aAudioDevice)
|
2015-09-19 07:49:07 +03:00
|
|
|
, mVideoDevice(aVideoDevice)
|
2012-12-29 00:29:52 +04:00
|
|
|
, mWindowID(aWindowID)
|
2017-04-26 12:13:40 +03:00
|
|
|
, mWindowListener(aWindowListener)
|
|
|
|
, mSourceListener(aSourceListener)
|
2017-01-28 20:29:13 +03:00
|
|
|
, mPrincipalInfo(aPrincipalInfo)
|
2014-05-01 14:51:00 +04:00
|
|
|
, mPeerIdentity(aPeerIdentity)
|
2014-03-15 23:00:15 +04:00
|
|
|
, mManager(MediaManager::GetInstance())
|
|
|
|
{
|
|
|
|
}
|
2012-07-12 15:53:08 +04:00
|
|
|
|
|
|
|
~GetUserMediaStreamRunnable() {}
|
2012-06-03 11:35:15 +04:00
|
|
|
|
2016-01-05 05:16:21 +03:00
|
|
|
class TracksAvailableCallback : public OnTracksAvailableCallback
|
2013-05-03 09:07:37 +04:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
TracksAvailableCallback(MediaManager* aManager,
|
2018-07-28 07:40:26 +03:00
|
|
|
const nsMainThreadPtrHandle<MediaManager::GetUserMediaSuccessCallback>& aSuccess,
|
2018-03-19 11:40:38 +03:00
|
|
|
const RefPtr<GetUserMediaWindowListener>& aWindowListener,
|
2013-12-06 01:30:50 +04:00
|
|
|
DOMMediaStream* aStream)
|
2018-03-19 11:40:38 +03:00
|
|
|
: mWindowListener(aWindowListener),
|
|
|
|
mOnSuccess(aSuccess),
|
|
|
|
mManager(aManager),
|
|
|
|
mStream(aStream)
|
|
|
|
{}
|
2016-01-18 06:50:29 +03:00
|
|
|
void NotifyTracksAvailable(DOMMediaStream* aStream) override
|
2013-05-03 09:07:37 +04:00
|
|
|
{
|
2018-03-19 11:40:38 +03:00
|
|
|
// We're on the main thread, so no worries here.
|
|
|
|
if (!mManager->IsWindowListenerStillActive(mWindowListener)) {
|
2013-05-03 09:07:37 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Start currentTime from the point where this stream was successfully
|
|
|
|
// returned.
|
2015-09-30 04:31:54 +03:00
|
|
|
aStream->SetLogicalStreamStartTime(aStream->GetPlaybackStream()->GetCurrentTime());
|
2013-05-03 09:07:37 +04:00
|
|
|
|
|
|
|
// This is safe since we're on main-thread, and the windowlist can only
|
|
|
|
// be invalidated from the main-thread (see OnNavigation)
|
|
|
|
LOG(("Returning success for getUserMedia()"));
|
2018-07-28 07:40:26 +03:00
|
|
|
CallOnSuccess(mOnSuccess, *aStream);
|
2013-05-03 09:07:37 +04:00
|
|
|
}
|
2018-03-19 11:40:38 +03:00
|
|
|
RefPtr<GetUserMediaWindowListener> mWindowListener;
|
2018-07-28 07:40:26 +03:00
|
|
|
nsMainThreadPtrHandle<MediaManager::GetUserMediaSuccessCallback> mOnSuccess;
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<MediaManager> mManager;
|
2013-05-03 09:07:37 +04:00
|
|
|
// Keep the DOMMediaStream alive until the NotifyTracksAvailable callback
|
|
|
|
// has fired, otherwise we might immediately destroy the DOMMediaStream and
|
|
|
|
// shut down the underlying MediaStream prematurely.
|
|
|
|
// This creates a cycle which is broken when NotifyTracksAvailable
|
|
|
|
// is fired (which will happen unless the browser shuts down,
|
|
|
|
// since we only add this callback when we've successfully appended
|
|
|
|
// the desired tracks in the MediaStreamGraph) or when
|
|
|
|
// DOMMediaStream::NotifyMediaStreamGraphShutdown is called.
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<DOMMediaStream> mStream;
|
2013-05-03 09:07:37 +04:00
|
|
|
};
|
|
|
|
|
2012-06-03 11:35:15 +04:00
|
|
|
NS_IMETHOD
|
2016-08-08 05:18:10 +03:00
|
|
|
Run() override
|
2012-06-03 11:35:15 +04:00
|
|
|
{
|
2015-09-30 09:08:22 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2018-03-16 22:09:55 +03:00
|
|
|
LOG(("GetUserMediaStreamRunnable::Run()"));
|
2017-11-06 21:09:35 +03:00
|
|
|
nsGlobalWindowInner* globalWindow = nsGlobalWindowInner::GetInnerWindowWithId(mWindowID);
|
2016-01-30 20:05:36 +03:00
|
|
|
nsPIDOMWindowInner* window = globalWindow ? globalWindow->AsInner() : nullptr;
|
2012-09-20 23:54:00 +04:00
|
|
|
|
2012-11-14 01:55:02 +04:00
|
|
|
// We're on main-thread, and the windowlist can only
|
|
|
|
// be invalidated from the main-thread (see OnNavigation)
|
2018-03-19 11:40:38 +03:00
|
|
|
if (!mManager->IsWindowListenerStillActive(mWindowListener)) {
|
|
|
|
// This window is no longer live. mListener has already been removed.
|
2012-11-14 01:55:02 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2015-08-25 11:29:51 +03:00
|
|
|
MediaStreamGraph::GraphDriverType graphDriverType =
|
2015-09-19 07:49:07 +03:00
|
|
|
mAudioDevice ? MediaStreamGraph::AUDIO_THREAD_DRIVER
|
2015-08-25 11:29:51 +03:00
|
|
|
: MediaStreamGraph::SYSTEM_THREAD_DRIVER;
|
|
|
|
MediaStreamGraph* msg =
|
2018-04-03 20:02:15 +03:00
|
|
|
MediaStreamGraph::GetInstance(graphDriverType, window,
|
|
|
|
MediaStreamGraph::REQUEST_DEFAULT_SAMPLE_RATE);
|
2015-08-25 11:29:51 +03:00
|
|
|
|
2017-11-14 13:53:52 +03:00
|
|
|
nsMainThreadPtrHandle<DOMMediaStream> domStream;
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<SourceMediaStream> stream;
|
2015-07-24 15:28:16 +03:00
|
|
|
// AudioCapture is a special case, here, in the sense that we're not really
|
|
|
|
// using the audio source and the SourceMediaStream, which acts as
|
|
|
|
// placeholders. We re-route a number of stream internaly in the MSG and mix
|
|
|
|
// them down instead.
|
2015-09-19 07:49:07 +03:00
|
|
|
if (mAudioDevice &&
|
2016-02-17 00:55:33 +03:00
|
|
|
mAudioDevice->GetMediaSource() == MediaSourceEnum::AudioCapture) {
|
2017-11-17 22:13:06 +03:00
|
|
|
NS_WARNING("MediaCaptureWindowState doesn't handle "
|
|
|
|
"MediaSourceEnum::AudioCapture. This must be fixed with UX "
|
|
|
|
"before shipping.");
|
2015-07-24 15:28:17 +03:00
|
|
|
// It should be possible to pipe the capture stream to anything. CORS is
|
|
|
|
// not a problem here, we got explicit user content.
|
2016-02-01 17:46:34 +03:00
|
|
|
nsCOMPtr<nsIPrincipal> principal = window->GetExtantDoc()->NodePrincipal();
|
2017-11-14 13:53:52 +03:00
|
|
|
domStream = new nsMainThreadPtrHolder<DOMMediaStream>(
|
|
|
|
"GetUserMediaStreamRunnable::AudioCaptureDOMStreamMainThreadHolder",
|
|
|
|
DOMMediaStream::CreateAudioCaptureStreamAsInput(window, principal, msg));
|
2016-02-01 17:46:34 +03:00
|
|
|
|
2017-06-29 21:30:57 +03:00
|
|
|
stream = msg->CreateSourceStream(); // Placeholder
|
2015-07-24 15:28:16 +03:00
|
|
|
msg->RegisterCaptureStreamForWindow(
|
2015-09-30 04:31:54 +03:00
|
|
|
mWindowID, domStream->GetInputStream()->AsProcessedStream());
|
2015-07-24 15:28:16 +03:00
|
|
|
window->SetAudioCapture(true);
|
|
|
|
} else {
|
2016-04-06 15:46:56 +03:00
|
|
|
class LocalTrackSource : public MediaStreamTrackSource
|
|
|
|
{
|
|
|
|
public:
|
2016-01-05 05:16:24 +03:00
|
|
|
LocalTrackSource(nsIPrincipal* aPrincipal,
|
2016-01-22 11:27:37 +03:00
|
|
|
const nsString& aLabel,
|
2018-01-23 13:31:22 +03:00
|
|
|
const RefPtr<SourceListener>& aListener,
|
2016-04-06 15:46:56 +03:00
|
|
|
const MediaSourceEnum aSource,
|
2016-01-05 05:16:29 +03:00
|
|
|
const TrackID aTrackID,
|
|
|
|
const PeerIdentity* aPeerIdentity)
|
2018-01-23 13:31:22 +03:00
|
|
|
: MediaStreamTrackSource(aPrincipal, aLabel),
|
|
|
|
mListener(aListener.get()),
|
|
|
|
mSource(aSource),
|
|
|
|
mTrackID(aTrackID),
|
|
|
|
mPeerIdentity(aPeerIdentity)
|
|
|
|
{}
|
2016-04-06 15:46:56 +03:00
|
|
|
|
|
|
|
MediaSourceEnum GetMediaSource() const override
|
|
|
|
{
|
|
|
|
return mSource;
|
|
|
|
}
|
|
|
|
|
2016-01-05 05:16:29 +03:00
|
|
|
const PeerIdentity* GetPeerIdentity() const override
|
|
|
|
{
|
|
|
|
return mPeerIdentity;
|
|
|
|
}
|
|
|
|
|
2015-11-19 06:17:09 +03:00
|
|
|
already_AddRefed<PledgeVoid>
|
2016-02-01 17:43:38 +03:00
|
|
|
ApplyConstraints(nsPIDOMWindowInner* aWindow,
|
2017-02-01 23:43:38 +03:00
|
|
|
const MediaTrackConstraints& aConstraints,
|
|
|
|
dom::CallerType aCallerType) override
|
2016-02-01 17:43:38 +03:00
|
|
|
{
|
2018-02-23 12:05:42 +03:00
|
|
|
RefPtr<PledgeVoid> p = new PledgeVoid();
|
2017-11-02 18:27:33 +03:00
|
|
|
if (sHasShutdown || !mListener) {
|
2016-07-06 23:55:58 +03:00
|
|
|
// Track has been stopped, or we are in shutdown. In either case
|
|
|
|
// there's no observable outcome, so pretend we succeeded.
|
|
|
|
p->Resolve(false);
|
2015-11-19 06:17:09 +03:00
|
|
|
return p.forget();
|
2016-02-01 17:43:38 +03:00
|
|
|
}
|
2018-02-23 12:05:42 +03:00
|
|
|
|
|
|
|
mListener->ApplyConstraintsToTrack(aWindow, mTrackID,
|
|
|
|
aConstraints, aCallerType)
|
|
|
|
->Then(GetMainThreadSerialEventTarget(), __func__,
|
|
|
|
[p]()
|
|
|
|
{
|
|
|
|
if (!MediaManager::Exists()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
p->Resolve(false);
|
|
|
|
},
|
2018-02-23 12:06:22 +03:00
|
|
|
[p, weakWindow = nsWeakPtr(do_GetWeakReference(aWindow)),
|
|
|
|
listener = mListener, trackID = mTrackID]
|
2018-02-23 12:05:42 +03:00
|
|
|
(Maybe<nsString>&& aBadConstraint)
|
|
|
|
{
|
|
|
|
if (!MediaManager::Exists()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!weakWindow->IsAlive()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aBadConstraint.isNothing()) {
|
2018-02-23 12:06:22 +03:00
|
|
|
// Unexpected error during reconfig that left the source
|
|
|
|
// stopped. We resolve the promise and end the track.
|
|
|
|
if (listener) {
|
|
|
|
listener->StopTrack(trackID);
|
|
|
|
}
|
|
|
|
p->Resolve(false);
|
2018-02-23 12:05:42 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-02-23 12:06:22 +03:00
|
|
|
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryReferent(weakWindow);
|
2018-02-23 12:05:42 +03:00
|
|
|
auto error = MakeRefPtr<MediaStreamError>(
|
|
|
|
window,
|
2018-04-10 08:22:53 +03:00
|
|
|
MediaMgrError::Name::OverconstrainedError,
|
2018-02-23 12:05:42 +03:00
|
|
|
NS_LITERAL_STRING(""),
|
|
|
|
aBadConstraint.valueOr(nsString()));
|
|
|
|
p->Reject(error);
|
|
|
|
});
|
|
|
|
|
|
|
|
return p.forget();
|
2016-02-01 17:43:38 +03:00
|
|
|
}
|
|
|
|
|
2016-06-20 07:38:25 +03:00
|
|
|
void
|
|
|
|
GetSettings(dom::MediaTrackSettings& aOutSettings) override
|
|
|
|
{
|
2016-07-06 23:55:58 +03:00
|
|
|
if (mListener) {
|
2017-11-17 21:56:00 +03:00
|
|
|
mListener->GetSettingsFor(mTrackID, aOutSettings);
|
2016-07-06 23:55:58 +03:00
|
|
|
}
|
2016-06-20 07:38:25 +03:00
|
|
|
}
|
2016-02-01 17:43:38 +03:00
|
|
|
|
2016-04-06 15:46:56 +03:00
|
|
|
void Stop() override
|
|
|
|
{
|
|
|
|
if (mListener) {
|
|
|
|
mListener->StopTrack(mTrackID);
|
|
|
|
mListener = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-10 17:55:42 +03:00
|
|
|
void Disable() override
|
|
|
|
{
|
|
|
|
if (mListener) {
|
2017-11-17 21:56:00 +03:00
|
|
|
mListener->SetEnabledFor(mTrackID, false);
|
2017-11-10 17:55:42 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Enable() override
|
|
|
|
{
|
|
|
|
if (mListener) {
|
2017-11-17 21:56:00 +03:00
|
|
|
mListener->SetEnabledFor(mTrackID, true);
|
2017-11-10 17:55:42 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-06 15:46:56 +03:00
|
|
|
protected:
|
|
|
|
~LocalTrackSource() {}
|
|
|
|
|
2018-01-23 13:31:22 +03:00
|
|
|
// This is a weak pointer to avoid having the SourceListener (which may
|
|
|
|
// have references to threads and threadpools) kept alive by DOM-objects
|
|
|
|
// that may have ref-cycles and thus are released very late during
|
|
|
|
// shutdown, even after xpcom-shutdown-threads. See bug 1351655 for what
|
|
|
|
// can happen.
|
|
|
|
WeakPtr<SourceListener> mListener;
|
2016-04-06 15:46:56 +03:00
|
|
|
const MediaSourceEnum mSource;
|
|
|
|
const TrackID mTrackID;
|
2016-01-05 05:16:29 +03:00
|
|
|
const RefPtr<const PeerIdentity> mPeerIdentity;
|
2016-04-06 15:46:56 +03:00
|
|
|
};
|
|
|
|
|
2016-01-05 05:16:24 +03:00
|
|
|
nsCOMPtr<nsIPrincipal> principal;
|
|
|
|
if (mPeerIdentity) {
|
2017-03-22 13:38:40 +03:00
|
|
|
principal = NullPrincipal::CreateWithInheritedAttributes(window->GetExtantDoc()->NodePrincipal());
|
2016-01-05 05:16:24 +03:00
|
|
|
} else {
|
|
|
|
principal = window->GetExtantDoc()->NodePrincipal();
|
|
|
|
}
|
|
|
|
|
2015-07-24 15:28:16 +03:00
|
|
|
// Normal case, connect the source stream to the track union stream to
|
2016-04-06 15:47:43 +03:00
|
|
|
// avoid us blocking. Pass a simple TrackSourceGetter for potential
|
|
|
|
// fake tracks. Apart from them gUM never adds tracks dynamically.
|
2017-11-14 13:53:52 +03:00
|
|
|
domStream = new nsMainThreadPtrHolder<DOMMediaStream>(
|
|
|
|
"GetUserMediaStreamRunnable::DOMMediaStreamMainThreadHolder",
|
2016-04-25 06:43:27 +03:00
|
|
|
DOMLocalMediaStream::CreateSourceStreamAsInput(window, msg,
|
2017-11-14 13:53:52 +03:00
|
|
|
new FakeTrackSourceGetter(principal)));
|
2017-04-26 12:13:40 +03:00
|
|
|
stream = domStream->GetInputStream()->AsSourceStream();
|
2015-09-30 04:31:54 +03:00
|
|
|
|
|
|
|
if (mAudioDevice) {
|
2016-01-16 15:39:00 +03:00
|
|
|
nsString audioDeviceName;
|
|
|
|
mAudioDevice->GetName(audioDeviceName);
|
2017-11-17 21:56:00 +03:00
|
|
|
const MediaSourceEnum source = mAudioDevice->GetMediaSource();
|
2016-04-06 15:46:56 +03:00
|
|
|
RefPtr<MediaStreamTrackSource> audioSource =
|
2017-04-26 12:13:40 +03:00
|
|
|
new LocalTrackSource(principal, audioDeviceName, mSourceListener,
|
|
|
|
source, kAudioTrack, mPeerIdentity);
|
2015-11-25 07:42:26 +03:00
|
|
|
MOZ_ASSERT(IsOn(mConstraints.mAudio));
|
2016-08-12 14:50:41 +03:00
|
|
|
RefPtr<MediaStreamTrack> track =
|
|
|
|
domStream->CreateDOMTrack(kAudioTrack, MediaSegment::AUDIO, audioSource,
|
|
|
|
GetInvariant(mConstraints.mAudio));
|
|
|
|
domStream->AddTrackInternal(track);
|
2015-09-30 04:31:54 +03:00
|
|
|
}
|
|
|
|
if (mVideoDevice) {
|
2016-01-16 15:39:00 +03:00
|
|
|
nsString videoDeviceName;
|
|
|
|
mVideoDevice->GetName(videoDeviceName);
|
2017-11-17 21:56:00 +03:00
|
|
|
const MediaSourceEnum source = mVideoDevice->GetMediaSource();
|
2016-04-06 15:46:56 +03:00
|
|
|
RefPtr<MediaStreamTrackSource> videoSource =
|
2017-04-26 12:13:40 +03:00
|
|
|
new LocalTrackSource(principal, videoDeviceName, mSourceListener,
|
|
|
|
source, kVideoTrack, mPeerIdentity);
|
2015-11-25 07:42:26 +03:00
|
|
|
MOZ_ASSERT(IsOn(mConstraints.mVideo));
|
2016-08-12 14:50:41 +03:00
|
|
|
RefPtr<MediaStreamTrack> track =
|
|
|
|
domStream->CreateDOMTrack(kVideoTrack, MediaSegment::VIDEO, videoSource,
|
|
|
|
GetInvariant(mConstraints.mVideo));
|
|
|
|
domStream->AddTrackInternal(track);
|
2015-09-30 04:31:54 +03:00
|
|
|
}
|
2015-07-24 15:28:16 +03:00
|
|
|
}
|
|
|
|
|
2017-11-02 18:27:33 +03:00
|
|
|
if (!domStream || !stream || sHasShutdown) {
|
2012-11-14 01:55:02 +04:00
|
|
|
LOG(("Returning error for getUserMedia() - no stream"));
|
2014-10-27 22:42:56 +03:00
|
|
|
|
2017-11-06 21:09:35 +03:00
|
|
|
if (auto* window = nsGlobalWindowInner::GetInnerWindowWithId(mWindowID)) {
|
2016-01-30 20:05:36 +03:00
|
|
|
RefPtr<MediaStreamError> error = new MediaStreamError(window->AsInner(),
|
2018-04-06 22:06:16 +03:00
|
|
|
MediaStreamError::Name::AbortError,
|
2017-11-02 18:27:33 +03:00
|
|
|
sHasShutdown ? NS_LITERAL_STRING("In shutdown") :
|
2018-04-10 08:22:53 +03:00
|
|
|
NS_LITERAL_STRING("No stream."));
|
2018-07-28 07:40:26 +03:00
|
|
|
CallOnError(mOnFailure, *error);
|
2014-10-27 22:42:56 +03:00
|
|
|
}
|
2012-11-14 01:55:02 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2012-07-12 15:53:48 +04:00
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
// Activate our source listener. We'll call Start() on the source when we
|
|
|
|
// get a callback that the MediaStream has started consuming. The listener
|
|
|
|
// is freed when the page is invalidated (on navigation or close).
|
|
|
|
mWindowListener->Activate(mSourceListener, stream, mAudioDevice, mVideoDevice);
|
2012-07-12 15:53:08 +04:00
|
|
|
|
2013-12-06 01:30:51 +04:00
|
|
|
// Note: includes JS callbacks; must be released on MainThread
|
2017-11-14 13:53:52 +03:00
|
|
|
typedef Refcountable<UniquePtr<TracksAvailableCallback>> Callback;
|
|
|
|
nsMainThreadPtrHandle<Callback> callback(
|
|
|
|
new nsMainThreadPtrHolder<Callback>(
|
|
|
|
"GetUserMediaStreamRunnable::TracksAvailableCallbackMainThreadHolder",
|
|
|
|
MakeAndAddRef<Callback>(
|
|
|
|
new TracksAvailableCallback(mManager,
|
2017-11-15 20:40:35 +03:00
|
|
|
mOnSuccess,
|
2018-03-19 11:40:38 +03:00
|
|
|
mWindowListener,
|
2017-11-14 13:53:52 +03:00
|
|
|
domStream))));
|
2013-05-03 09:07:37 +04:00
|
|
|
|
2014-04-02 21:58:19 +04:00
|
|
|
// Dispatch to the media thread to ask it to start the sources,
|
|
|
|
// because that can take a while.
|
2017-11-14 13:50:07 +03:00
|
|
|
// Pass ownership of domStream through the lambda to the nested chrome
|
|
|
|
// notification lambda to ensure it's kept alive until that lambda runs or is discarded.
|
2018-02-16 13:55:27 +03:00
|
|
|
mSourceListener->InitializeAsync()->Then(
|
|
|
|
GetMainThreadSerialEventTarget(), __func__,
|
|
|
|
[manager = mManager, domStream, callback,
|
|
|
|
windowListener = mWindowListener]()
|
|
|
|
{
|
2018-03-16 22:09:55 +03:00
|
|
|
LOG(("GetUserMediaStreamRunnable::Run: starting success callback "
|
|
|
|
"following InitializeAsync()"));
|
2018-02-16 13:55:27 +03:00
|
|
|
// Initiating and starting devices succeeded.
|
|
|
|
// onTracksAvailableCallback must be added to domStream on main thread.
|
2018-02-26 18:54:18 +03:00
|
|
|
domStream->OnTracksAvailable(callback->release());
|
2018-02-16 13:55:27 +03:00
|
|
|
windowListener->ChromeAffectingStateChanged();
|
|
|
|
manager->SendPendingGUMRequest();
|
|
|
|
},[manager = mManager, windowID = mWindowID,
|
2018-05-30 22:15:35 +03:00
|
|
|
onFailure = std::move(mOnFailure)](const RefPtr<MediaMgrError>& error)
|
2018-02-16 13:55:27 +03:00
|
|
|
{
|
2018-03-16 22:09:55 +03:00
|
|
|
LOG(("GetUserMediaStreamRunnable::Run: starting failure callback "
|
|
|
|
"following InitializeAsync()"));
|
2018-02-16 13:55:27 +03:00
|
|
|
// Initiating and starting devices failed.
|
2018-02-26 18:54:18 +03:00
|
|
|
|
2018-02-16 13:55:27 +03:00
|
|
|
// Only run if the window is still active for our window listener.
|
|
|
|
if (!(manager->IsWindowStillActive(windowID))) {
|
2018-02-26 18:54:18 +03:00
|
|
|
return;
|
2018-02-16 13:55:27 +03:00
|
|
|
}
|
2018-02-16 13:55:27 +03:00
|
|
|
// This is safe since we're on main-thread, and the windowlist can only
|
|
|
|
// be invalidated from the main-thread (see OnNavigation)
|
|
|
|
if (auto* window = nsGlobalWindowInner::GetInnerWindowWithId(windowID)) {
|
|
|
|
auto streamError = MakeRefPtr<MediaStreamError>(window->AsInner(), *error);
|
2018-07-28 07:40:26 +03:00
|
|
|
CallOnError(onFailure, *streamError);
|
2018-02-16 13:55:27 +03:00
|
|
|
}
|
|
|
|
});
|
2015-07-10 17:15:19 +03:00
|
|
|
|
2017-01-28 20:29:13 +03:00
|
|
|
if (!IsPincipalInfoPrivate(mPrincipalInfo)) {
|
|
|
|
// Call GetPrincipalKey again, this time w/persist = true, to promote
|
2015-07-10 17:15:19 +03:00
|
|
|
// deviceIds to persistent, in case they're not already. Fire'n'forget.
|
2018-09-25 20:03:50 +03:00
|
|
|
media::GetPrincipalKey(mPrincipalInfo, true)
|
|
|
|
->Then(GetCurrentThreadSerialEventTarget(), __func__,
|
|
|
|
[](const PrincipalKeyPromise::ResolveOrRejectValue& aValue) {
|
|
|
|
if (aValue.IsReject()) {
|
|
|
|
LOG(("Failed get Principal key. Persisting of deviceIds will be broken"));
|
|
|
|
}
|
|
|
|
});
|
2015-07-10 17:15:19 +03:00
|
|
|
}
|
2012-06-03 11:35:15 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2018-07-28 07:40:26 +03:00
|
|
|
nsMainThreadPtrHandle<MediaManager::GetUserMediaSuccessCallback> mOnSuccess;
|
|
|
|
nsMainThreadPtrHandle<MediaManager::GetUserMediaErrorCallback> mOnFailure;
|
2015-11-25 07:42:26 +03:00
|
|
|
MediaStreamConstraints mConstraints;
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
RefPtr<MediaDevice> mAudioDevice;
|
|
|
|
RefPtr<MediaDevice> mVideoDevice;
|
2012-08-22 19:56:38 +04:00
|
|
|
uint64_t mWindowID;
|
2017-04-26 12:13:40 +03:00
|
|
|
RefPtr<GetUserMediaWindowListener> mWindowListener;
|
|
|
|
RefPtr<SourceListener> mSourceListener;
|
2017-01-28 20:29:13 +03:00
|
|
|
ipc::PrincipalInfo mPrincipalInfo;
|
2016-01-05 05:16:28 +03:00
|
|
|
RefPtr<PeerIdentity> mPeerIdentity;
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<MediaManager> mManager; // get ref to this when creating the runnable
|
2012-06-03 11:35:15 +04:00
|
|
|
};
|
|
|
|
|
2015-07-03 01:01:52 +03:00
|
|
|
// Source getter returning full list
|
2013-09-16 10:34:57 +04:00
|
|
|
|
2014-09-24 19:17:33 +04:00
|
|
|
static void
|
2018-07-11 09:59:13 +03:00
|
|
|
GetMediaDevices(MediaEngine *aEngine,
|
|
|
|
uint64_t aWindowId,
|
|
|
|
MediaSourceEnum aSrcType,
|
2018-09-25 20:03:50 +03:00
|
|
|
MediaManager::MediaDeviceSet& aResult,
|
2018-07-11 09:59:13 +03:00
|
|
|
const char* aMediaDeviceName = nullptr)
|
2013-09-16 10:34:57 +04:00
|
|
|
{
|
2017-11-17 21:56:00 +03:00
|
|
|
MOZ_ASSERT(MediaManager::IsInMediaThread());
|
|
|
|
|
2018-03-16 22:09:55 +03:00
|
|
|
LOG(("%s: aEngine=%p, aWindowId=%" PRIu64 ", aSrcType=%" PRIu8 ", aMediaDeviceName=%s",
|
|
|
|
__func__, aEngine, aWindowId, static_cast<uint8_t>(aSrcType),
|
|
|
|
aMediaDeviceName ? aMediaDeviceName : "null"));
|
2018-07-11 09:59:13 +03:00
|
|
|
nsTArray<RefPtr<MediaDevice>> devices;
|
2018-07-16 12:30:46 +03:00
|
|
|
aEngine->EnumerateDevices(aWindowId, aSrcType, MediaSinkEnum::Other, &devices);
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We're allowing multiple tabs to access the same camera for parity
|
|
|
|
* with Chrome. See bug 811757 for some of the issues surrounding
|
|
|
|
* this decision. To disallow, we'd filter by IsAvailable() as we used
|
|
|
|
* to.
|
|
|
|
*/
|
2018-03-16 22:09:55 +03:00
|
|
|
if (aMediaDeviceName && *aMediaDeviceName) {
|
2018-07-11 09:59:13 +03:00
|
|
|
for (auto& device : devices) {
|
|
|
|
if (device->mName.EqualsASCII(aMediaDeviceName)) {
|
|
|
|
aResult.AppendElement(device);
|
2018-03-16 22:09:55 +03:00
|
|
|
LOG(("%s: found aMediaDeviceName=%s", __func__, aMediaDeviceName));
|
2015-07-03 01:01:52 +03:00
|
|
|
break;
|
2013-11-11 14:39:54 +04:00
|
|
|
}
|
2013-09-16 10:34:57 +04:00
|
|
|
}
|
2015-07-03 01:01:52 +03:00
|
|
|
} else {
|
2018-07-11 09:59:13 +03:00
|
|
|
aResult = devices;
|
|
|
|
if (MOZ_LOG_TEST(GetMediaManagerLog(), mozilla::LogLevel::Debug)) {
|
|
|
|
for (auto& device : devices) {
|
|
|
|
LOG(("%s: appending device=%s", __func__,
|
|
|
|
NS_ConvertUTF16toUTF8(device->mName).get()));
|
|
|
|
}
|
2015-07-03 01:01:52 +03:00
|
|
|
}
|
2013-09-16 10:34:57 +04:00
|
|
|
}
|
2015-07-03 01:01:52 +03:00
|
|
|
}
|
2013-09-16 10:34:57 +04:00
|
|
|
|
2015-10-04 03:42:26 +03:00
|
|
|
// TODO: Remove once upgraded to GCC 4.8+ on linux. Bogus error on static func:
|
|
|
|
// error: 'this' was not captured for this lambda function
|
|
|
|
|
|
|
|
static auto& MediaManager_ToJSArray = MediaManager::ToJSArray;
|
|
|
|
static auto& MediaManager_AnonymizeDevices = MediaManager::AnonymizeDevices;
|
|
|
|
|
2018-09-25 20:03:50 +03:00
|
|
|
RefPtr<MediaManager::BadConstraintsPromise>
|
2015-10-04 03:42:26 +03:00
|
|
|
MediaManager::SelectSettings(
|
|
|
|
MediaStreamConstraints& aConstraints,
|
2016-08-19 23:39:54 +03:00
|
|
|
bool aIsChrome,
|
2018-09-25 20:03:50 +03:00
|
|
|
const RefPtr<MediaDeviceSetRefCnt>& aSources)
|
2015-07-03 01:01:52 +03:00
|
|
|
{
|
2015-10-04 03:42:26 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2015-07-03 01:01:52 +03:00
|
|
|
|
2015-10-04 03:42:26 +03:00
|
|
|
// Algorithm accesses device capabilities code and must run on media thread.
|
|
|
|
// Modifies passed-in aSources.
|
2015-07-03 01:01:52 +03:00
|
|
|
|
2018-09-25 20:03:50 +03:00
|
|
|
return MediaManager::PostTask<BadConstraintsPromise>(
|
|
|
|
__func__,
|
|
|
|
[aConstraints, aSources,
|
|
|
|
aIsChrome](MozPromiseHolder<BadConstraintsPromise>& holder) mutable {
|
2015-10-04 03:42:26 +03:00
|
|
|
auto& sources = **aSources;
|
2015-07-03 01:01:52 +03:00
|
|
|
|
2015-10-04 03:42:26 +03:00
|
|
|
// Since the advanced part of the constraints algorithm needs to know when
|
|
|
|
// a candidate set is overconstrained (zero members), we must split up the
|
|
|
|
// list into videos and audios, and put it back together again at the end.
|
|
|
|
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
nsTArray<RefPtr<MediaDevice>> videos;
|
|
|
|
nsTArray<RefPtr<MediaDevice>> audios;
|
2015-09-18 21:04:41 +03:00
|
|
|
|
2015-10-04 03:42:26 +03:00
|
|
|
for (auto& source : sources) {
|
2018-07-16 12:29:12 +03:00
|
|
|
MOZ_ASSERT(source->mKind == dom::MediaDeviceKind::Videoinput ||
|
|
|
|
source->mKind == dom::MediaDeviceKind::Audioinput);
|
|
|
|
if (source->mKind == dom::MediaDeviceKind::Videoinput) {
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
videos.AppendElement(source);
|
2018-07-16 12:29:12 +03:00
|
|
|
} else if (source->mKind == dom::MediaDeviceKind::Audioinput) {
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
audios.AppendElement(source);
|
2015-10-04 03:42:26 +03:00
|
|
|
}
|
2015-07-03 01:01:52 +03:00
|
|
|
}
|
2015-10-04 03:42:26 +03:00
|
|
|
sources.Clear();
|
|
|
|
const char* badConstraint = nullptr;
|
2016-05-06 00:11:53 +03:00
|
|
|
bool needVideo = IsOn(aConstraints.mVideo);
|
|
|
|
bool needAudio = IsOn(aConstraints.mAudio);
|
2015-10-04 03:42:26 +03:00
|
|
|
|
2016-05-06 00:11:53 +03:00
|
|
|
if (needVideo && videos.Length()) {
|
2015-10-04 03:42:26 +03:00
|
|
|
badConstraint = MediaConstraintsHelper::SelectSettings(
|
2016-08-19 23:39:54 +03:00
|
|
|
NormalizedConstraints(GetInvariant(aConstraints.mVideo)), videos,
|
|
|
|
aIsChrome);
|
2015-07-03 01:01:52 +03:00
|
|
|
}
|
2016-05-06 00:11:53 +03:00
|
|
|
if (!badConstraint && needAudio && audios.Length()) {
|
2015-10-04 03:42:26 +03:00
|
|
|
badConstraint = MediaConstraintsHelper::SelectSettings(
|
2016-08-19 23:39:54 +03:00
|
|
|
NormalizedConstraints(GetInvariant(aConstraints.mAudio)), audios,
|
|
|
|
aIsChrome);
|
2016-05-05 22:46:04 +03:00
|
|
|
}
|
2016-05-06 00:11:53 +03:00
|
|
|
if (!badConstraint &&
|
|
|
|
!needVideo == !videos.Length() &&
|
|
|
|
!needAudio == !audios.Length()) {
|
2016-05-05 22:46:04 +03:00
|
|
|
for (auto& video : videos) {
|
|
|
|
sources.AppendElement(video);
|
|
|
|
}
|
2015-10-04 03:42:26 +03:00
|
|
|
for (auto& audio : audios) {
|
|
|
|
sources.AppendElement(audio);
|
|
|
|
}
|
|
|
|
}
|
2018-09-25 20:03:50 +03:00
|
|
|
holder.Resolve(badConstraint, __func__);
|
|
|
|
});
|
2013-09-16 10:34:57 +04:00
|
|
|
}
|
|
|
|
|
2012-06-03 11:35:15 +04:00
|
|
|
/**
|
|
|
|
* Runs on a seperate thread and is responsible for enumerating devices.
|
|
|
|
* Depending on whether a picture or stream was asked for, either
|
2014-10-13 07:37:37 +04:00
|
|
|
* ProcessGetUserMedia is called, and the results are sent back to the DOM.
|
2012-06-03 11:35:15 +04:00
|
|
|
*
|
2012-07-12 15:53:08 +04:00
|
|
|
* Do not run this on the main thread. The success and error callbacks *MUST*
|
|
|
|
* be dispatched on the main thread!
|
2012-06-03 11:35:15 +04:00
|
|
|
*/
|
2016-04-28 03:06:05 +03:00
|
|
|
class GetUserMediaTask : public Runnable
|
2012-06-03 11:35:15 +04:00
|
|
|
{
|
|
|
|
public:
|
2014-09-12 18:49:39 +04:00
|
|
|
GetUserMediaTask(
|
2014-04-18 22:00:16 +04:00
|
|
|
const MediaStreamConstraints& aConstraints,
|
2018-07-28 07:40:26 +03:00
|
|
|
const nsMainThreadPtrHandle<MediaManager::GetUserMediaSuccessCallback>& aOnSuccess,
|
|
|
|
const nsMainThreadPtrHandle<MediaManager::GetUserMediaErrorCallback>& aOnFailure,
|
2017-06-12 22:34:10 +03:00
|
|
|
uint64_t aWindowID,
|
|
|
|
GetUserMediaWindowListener* aWindowListener,
|
|
|
|
SourceListener* aSourceListener,
|
|
|
|
MediaEnginePrefs& aPrefs,
|
2017-01-28 20:29:13 +03:00
|
|
|
const ipc::PrincipalInfo& aPrincipalInfo,
|
2016-08-19 23:39:54 +03:00
|
|
|
bool aIsChrome,
|
2018-07-16 12:30:46 +03:00
|
|
|
MediaManager::MediaDeviceSet* aMediaDeviceSet,
|
2018-05-29 23:14:38 +03:00
|
|
|
bool aShouldFocusSource)
|
2017-06-12 22:34:10 +03:00
|
|
|
: Runnable("GetUserMediaTask")
|
|
|
|
, mConstraints(aConstraints)
|
2014-10-18 04:47:46 +04:00
|
|
|
, mOnSuccess(aOnSuccess)
|
|
|
|
, mOnFailure(aOnFailure)
|
2012-09-29 02:26:00 +04:00
|
|
|
, mWindowID(aWindowID)
|
2017-04-26 12:13:40 +03:00
|
|
|
, mWindowListener(aWindowListener)
|
|
|
|
, mSourceListener(aSourceListener)
|
2013-03-05 01:02:17 +04:00
|
|
|
, mPrefs(aPrefs)
|
2017-01-28 20:29:13 +03:00
|
|
|
, mPrincipalInfo(aPrincipalInfo)
|
2016-08-19 23:39:54 +03:00
|
|
|
, mIsChrome(aIsChrome)
|
2018-05-29 23:14:38 +03:00
|
|
|
, mShouldFocusSource(aShouldFocusSource)
|
2012-09-29 02:26:00 +04:00
|
|
|
, mDeviceChosen(false)
|
2018-07-16 12:30:46 +03:00
|
|
|
, mMediaDeviceSet(aMediaDeviceSet)
|
2013-03-05 01:02:17 +04:00
|
|
|
, mManager(MediaManager::GetInstance())
|
|
|
|
{}
|
2012-09-29 02:26:00 +04:00
|
|
|
|
2014-09-12 18:49:39 +04:00
|
|
|
~GetUserMediaTask() {
|
2012-09-29 02:26:00 +04:00
|
|
|
}
|
2012-06-03 11:35:15 +04:00
|
|
|
|
2014-01-09 01:51:33 +04:00
|
|
|
void
|
2018-04-10 08:22:53 +03:00
|
|
|
Fail(MediaMgrError::Name aName,
|
2016-06-14 21:42:46 +03:00
|
|
|
const nsAString& aMessage = EmptyString(),
|
|
|
|
const nsAString& aConstraint = EmptyString()) {
|
|
|
|
RefPtr<MediaMgrError> error = new MediaMgrError(aName, aMessage, aConstraint);
|
2017-11-15 20:40:35 +03:00
|
|
|
auto errorRunnable = MakeRefPtr<ErrorCallbackRunnable>(
|
|
|
|
mOnFailure, *error, mWindowID);
|
2014-03-15 23:00:15 +04:00
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
NS_DispatchToMainThread(errorRunnable.forget());
|
2015-03-06 21:23:33 +03:00
|
|
|
// Do after ErrorCallbackRunnable Run()s, as it checks active window list
|
2017-04-26 12:13:40 +03:00
|
|
|
NS_DispatchToMainThread(NewRunnableMethod<RefPtr<SourceListener>>(
|
2017-06-12 22:34:10 +03:00
|
|
|
"GetUserMediaWindowListener::Remove",
|
|
|
|
mWindowListener,
|
|
|
|
&GetUserMediaWindowListener::Remove,
|
|
|
|
mSourceListener));
|
2014-01-09 01:51:33 +04:00
|
|
|
}
|
|
|
|
|
2016-04-28 03:06:05 +03:00
|
|
|
NS_IMETHOD
|
|
|
|
Run() override
|
2012-06-03 11:35:15 +04:00
|
|
|
{
|
2015-03-03 17:51:05 +03:00
|
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
2014-10-18 04:47:46 +04:00
|
|
|
MOZ_ASSERT(mOnSuccess);
|
|
|
|
MOZ_ASSERT(mOnFailure);
|
2015-07-03 01:01:52 +03:00
|
|
|
MOZ_ASSERT(mDeviceChosen);
|
2018-03-16 22:09:55 +03:00
|
|
|
LOG(("GetUserMediaTask::Run()"));
|
2012-09-20 23:54:00 +04:00
|
|
|
|
2015-07-03 01:01:52 +03:00
|
|
|
// Allocate a video or audio device and return a MediaStream via
|
|
|
|
// a GetUserMediaStreamRunnable.
|
2012-09-29 02:26:00 +04:00
|
|
|
|
2015-07-03 01:01:52 +03:00
|
|
|
nsresult rv;
|
2016-06-14 21:42:46 +03:00
|
|
|
const char* errorMsg = nullptr;
|
|
|
|
const char* badConstraint = nullptr;
|
2015-07-03 01:01:52 +03:00
|
|
|
|
|
|
|
if (mAudioDevice) {
|
2016-06-14 21:42:46 +03:00
|
|
|
auto& constraints = GetInvariant(mConstraints.mAudio);
|
2017-01-28 20:29:13 +03:00
|
|
|
rv = mAudioDevice->Allocate(constraints, mPrefs, mPrincipalInfo,
|
|
|
|
&badConstraint);
|
2015-07-03 01:01:52 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
2016-06-14 21:42:46 +03:00
|
|
|
errorMsg = "Failed to allocate audiosource";
|
2016-06-16 02:25:07 +03:00
|
|
|
if (rv == NS_ERROR_NOT_AVAILABLE && !badConstraint) {
|
2017-11-17 21:56:00 +03:00
|
|
|
nsTArray<RefPtr<MediaDevice>> devices;
|
|
|
|
devices.AppendElement(mAudioDevice);
|
2016-07-18 09:56:22 +03:00
|
|
|
badConstraint = MediaConstraintsHelper::SelectSettings(
|
2017-11-17 21:56:00 +03:00
|
|
|
NormalizedConstraints(constraints), devices, mIsChrome);
|
2016-06-14 21:42:46 +03:00
|
|
|
}
|
2012-09-20 23:54:00 +04:00
|
|
|
}
|
|
|
|
}
|
2016-06-14 21:42:46 +03:00
|
|
|
if (!errorMsg && mVideoDevice) {
|
|
|
|
auto& constraints = GetInvariant(mConstraints.mVideo);
|
2017-01-28 20:29:13 +03:00
|
|
|
rv = mVideoDevice->Allocate(constraints, mPrefs, mPrincipalInfo,
|
|
|
|
&badConstraint);
|
2015-07-03 01:01:52 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
2016-06-14 21:42:46 +03:00
|
|
|
errorMsg = "Failed to allocate videosource";
|
2016-06-16 02:25:07 +03:00
|
|
|
if (rv == NS_ERROR_NOT_AVAILABLE && !badConstraint) {
|
2017-11-17 21:56:00 +03:00
|
|
|
nsTArray<RefPtr<MediaDevice>> devices;
|
|
|
|
devices.AppendElement(mVideoDevice);
|
2016-07-18 09:56:22 +03:00
|
|
|
badConstraint = MediaConstraintsHelper::SelectSettings(
|
2017-11-17 21:56:00 +03:00
|
|
|
NormalizedConstraints(constraints), devices, mIsChrome);
|
2016-06-14 21:42:46 +03:00
|
|
|
}
|
2015-07-03 01:01:52 +03:00
|
|
|
if (mAudioDevice) {
|
2016-06-30 22:43:24 +03:00
|
|
|
mAudioDevice->Deallocate();
|
2015-07-03 01:01:52 +03:00
|
|
|
}
|
2018-05-08 22:55:36 +03:00
|
|
|
} else {
|
|
|
|
if (!mIsChrome) {
|
2018-05-29 23:14:38 +03:00
|
|
|
if (mShouldFocusSource) {
|
|
|
|
rv = mVideoDevice->FocusOnSelectedSource();
|
|
|
|
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
LOG(("FocusOnSelectedSource failed"));
|
|
|
|
}
|
2018-05-08 22:55:36 +03:00
|
|
|
}
|
|
|
|
}
|
2015-07-03 01:01:52 +03:00
|
|
|
}
|
|
|
|
}
|
2016-06-14 21:42:46 +03:00
|
|
|
if (errorMsg) {
|
2016-12-16 06:16:31 +03:00
|
|
|
LOG(("%s %" PRIu32, errorMsg, static_cast<uint32_t>(rv)));
|
2016-10-13 00:31:20 +03:00
|
|
|
if (badConstraint) {
|
2018-04-10 08:22:53 +03:00
|
|
|
Fail(MediaMgrError::Name::OverconstrainedError,
|
2016-10-13 00:31:20 +03:00
|
|
|
NS_LITERAL_STRING(""),
|
|
|
|
NS_ConvertUTF8toUTF16(badConstraint));
|
|
|
|
} else {
|
2018-04-10 08:22:53 +03:00
|
|
|
Fail(MediaMgrError::Name::NotReadableError,
|
2016-10-13 00:31:20 +03:00
|
|
|
NS_ConvertUTF8toUTF16(errorMsg));
|
2016-06-14 21:42:46 +03:00
|
|
|
}
|
2017-06-12 22:34:10 +03:00
|
|
|
NS_DispatchToMainThread(NS_NewRunnableFunction("MediaManager::SendPendingGUMRequest",
|
|
|
|
[]() -> void {
|
2017-09-29 22:06:51 +03:00
|
|
|
MediaManager* manager = MediaManager::GetIfExists();
|
|
|
|
if (!manager) {
|
|
|
|
return;
|
|
|
|
}
|
2017-05-12 06:32:14 +03:00
|
|
|
manager->SendPendingGUMRequest();
|
|
|
|
}));
|
2016-06-14 21:42:46 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2015-07-03 01:01:52 +03:00
|
|
|
PeerIdentity* peerIdentity = nullptr;
|
|
|
|
if (!mConstraints.mPeerIdentity.IsEmpty()) {
|
|
|
|
peerIdentity = new PeerIdentity(mConstraints.mPeerIdentity);
|
|
|
|
}
|
|
|
|
|
2015-09-19 07:49:07 +03:00
|
|
|
NS_DispatchToMainThread(do_AddRef(
|
|
|
|
new GetUserMediaStreamRunnable(mOnSuccess, mOnFailure, mWindowID,
|
2017-04-26 12:13:40 +03:00
|
|
|
mWindowListener, mSourceListener,
|
|
|
|
mPrincipalInfo, mConstraints,
|
|
|
|
mAudioDevice, mVideoDevice,
|
2018-05-08 22:55:36 +03:00
|
|
|
peerIdentity, mIsChrome)));
|
2016-04-28 03:06:05 +03:00
|
|
|
return NS_OK;
|
2012-06-03 11:35:15 +04:00
|
|
|
}
|
|
|
|
|
2012-10-06 04:20:47 +04:00
|
|
|
nsresult
|
2018-04-10 08:22:53 +03:00
|
|
|
Denied(MediaMgrError::Name aName,
|
2014-10-27 22:42:56 +03:00
|
|
|
const nsAString& aMessage = EmptyString())
|
2012-10-06 04:20:47 +04:00
|
|
|
{
|
2014-10-18 04:47:46 +04:00
|
|
|
MOZ_ASSERT(mOnSuccess);
|
|
|
|
MOZ_ASSERT(mOnFailure);
|
2014-01-09 01:51:33 +04:00
|
|
|
|
|
|
|
// We add a disabled listener to the StreamListeners array until accepted
|
|
|
|
// If this was the only active MediaStream, remove the window from the list.
|
2012-10-06 04:20:47 +04:00
|
|
|
if (NS_IsMainThread()) {
|
2017-11-06 21:09:35 +03:00
|
|
|
if (auto* window = nsGlobalWindowInner::GetInnerWindowWithId(mWindowID)) {
|
2016-01-30 20:05:36 +03:00
|
|
|
RefPtr<MediaStreamError> error = new MediaStreamError(window->AsInner(),
|
|
|
|
aName, aMessage);
|
2018-07-28 07:40:26 +03:00
|
|
|
CallOnError(mOnFailure, *error);
|
2014-10-27 22:42:56 +03:00
|
|
|
}
|
2013-01-07 06:31:32 +04:00
|
|
|
// Should happen *after* error runs for consistency, but may not matter
|
2017-04-26 12:13:40 +03:00
|
|
|
mWindowListener->Remove(mSourceListener);
|
2012-10-06 04:20:47 +04:00
|
|
|
} else {
|
2012-10-26 04:14:47 +04:00
|
|
|
// This will re-check the window being alive on main-thread
|
2014-10-27 22:42:56 +03:00
|
|
|
Fail(aName, aMessage);
|
2012-10-06 04:20:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2014-02-25 15:50:42 +04:00
|
|
|
nsresult
|
2014-04-18 22:00:16 +04:00
|
|
|
SetContraints(const MediaStreamConstraints& aConstraints)
|
2014-02-25 15:50:42 +04:00
|
|
|
{
|
|
|
|
mConstraints = aConstraints;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2016-05-06 04:54:04 +03:00
|
|
|
const MediaStreamConstraints&
|
|
|
|
GetConstraints()
|
|
|
|
{
|
|
|
|
return mConstraints;
|
|
|
|
}
|
|
|
|
|
2012-10-06 04:20:47 +04:00
|
|
|
nsresult
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
SetAudioDevice(MediaDevice* aAudioDevice)
|
2012-10-16 00:41:46 +04:00
|
|
|
{
|
|
|
|
mAudioDevice = aAudioDevice;
|
|
|
|
mDeviceChosen = true;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
SetVideoDevice(MediaDevice* aVideoDevice)
|
2012-10-06 04:20:47 +04:00
|
|
|
{
|
2012-10-16 00:41:46 +04:00
|
|
|
mVideoDevice = aVideoDevice;
|
2012-10-06 04:20:47 +04:00
|
|
|
mDeviceChosen = true;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2017-04-24 10:11:51 +03:00
|
|
|
uint64_t
|
|
|
|
GetWindowID()
|
|
|
|
{
|
|
|
|
return mWindowID;
|
|
|
|
}
|
|
|
|
|
2012-09-20 23:54:00 +04:00
|
|
|
private:
|
2014-04-18 22:00:16 +04:00
|
|
|
MediaStreamConstraints mConstraints;
|
2012-06-03 11:35:15 +04:00
|
|
|
|
2018-07-28 07:40:26 +03:00
|
|
|
nsMainThreadPtrHandle<MediaManager::GetUserMediaSuccessCallback> mOnSuccess;
|
|
|
|
nsMainThreadPtrHandle<MediaManager::GetUserMediaErrorCallback> mOnFailure;
|
2012-09-20 23:54:00 +04:00
|
|
|
uint64_t mWindowID;
|
2017-04-26 12:13:40 +03:00
|
|
|
RefPtr<GetUserMediaWindowListener> mWindowListener;
|
|
|
|
RefPtr<SourceListener> mSourceListener;
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
RefPtr<MediaDevice> mAudioDevice;
|
|
|
|
RefPtr<MediaDevice> mVideoDevice;
|
2013-03-05 01:02:17 +04:00
|
|
|
MediaEnginePrefs mPrefs;
|
2017-01-28 20:29:13 +03:00
|
|
|
ipc::PrincipalInfo mPrincipalInfo;
|
2016-08-19 23:39:54 +03:00
|
|
|
bool mIsChrome;
|
2018-05-29 23:14:38 +03:00
|
|
|
bool mShouldFocusSource;
|
2012-07-12 15:53:08 +04:00
|
|
|
|
2012-09-29 02:26:00 +04:00
|
|
|
bool mDeviceChosen;
|
2015-07-03 01:01:52 +03:00
|
|
|
public:
|
2018-07-16 12:30:46 +03:00
|
|
|
nsAutoPtr<MediaManager::MediaDeviceSet> mMediaDeviceSet;
|
2015-07-03 01:01:52 +03:00
|
|
|
private:
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<MediaManager> mManager; // get ref to this when creating the runnable
|
2012-09-20 23:54:00 +04:00
|
|
|
};
|
2012-06-03 11:35:15 +04:00
|
|
|
|
2017-07-24 03:08:55 +03:00
|
|
|
#if defined(ANDROID)
|
2016-04-26 03:23:21 +03:00
|
|
|
class GetUserMediaRunnableWrapper : public Runnable
|
2014-09-12 18:49:39 +04:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
// This object must take ownership of task
|
2018-03-27 17:51:32 +03:00
|
|
|
explicit GetUserMediaRunnableWrapper(GetUserMediaTask* task)
|
2017-06-12 22:34:10 +03:00
|
|
|
: Runnable("GetUserMediaRunnableWrapper")
|
|
|
|
, mTask(task) {
|
2014-09-12 18:49:39 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
~GetUserMediaRunnableWrapper() {
|
|
|
|
}
|
|
|
|
|
2016-04-28 03:06:05 +03:00
|
|
|
NS_IMETHOD Run() override {
|
2014-09-12 18:49:39 +04:00
|
|
|
mTask->Run();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
nsAutoPtr<GetUserMediaTask> mTask;
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
2012-09-20 23:54:00 +04:00
|
|
|
/**
|
2015-06-18 18:46:36 +03:00
|
|
|
* EnumerateRawDevices - Enumerate a list of audio & video devices that
|
|
|
|
* satisfy passed-in constraints. List contains raw id's.
|
2012-09-20 23:54:00 +04:00
|
|
|
*/
|
2013-11-11 14:39:54 +04:00
|
|
|
|
2018-09-25 20:03:50 +03:00
|
|
|
RefPtr<MediaManager::MediaDeviceSetPromise>
|
2015-07-24 15:28:17 +03:00
|
|
|
MediaManager::EnumerateRawDevices(uint64_t aWindowId,
|
2018-07-16 12:30:46 +03:00
|
|
|
MediaSourceEnum aVideoInputType,
|
|
|
|
MediaSourceEnum aAudioInputType,
|
|
|
|
MediaSinkEnum aAudioOutputType,
|
|
|
|
DeviceEnumerationType aVideoInputEnumType /* = DeviceEnumerationType::Normal */,
|
|
|
|
DeviceEnumerationType aAudioInputEnumType /* = DeviceEnumerationType::Normal */)
|
2015-06-18 18:46:36 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2018-07-16 12:30:46 +03:00
|
|
|
MOZ_ASSERT(aVideoInputType != MediaSourceEnum::Other ||
|
|
|
|
aAudioInputType != MediaSourceEnum::Other ||
|
|
|
|
aAudioOutputType != MediaSinkEnum::Other);
|
Bug 1436523 - Rework media manager enumeration to prefer loopback to fake devices, allow mixing of fake and loopback. r=achronop
Change the media manager so that if fake and loopback devices are requested,
loopback is preferred. With this change loopback and fake devices can also be
mixed. Since the fake flag is coarse, and does not specify fake audio or video,
we would previously just make everything fake. As loopback sets flags for video
and audio separately, we can now request a single loopback device, while also
setting the fake flag to get a mix. E.g. if we request a loopback audio device,
and set the fake flag, we should get loopback audio and fake video.
This change also attempts to somewhat consolidate where these settings take
place. Previously, EnumerateRawDevices did much of the loopback setup. However,
other steps around fingerprint resistance or fake devices were done in earlier
functions (EnumerateDevices and GetUserMedia). This changeset moves the loopback
setup so that it's more consolidated with the other setup code in these
functions.
MozReview-Commit-ID: FF0bR0Nyws9
--HG--
extra : rebase_source : 374a6fd0842a430e27c695bcf956e2e072a77fc3
2018-02-13 00:56:26 +03:00
|
|
|
// Since the enums can take one of several values, the following asserts rely
|
2018-07-16 12:30:46 +03:00
|
|
|
// on short circuting behavior. E.g. aVideoInputEnumType != Fake will be true if
|
Bug 1436523 - Rework media manager enumeration to prefer loopback to fake devices, allow mixing of fake and loopback. r=achronop
Change the media manager so that if fake and loopback devices are requested,
loopback is preferred. With this change loopback and fake devices can also be
mixed. Since the fake flag is coarse, and does not specify fake audio or video,
we would previously just make everything fake. As loopback sets flags for video
and audio separately, we can now request a single loopback device, while also
setting the fake flag to get a mix. E.g. if we request a loopback audio device,
and set the fake flag, we should get loopback audio and fake video.
This change also attempts to somewhat consolidate where these settings take
place. Previously, EnumerateRawDevices did much of the loopback setup. However,
other steps around fingerprint resistance or fake devices were done in earlier
functions (EnumerateDevices and GetUserMedia). This changeset moves the loopback
setup so that it's more consolidated with the other setup code in these
functions.
MozReview-Commit-ID: FF0bR0Nyws9
--HG--
extra : rebase_source : 374a6fd0842a430e27c695bcf956e2e072a77fc3
2018-02-13 00:56:26 +03:00
|
|
|
// the requested device is not fake and thus the assert will pass. However,
|
2018-07-16 12:30:46 +03:00
|
|
|
// if the device is fake, aVideoInputType == MediaSourceEnum::Camera will be
|
Bug 1436523 - Rework media manager enumeration to prefer loopback to fake devices, allow mixing of fake and loopback. r=achronop
Change the media manager so that if fake and loopback devices are requested,
loopback is preferred. With this change loopback and fake devices can also be
mixed. Since the fake flag is coarse, and does not specify fake audio or video,
we would previously just make everything fake. As loopback sets flags for video
and audio separately, we can now request a single loopback device, while also
setting the fake flag to get a mix. E.g. if we request a loopback audio device,
and set the fake flag, we should get loopback audio and fake video.
This change also attempts to somewhat consolidate where these settings take
place. Previously, EnumerateRawDevices did much of the loopback setup. However,
other steps around fingerprint resistance or fake devices were done in earlier
functions (EnumerateDevices and GetUserMedia). This changeset moves the loopback
setup so that it's more consolidated with the other setup code in these
functions.
MozReview-Commit-ID: FF0bR0Nyws9
--HG--
extra : rebase_source : 374a6fd0842a430e27c695bcf956e2e072a77fc3
2018-02-13 00:56:26 +03:00
|
|
|
// checked as well, ensuring that fake devices are of the camera type.
|
2018-07-16 12:30:46 +03:00
|
|
|
MOZ_ASSERT(aVideoInputEnumType != DeviceEnumerationType::Fake ||
|
|
|
|
aVideoInputType == MediaSourceEnum::Camera,
|
Bug 1436523 - Rework media manager enumeration to prefer loopback to fake devices, allow mixing of fake and loopback. r=achronop
Change the media manager so that if fake and loopback devices are requested,
loopback is preferred. With this change loopback and fake devices can also be
mixed. Since the fake flag is coarse, and does not specify fake audio or video,
we would previously just make everything fake. As loopback sets flags for video
and audio separately, we can now request a single loopback device, while also
setting the fake flag to get a mix. E.g. if we request a loopback audio device,
and set the fake flag, we should get loopback audio and fake video.
This change also attempts to somewhat consolidate where these settings take
place. Previously, EnumerateRawDevices did much of the loopback setup. However,
other steps around fingerprint resistance or fake devices were done in earlier
functions (EnumerateDevices and GetUserMedia). This changeset moves the loopback
setup so that it's more consolidated with the other setup code in these
functions.
MozReview-Commit-ID: FF0bR0Nyws9
--HG--
extra : rebase_source : 374a6fd0842a430e27c695bcf956e2e072a77fc3
2018-02-13 00:56:26 +03:00
|
|
|
"If fake cams are requested video type should be camera!");
|
2018-07-16 12:30:46 +03:00
|
|
|
MOZ_ASSERT(aVideoInputEnumType != DeviceEnumerationType::Loopback ||
|
|
|
|
aVideoInputType == MediaSourceEnum::Camera,
|
Bug 1436523 - Rework media manager enumeration to prefer loopback to fake devices, allow mixing of fake and loopback. r=achronop
Change the media manager so that if fake and loopback devices are requested,
loopback is preferred. With this change loopback and fake devices can also be
mixed. Since the fake flag is coarse, and does not specify fake audio or video,
we would previously just make everything fake. As loopback sets flags for video
and audio separately, we can now request a single loopback device, while also
setting the fake flag to get a mix. E.g. if we request a loopback audio device,
and set the fake flag, we should get loopback audio and fake video.
This change also attempts to somewhat consolidate where these settings take
place. Previously, EnumerateRawDevices did much of the loopback setup. However,
other steps around fingerprint resistance or fake devices were done in earlier
functions (EnumerateDevices and GetUserMedia). This changeset moves the loopback
setup so that it's more consolidated with the other setup code in these
functions.
MozReview-Commit-ID: FF0bR0Nyws9
--HG--
extra : rebase_source : 374a6fd0842a430e27c695bcf956e2e072a77fc3
2018-02-13 00:56:26 +03:00
|
|
|
"If loopback video is requested video type should be camera!");
|
2018-07-16 12:30:46 +03:00
|
|
|
MOZ_ASSERT(aAudioInputEnumType != DeviceEnumerationType::Fake ||
|
|
|
|
aAudioInputType == MediaSourceEnum::Microphone,
|
Bug 1436523 - Rework media manager enumeration to prefer loopback to fake devices, allow mixing of fake and loopback. r=achronop
Change the media manager so that if fake and loopback devices are requested,
loopback is preferred. With this change loopback and fake devices can also be
mixed. Since the fake flag is coarse, and does not specify fake audio or video,
we would previously just make everything fake. As loopback sets flags for video
and audio separately, we can now request a single loopback device, while also
setting the fake flag to get a mix. E.g. if we request a loopback audio device,
and set the fake flag, we should get loopback audio and fake video.
This change also attempts to somewhat consolidate where these settings take
place. Previously, EnumerateRawDevices did much of the loopback setup. However,
other steps around fingerprint resistance or fake devices were done in earlier
functions (EnumerateDevices and GetUserMedia). This changeset moves the loopback
setup so that it's more consolidated with the other setup code in these
functions.
MozReview-Commit-ID: FF0bR0Nyws9
--HG--
extra : rebase_source : 374a6fd0842a430e27c695bcf956e2e072a77fc3
2018-02-13 00:56:26 +03:00
|
|
|
"If fake mics are requested audio type should be microphone!");
|
2018-07-16 12:30:46 +03:00
|
|
|
MOZ_ASSERT(aAudioInputEnumType != DeviceEnumerationType::Loopback ||
|
|
|
|
aAudioInputType == MediaSourceEnum::Microphone,
|
Bug 1436523 - Rework media manager enumeration to prefer loopback to fake devices, allow mixing of fake and loopback. r=achronop
Change the media manager so that if fake and loopback devices are requested,
loopback is preferred. With this change loopback and fake devices can also be
mixed. Since the fake flag is coarse, and does not specify fake audio or video,
we would previously just make everything fake. As loopback sets flags for video
and audio separately, we can now request a single loopback device, while also
setting the fake flag to get a mix. E.g. if we request a loopback audio device,
and set the fake flag, we should get loopback audio and fake video.
This change also attempts to somewhat consolidate where these settings take
place. Previously, EnumerateRawDevices did much of the loopback setup. However,
other steps around fingerprint resistance or fake devices were done in earlier
functions (EnumerateDevices and GetUserMedia). This changeset moves the loopback
setup so that it's more consolidated with the other setup code in these
functions.
MozReview-Commit-ID: FF0bR0Nyws9
--HG--
extra : rebase_source : 374a6fd0842a430e27c695bcf956e2e072a77fc3
2018-02-13 00:56:26 +03:00
|
|
|
"If loopback audio is requested audio type should be microphone!");
|
|
|
|
|
2018-07-16 12:30:46 +03:00
|
|
|
LOG(("%s: aWindowId=%" PRIu64 ", aVideoInputType=%" PRIu8 ", aAudioInputType=%" PRIu8
|
|
|
|
", aVideoInputEnumType=%" PRIu8 ", aAudioInputEnumType=%" PRIu8,
|
2018-03-16 22:09:26 +03:00
|
|
|
__func__, aWindowId,
|
2018-07-16 12:30:46 +03:00
|
|
|
static_cast<uint8_t>(aVideoInputType), static_cast<uint8_t>(aAudioInputType),
|
|
|
|
static_cast<uint8_t>(aVideoInputEnumType), static_cast<uint8_t>(aAudioInputEnumType)));
|
2018-09-25 20:03:50 +03:00
|
|
|
|
|
|
|
auto holder = MakeUnique<MozPromiseHolder<MediaDeviceSetPromise>>();
|
|
|
|
RefPtr<MediaDeviceSetPromise> promise = holder->Ensure(__func__);
|
2015-06-18 18:46:36 +03:00
|
|
|
|
2018-07-16 12:30:46 +03:00
|
|
|
bool hasVideo = aVideoInputType != MediaSourceEnum::Other;
|
|
|
|
bool hasAudio = aAudioInputType != MediaSourceEnum::Other;
|
|
|
|
bool hasAudioOutput = aAudioOutputType == MediaSinkEnum::Speaker;
|
Bug 1436523 - Rework media manager enumeration to prefer loopback to fake devices, allow mixing of fake and loopback. r=achronop
Change the media manager so that if fake and loopback devices are requested,
loopback is preferred. With this change loopback and fake devices can also be
mixed. Since the fake flag is coarse, and does not specify fake audio or video,
we would previously just make everything fake. As loopback sets flags for video
and audio separately, we can now request a single loopback device, while also
setting the fake flag to get a mix. E.g. if we request a loopback audio device,
and set the fake flag, we should get loopback audio and fake video.
This change also attempts to somewhat consolidate where these settings take
place. Previously, EnumerateRawDevices did much of the loopback setup. However,
other steps around fingerprint resistance or fake devices were done in earlier
functions (EnumerateDevices and GetUserMedia). This changeset moves the loopback
setup so that it's more consolidated with the other setup code in these
functions.
MozReview-Commit-ID: FF0bR0Nyws9
--HG--
extra : rebase_source : 374a6fd0842a430e27c695bcf956e2e072a77fc3
2018-02-13 00:56:26 +03:00
|
|
|
|
2018-07-16 12:30:46 +03:00
|
|
|
// True of at least one of video input or audio input is a fake device
|
|
|
|
bool fakeDeviceRequested = (aVideoInputEnumType == DeviceEnumerationType::Fake && hasVideo) ||
|
|
|
|
(aAudioInputEnumType == DeviceEnumerationType::Fake && hasAudio);
|
|
|
|
// True if at least one of video input or audio input is a real device
|
|
|
|
// or there is audio output.
|
|
|
|
bool realDeviceRequested = (aVideoInputEnumType != DeviceEnumerationType::Fake && hasVideo) ||
|
|
|
|
(aAudioInputEnumType != DeviceEnumerationType::Fake && hasAudio) ||
|
|
|
|
hasAudioOutput;
|
Bug 1436523 - Rework media manager enumeration to prefer loopback to fake devices, allow mixing of fake and loopback. r=achronop
Change the media manager so that if fake and loopback devices are requested,
loopback is preferred. With this change loopback and fake devices can also be
mixed. Since the fake flag is coarse, and does not specify fake audio or video,
we would previously just make everything fake. As loopback sets flags for video
and audio separately, we can now request a single loopback device, while also
setting the fake flag to get a mix. E.g. if we request a loopback audio device,
and set the fake flag, we should get loopback audio and fake video.
This change also attempts to somewhat consolidate where these settings take
place. Previously, EnumerateRawDevices did much of the loopback setup. However,
other steps around fingerprint resistance or fake devices were done in earlier
functions (EnumerateDevices and GetUserMedia). This changeset moves the loopback
setup so that it's more consolidated with the other setup code in these
functions.
MozReview-Commit-ID: FF0bR0Nyws9
--HG--
extra : rebase_source : 374a6fd0842a430e27c695bcf956e2e072a77fc3
2018-02-13 00:56:26 +03:00
|
|
|
|
|
|
|
nsAutoCString videoLoopDev, audioLoopDev;
|
2018-07-16 12:30:46 +03:00
|
|
|
if (hasVideo && aVideoInputEnumType == DeviceEnumerationType::Loopback) {
|
Bug 1436523 - Rework media manager enumeration to prefer loopback to fake devices, allow mixing of fake and loopback. r=achronop
Change the media manager so that if fake and loopback devices are requested,
loopback is preferred. With this change loopback and fake devices can also be
mixed. Since the fake flag is coarse, and does not specify fake audio or video,
we would previously just make everything fake. As loopback sets flags for video
and audio separately, we can now request a single loopback device, while also
setting the fake flag to get a mix. E.g. if we request a loopback audio device,
and set the fake flag, we should get loopback audio and fake video.
This change also attempts to somewhat consolidate where these settings take
place. Previously, EnumerateRawDevices did much of the loopback setup. However,
other steps around fingerprint resistance or fake devices were done in earlier
functions (EnumerateDevices and GetUserMedia). This changeset moves the loopback
setup so that it's more consolidated with the other setup code in these
functions.
MozReview-Commit-ID: FF0bR0Nyws9
--HG--
extra : rebase_source : 374a6fd0842a430e27c695bcf956e2e072a77fc3
2018-02-13 00:56:26 +03:00
|
|
|
Preferences::GetCString("media.video_loopback_dev", videoLoopDev);
|
|
|
|
}
|
2018-07-16 12:30:46 +03:00
|
|
|
if (hasAudio && aAudioInputEnumType == DeviceEnumerationType::Loopback) {
|
Bug 1436523 - Rework media manager enumeration to prefer loopback to fake devices, allow mixing of fake and loopback. r=achronop
Change the media manager so that if fake and loopback devices are requested,
loopback is preferred. With this change loopback and fake devices can also be
mixed. Since the fake flag is coarse, and does not specify fake audio or video,
we would previously just make everything fake. As loopback sets flags for video
and audio separately, we can now request a single loopback device, while also
setting the fake flag to get a mix. E.g. if we request a loopback audio device,
and set the fake flag, we should get loopback audio and fake video.
This change also attempts to somewhat consolidate where these settings take
place. Previously, EnumerateRawDevices did much of the loopback setup. However,
other steps around fingerprint resistance or fake devices were done in earlier
functions (EnumerateDevices and GetUserMedia). This changeset moves the loopback
setup so that it's more consolidated with the other setup code in these
functions.
MozReview-Commit-ID: FF0bR0Nyws9
--HG--
extra : rebase_source : 374a6fd0842a430e27c695bcf956e2e072a77fc3
2018-02-13 00:56:26 +03:00
|
|
|
Preferences::GetCString("media.audio_loopback_dev", audioLoopDev);
|
|
|
|
}
|
|
|
|
|
2018-09-25 20:03:50 +03:00
|
|
|
RefPtr<Runnable> task = NewTaskFrom([holder = std::move(holder), aWindowId, aVideoInputType,
|
|
|
|
aAudioInputType, aVideoInputEnumType, aAudioInputEnumType,
|
Bug 1436523 - Rework media manager enumeration to prefer loopback to fake devices, allow mixing of fake and loopback. r=achronop
Change the media manager so that if fake and loopback devices are requested,
loopback is preferred. With this change loopback and fake devices can also be
mixed. Since the fake flag is coarse, and does not specify fake audio or video,
we would previously just make everything fake. As loopback sets flags for video
and audio separately, we can now request a single loopback device, while also
setting the fake flag to get a mix. E.g. if we request a loopback audio device,
and set the fake flag, we should get loopback audio and fake video.
This change also attempts to somewhat consolidate where these settings take
place. Previously, EnumerateRawDevices did much of the loopback setup. However,
other steps around fingerprint resistance or fake devices were done in earlier
functions (EnumerateDevices and GetUserMedia). This changeset moves the loopback
setup so that it's more consolidated with the other setup code in these
functions.
MozReview-Commit-ID: FF0bR0Nyws9
--HG--
extra : rebase_source : 374a6fd0842a430e27c695bcf956e2e072a77fc3
2018-02-13 00:56:26 +03:00
|
|
|
videoLoopDev, audioLoopDev,
|
2018-07-16 12:30:46 +03:00
|
|
|
hasVideo, hasAudio, hasAudioOutput,
|
|
|
|
fakeDeviceRequested, realDeviceRequested]() {
|
2015-12-03 06:51:03 +03:00
|
|
|
// Only enumerate what's asked for, and only fake cams and mics.
|
|
|
|
RefPtr<MediaEngine> fakeBackend, realBackend;
|
Bug 1436523 - Rework media manager enumeration to prefer loopback to fake devices, allow mixing of fake and loopback. r=achronop
Change the media manager so that if fake and loopback devices are requested,
loopback is preferred. With this change loopback and fake devices can also be
mixed. Since the fake flag is coarse, and does not specify fake audio or video,
we would previously just make everything fake. As loopback sets flags for video
and audio separately, we can now request a single loopback device, while also
setting the fake flag to get a mix. E.g. if we request a loopback audio device,
and set the fake flag, we should get loopback audio and fake video.
This change also attempts to somewhat consolidate where these settings take
place. Previously, EnumerateRawDevices did much of the loopback setup. However,
other steps around fingerprint resistance or fake devices were done in earlier
functions (EnumerateDevices and GetUserMedia). This changeset moves the loopback
setup so that it's more consolidated with the other setup code in these
functions.
MozReview-Commit-ID: FF0bR0Nyws9
--HG--
extra : rebase_source : 374a6fd0842a430e27c695bcf956e2e072a77fc3
2018-02-13 00:56:26 +03:00
|
|
|
if (fakeDeviceRequested) {
|
2016-07-12 02:27:43 +03:00
|
|
|
fakeBackend = new MediaEngineDefault();
|
2015-12-03 06:51:03 +03:00
|
|
|
}
|
Bug 1436523 - Rework media manager enumeration to prefer loopback to fake devices, allow mixing of fake and loopback. r=achronop
Change the media manager so that if fake and loopback devices are requested,
loopback is preferred. With this change loopback and fake devices can also be
mixed. Since the fake flag is coarse, and does not specify fake audio or video,
we would previously just make everything fake. As loopback sets flags for video
and audio separately, we can now request a single loopback device, while also
setting the fake flag to get a mix. E.g. if we request a loopback audio device,
and set the fake flag, we should get loopback audio and fake video.
This change also attempts to somewhat consolidate where these settings take
place. Previously, EnumerateRawDevices did much of the loopback setup. However,
other steps around fingerprint resistance or fake devices were done in earlier
functions (EnumerateDevices and GetUserMedia). This changeset moves the loopback
setup so that it's more consolidated with the other setup code in these
functions.
MozReview-Commit-ID: FF0bR0Nyws9
--HG--
extra : rebase_source : 374a6fd0842a430e27c695bcf956e2e072a77fc3
2018-02-13 00:56:26 +03:00
|
|
|
if (realDeviceRequested) {
|
2017-09-29 22:06:51 +03:00
|
|
|
MediaManager* manager = MediaManager::GetIfExists();
|
|
|
|
MOZ_RELEASE_ASSERT(manager); // Must exist while media thread is alive
|
2015-12-03 06:51:03 +03:00
|
|
|
realBackend = manager->GetBackend(aWindowId);
|
2015-06-18 18:46:36 +03:00
|
|
|
}
|
2014-09-24 19:17:33 +04:00
|
|
|
|
2018-09-25 20:03:50 +03:00
|
|
|
auto result = MakeRefPtr<MediaDeviceSetRefCnt>(new MediaDeviceSet);
|
2015-07-03 01:01:52 +03:00
|
|
|
|
2015-12-03 06:51:03 +03:00
|
|
|
if (hasVideo) {
|
2018-07-16 12:30:46 +03:00
|
|
|
MediaDeviceSet videos;
|
2018-03-16 22:09:26 +03:00
|
|
|
LOG(("EnumerateRawDevices Task: Getting video sources with %s backend",
|
2018-07-16 12:30:46 +03:00
|
|
|
aVideoInputEnumType == DeviceEnumerationType::Fake ? "fake" : "real"));
|
|
|
|
GetMediaDevices(aVideoInputEnumType == DeviceEnumerationType::Fake ? fakeBackend : realBackend,
|
|
|
|
aWindowId, aVideoInputType, videos, videoLoopDev.get());
|
2018-09-25 20:03:50 +03:00
|
|
|
(*result)->AppendElements(videos);
|
2014-04-18 23:16:08 +04:00
|
|
|
}
|
2015-12-03 06:51:03 +03:00
|
|
|
if (hasAudio) {
|
2018-07-16 12:30:46 +03:00
|
|
|
MediaDeviceSet audios;
|
2018-03-16 22:09:26 +03:00
|
|
|
LOG(("EnumerateRawDevices Task: Getting audio sources with %s backend",
|
2018-07-16 12:30:46 +03:00
|
|
|
aAudioInputEnumType == DeviceEnumerationType::Fake ? "fake" : "real"));
|
|
|
|
GetMediaDevices(aAudioInputEnumType == DeviceEnumerationType::Fake ? fakeBackend : realBackend,
|
|
|
|
aWindowId, aAudioInputType, audios, audioLoopDev.get());
|
2018-09-25 20:03:50 +03:00
|
|
|
(*result)->AppendElements(audios);
|
2018-07-16 12:30:46 +03:00
|
|
|
}
|
2018-07-16 12:30:46 +03:00
|
|
|
if (hasAudioOutput) {
|
2018-07-16 12:30:46 +03:00
|
|
|
MediaDeviceSet outputs;
|
2018-07-16 12:30:46 +03:00
|
|
|
MOZ_ASSERT(realBackend);
|
|
|
|
realBackend->EnumerateDevices(aWindowId,
|
|
|
|
MediaSourceEnum::Other,
|
|
|
|
MediaSinkEnum::Speaker,
|
|
|
|
&outputs);
|
2018-09-25 20:03:50 +03:00
|
|
|
(*result)->AppendElements(outputs);
|
2018-07-16 12:30:46 +03:00
|
|
|
}
|
|
|
|
|
2018-09-25 20:03:50 +03:00
|
|
|
holder->Resolve(std::move(result), __func__);
|
2017-06-02 23:11:53 +03:00
|
|
|
});
|
|
|
|
|
Bug 1436523 - Rework media manager enumeration to prefer loopback to fake devices, allow mixing of fake and loopback. r=achronop
Change the media manager so that if fake and loopback devices are requested,
loopback is preferred. With this change loopback and fake devices can also be
mixed. Since the fake flag is coarse, and does not specify fake audio or video,
we would previously just make everything fake. As loopback sets flags for video
and audio separately, we can now request a single loopback device, while also
setting the fake flag to get a mix. E.g. if we request a loopback audio device,
and set the fake flag, we should get loopback audio and fake video.
This change also attempts to somewhat consolidate where these settings take
place. Previously, EnumerateRawDevices did much of the loopback setup. However,
other steps around fingerprint resistance or fake devices were done in earlier
functions (EnumerateDevices and GetUserMedia). This changeset moves the loopback
setup so that it's more consolidated with the other setup code in these
functions.
MozReview-Commit-ID: FF0bR0Nyws9
--HG--
extra : rebase_source : 374a6fd0842a430e27c695bcf956e2e072a77fc3
2018-02-13 00:56:26 +03:00
|
|
|
if (realDeviceRequested &&
|
2017-06-02 23:11:53 +03:00
|
|
|
Preferences::GetBool("media.navigator.permission.device", false)) {
|
|
|
|
// Need to ask permission to retrieve list of all devices;
|
|
|
|
// notify frontend observer and wait for callback notification to post task.
|
|
|
|
const char16_t* const type =
|
2018-07-16 12:30:46 +03:00
|
|
|
(aVideoInputType != MediaSourceEnum::Camera) ? u"audio" :
|
|
|
|
(aAudioInputType != MediaSourceEnum::Microphone) ? u"video" :
|
|
|
|
u"all";
|
2017-06-02 23:11:53 +03:00
|
|
|
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
|
|
|
obs->NotifyObservers(static_cast<nsIRunnable*>(task),
|
|
|
|
"getUserMedia:ask-device-permission",
|
|
|
|
type);
|
|
|
|
} else {
|
|
|
|
// Don't need to ask permission to retrieve list of all devices;
|
|
|
|
// post the retrieval task immediately.
|
|
|
|
MediaManager::PostTask(task.forget());
|
|
|
|
}
|
|
|
|
|
2018-09-25 20:03:50 +03:00
|
|
|
return promise;
|
2015-06-18 18:46:36 +03:00
|
|
|
}
|
2012-06-03 11:35:15 +04:00
|
|
|
|
2013-03-05 01:02:17 +04:00
|
|
|
MediaManager::MediaManager()
|
|
|
|
: mMediaThread(nullptr)
|
|
|
|
, mBackend(nullptr) {
|
2016-01-23 00:46:38 +03:00
|
|
|
mPrefs.mFreq = 1000; // 1KHz test tone
|
|
|
|
mPrefs.mWidth = 0; // adaptive default
|
|
|
|
mPrefs.mHeight = 0; // adaptive default
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
mPrefs.mFPS = MediaEnginePrefs::DEFAULT_VIDEO_FPS;
|
2016-01-23 00:46:38 +03:00
|
|
|
mPrefs.mAecOn = false;
|
|
|
|
mPrefs.mAgcOn = false;
|
|
|
|
mPrefs.mNoiseOn = false;
|
2016-04-20 03:20:45 +03:00
|
|
|
mPrefs.mExtendedFilter = true;
|
|
|
|
mPrefs.mDelayAgnostic = true;
|
2016-08-09 11:37:04 +03:00
|
|
|
mPrefs.mFakeDeviceChangeEventOn = false;
|
2016-01-23 00:46:38 +03:00
|
|
|
#ifdef MOZ_WEBRTC
|
|
|
|
mPrefs.mAec = webrtc::kEcUnchanged;
|
|
|
|
mPrefs.mAgc = webrtc::kAgcUnchanged;
|
|
|
|
mPrefs.mNoise = webrtc::kNsUnchanged;
|
|
|
|
#else
|
|
|
|
mPrefs.mAec = 0;
|
|
|
|
mPrefs.mAgc = 0;
|
|
|
|
mPrefs.mNoise = 0;
|
|
|
|
#endif
|
2016-01-21 19:51:36 +03:00
|
|
|
mPrefs.mFullDuplex = false;
|
2017-06-30 07:01:17 +03:00
|
|
|
mPrefs.mChannels = 0; // max channels default
|
2013-03-05 01:02:17 +04:00
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIPrefService> prefs = do_GetService("@mozilla.org/preferences-service;1", &rv);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(prefs);
|
|
|
|
if (branch) {
|
|
|
|
GetPrefs(branch, nullptr);
|
|
|
|
}
|
|
|
|
}
|
2017-10-26 19:37:16 +03:00
|
|
|
LOG(("%s: default prefs: %dx%d @%dfps, %dHz test tones, aec: %s,"
|
2016-01-23 00:46:38 +03:00
|
|
|
"agc: %s, noise: %s, aec level: %d, agc level: %d, noise level: %d,"
|
2017-11-17 06:57:07 +03:00
|
|
|
"%sfull_duplex, extended aec %s, delay_agnostic %s "
|
2017-06-30 07:01:17 +03:00
|
|
|
"channels %d",
|
2016-04-20 03:20:45 +03:00
|
|
|
__FUNCTION__, mPrefs.mWidth, mPrefs.mHeight,
|
2017-10-26 19:37:16 +03:00
|
|
|
mPrefs.mFPS, mPrefs.mFreq, mPrefs.mAecOn ? "on" : "off",
|
2016-01-23 00:46:38 +03:00
|
|
|
mPrefs.mAgcOn ? "on": "off", mPrefs.mNoiseOn ? "on": "off", mPrefs.mAec,
|
2017-11-17 06:57:07 +03:00
|
|
|
mPrefs.mAgc, mPrefs.mNoise, mPrefs.mFullDuplex ? "" : "not ",
|
2017-06-30 07:01:17 +03:00
|
|
|
mPrefs.mExtendedFilter ? "on" : "off", mPrefs.mDelayAgnostic ? "on" : "off",
|
|
|
|
mPrefs.mChannels));
|
2013-03-05 01:02:17 +04:00
|
|
|
}
|
|
|
|
|
2014-04-27 11:06:00 +04:00
|
|
|
NS_IMPL_ISUPPORTS(MediaManager, nsIMediaManagerService, nsIObserver)
|
2012-06-03 11:35:15 +04:00
|
|
|
|
2012-12-22 12:09:36 +04:00
|
|
|
/* static */ StaticRefPtr<MediaManager> MediaManager::sSingleton;
|
|
|
|
|
2015-03-03 17:51:05 +03:00
|
|
|
#ifdef DEBUG
|
|
|
|
/* static */ bool
|
|
|
|
MediaManager::IsInMediaThread()
|
|
|
|
{
|
|
|
|
return sSingleton?
|
|
|
|
(sSingleton->mMediaThread->thread_id() == PlatformThread::CurrentId()) :
|
|
|
|
false;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-03-20 00:31:40 +03:00
|
|
|
#ifdef XP_WIN
|
|
|
|
class MTAThread : public base::Thread {
|
|
|
|
public:
|
|
|
|
explicit MTAThread(const char* aName)
|
|
|
|
: base::Thread(aName)
|
|
|
|
, mResult(E_FAIL)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual void Init() override {
|
|
|
|
mResult = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void CleanUp() override {
|
|
|
|
if (SUCCEEDED(mResult)) {
|
|
|
|
CoUninitialize();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
HRESULT mResult;
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
2013-03-05 01:02:17 +04:00
|
|
|
// NOTE: never Dispatch(....,NS_DISPATCH_SYNC) to the MediaManager
|
|
|
|
// thread from the MainThread, as we NS_DISPATCH_SYNC to MainThread
|
|
|
|
// from MediaManager thread.
|
2015-09-04 02:09:34 +03:00
|
|
|
|
|
|
|
// Guaranteed never to return nullptr.
|
2013-03-05 01:02:17 +04:00
|
|
|
/* static */ MediaManager*
|
|
|
|
MediaManager::Get() {
|
|
|
|
if (!sSingleton) {
|
2015-09-30 09:08:22 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-03-08 00:44:25 +03:00
|
|
|
|
2015-03-20 01:43:25 +03:00
|
|
|
static int timesCreated = 0;
|
|
|
|
timesCreated++;
|
2016-03-08 00:44:25 +03:00
|
|
|
MOZ_RELEASE_ASSERT(timesCreated == 1);
|
|
|
|
|
2013-03-05 01:02:17 +04:00
|
|
|
sSingleton = new MediaManager();
|
|
|
|
|
2018-03-20 00:31:40 +03:00
|
|
|
#ifdef XP_WIN
|
|
|
|
sSingleton->mMediaThread = new MTAThread("MediaManager");
|
|
|
|
#else
|
2014-09-12 18:49:39 +04:00
|
|
|
sSingleton->mMediaThread = new base::Thread("MediaManager");
|
2018-03-20 00:31:40 +03:00
|
|
|
#endif
|
2014-09-12 18:49:39 +04:00
|
|
|
base::Thread::Options options;
|
|
|
|
#if defined(_WIN32)
|
|
|
|
options.message_loop_type = MessageLoop::TYPE_MOZILLA_NONMAINUITHREAD;
|
|
|
|
#else
|
|
|
|
options.message_loop_type = MessageLoop::TYPE_MOZILLA_NONMAINTHREAD;
|
|
|
|
#endif
|
|
|
|
if (!sSingleton->mMediaThread->StartWithOptions(options)) {
|
|
|
|
MOZ_CRASH();
|
|
|
|
}
|
|
|
|
|
2013-03-05 01:02:17 +04:00
|
|
|
LOG(("New Media thread for gum"));
|
|
|
|
|
|
|
|
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
|
|
|
if (obs) {
|
2015-07-13 06:55:02 +03:00
|
|
|
obs->AddObserver(sSingleton, "last-pb-context-exited", false);
|
2017-06-02 23:11:53 +03:00
|
|
|
obs->AddObserver(sSingleton, "getUserMedia:got-device-permission", false);
|
2015-07-03 01:01:52 +03:00
|
|
|
obs->AddObserver(sSingleton, "getUserMedia:privileged:allow", false);
|
2013-03-05 01:02:17 +04:00
|
|
|
obs->AddObserver(sSingleton, "getUserMedia:response:allow", false);
|
|
|
|
obs->AddObserver(sSingleton, "getUserMedia:response:deny", false);
|
2018-10-10 11:28:41 +03:00
|
|
|
obs->AddObserver(sSingleton, "getUserMedia:response:noOSPermission", false);
|
2013-03-05 01:02:17 +04:00
|
|
|
obs->AddObserver(sSingleton, "getUserMedia:revoke", false);
|
|
|
|
}
|
|
|
|
// else MediaManager won't work properly and will leak (see bug 837874)
|
|
|
|
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
|
|
|
if (prefs) {
|
|
|
|
prefs->AddObserver("media.navigator.video.default_width", sSingleton, false);
|
|
|
|
prefs->AddObserver("media.navigator.video.default_height", sSingleton, false);
|
|
|
|
prefs->AddObserver("media.navigator.video.default_fps", sSingleton, false);
|
2016-01-21 19:51:36 +03:00
|
|
|
prefs->AddObserver("media.navigator.audio.fake_frequency", sSingleton, false);
|
|
|
|
prefs->AddObserver("media.navigator.audio.full_duplex", sSingleton, false);
|
2016-01-23 00:46:38 +03:00
|
|
|
#ifdef MOZ_WEBRTC
|
|
|
|
prefs->AddObserver("media.getusermedia.aec_enabled", sSingleton, false);
|
|
|
|
prefs->AddObserver("media.getusermedia.aec", sSingleton, false);
|
|
|
|
prefs->AddObserver("media.getusermedia.agc_enabled", sSingleton, false);
|
|
|
|
prefs->AddObserver("media.getusermedia.agc", sSingleton, false);
|
|
|
|
prefs->AddObserver("media.getusermedia.noise_enabled", sSingleton, false);
|
|
|
|
prefs->AddObserver("media.getusermedia.noise", sSingleton, false);
|
2016-08-09 11:37:04 +03:00
|
|
|
prefs->AddObserver("media.ondevicechange.fakeDeviceChangeEvent.enabled", sSingleton, false);
|
2017-06-30 07:01:17 +03:00
|
|
|
prefs->AddObserver("media.getusermedia.channels", sSingleton, false);
|
2016-01-23 00:46:38 +03:00
|
|
|
#endif
|
2013-03-05 01:02:17 +04:00
|
|
|
}
|
2015-10-15 06:54:39 +03:00
|
|
|
|
|
|
|
// Prepare async shutdown
|
|
|
|
|
2015-11-18 23:42:16 +03:00
|
|
|
nsCOMPtr<nsIAsyncShutdownClient> shutdownPhase = GetShutdownPhase();
|
2015-10-15 06:54:39 +03:00
|
|
|
|
|
|
|
class Blocker : public media::ShutdownBlocker
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
Blocker()
|
|
|
|
: media::ShutdownBlocker(NS_LITERAL_STRING(
|
|
|
|
"Media shutdown: blocking on media thread")) {}
|
|
|
|
|
2015-11-18 23:42:16 +03:00
|
|
|
NS_IMETHOD BlockShutdown(nsIAsyncShutdownClient*) override
|
2015-10-15 06:54:39 +03:00
|
|
|
{
|
|
|
|
MOZ_RELEASE_ASSERT(MediaManager::GetIfExists());
|
|
|
|
MediaManager::GetIfExists()->Shutdown();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
sSingleton->mShutdownBlocker = new Blocker();
|
2015-11-18 23:42:16 +03:00
|
|
|
nsresult rv = shutdownPhase->AddBlocker(sSingleton->mShutdownBlocker,
|
|
|
|
NS_LITERAL_STRING(__FILE__),
|
|
|
|
__LINE__,
|
|
|
|
NS_LITERAL_STRING("Media shutdown"));
|
2015-10-15 06:54:39 +03:00
|
|
|
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
|
2013-03-05 01:02:17 +04:00
|
|
|
}
|
|
|
|
return sSingleton;
|
|
|
|
}
|
|
|
|
|
2015-03-20 01:43:25 +03:00
|
|
|
/* static */ MediaManager*
|
|
|
|
MediaManager::GetIfExists() {
|
|
|
|
return sSingleton;
|
|
|
|
}
|
|
|
|
|
2012-12-22 12:09:36 +04:00
|
|
|
/* static */ already_AddRefed<MediaManager>
|
|
|
|
MediaManager::GetInstance()
|
|
|
|
{
|
|
|
|
// so we can have non-refcounted getters
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<MediaManager> service = MediaManager::Get();
|
2012-12-22 12:09:36 +04:00
|
|
|
return service.forget();
|
|
|
|
}
|
2012-06-03 11:35:15 +04:00
|
|
|
|
2015-06-18 18:46:36 +03:00
|
|
|
media::Parent<media::NonE10s>*
|
|
|
|
MediaManager::GetNonE10sParent()
|
|
|
|
{
|
|
|
|
if (!mNonE10sParent) {
|
2016-11-01 14:44:02 +03:00
|
|
|
mNonE10sParent = new media::Parent<media::NonE10s>();
|
2015-06-18 18:46:36 +03:00
|
|
|
}
|
2016-11-01 14:44:02 +03:00
|
|
|
return mNonE10sParent;
|
2015-06-18 18:46:36 +03:00
|
|
|
}
|
|
|
|
|
2016-01-07 22:57:42 +03:00
|
|
|
/* static */ void
|
|
|
|
MediaManager::StartupInit()
|
|
|
|
{
|
|
|
|
#ifdef WIN32
|
2017-01-08 11:18:22 +03:00
|
|
|
if (!IsWin8OrLater()) {
|
2016-01-07 22:57:42 +03:00
|
|
|
// Bug 1107702 - Older Windows fail in GetAdaptersInfo (and others) if the
|
|
|
|
// first(?) call occurs after the process size is over 2GB (kb/2588507).
|
|
|
|
// Attempt to 'prime' the pump by making a call at startup.
|
|
|
|
unsigned long out_buf_len = sizeof(IP_ADAPTER_INFO);
|
|
|
|
PIP_ADAPTER_INFO pAdapterInfo = (IP_ADAPTER_INFO *) moz_xmalloc(out_buf_len);
|
|
|
|
if (GetAdaptersInfo(pAdapterInfo, &out_buf_len) == ERROR_BUFFER_OVERFLOW) {
|
|
|
|
free(pAdapterInfo);
|
|
|
|
pAdapterInfo = (IP_ADAPTER_INFO *) moz_xmalloc(out_buf_len);
|
|
|
|
GetAdaptersInfo(pAdapterInfo, &out_buf_len);
|
|
|
|
}
|
|
|
|
if (pAdapterInfo) {
|
|
|
|
free(pAdapterInfo);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2014-09-12 18:49:39 +04:00
|
|
|
/* static */
|
2015-05-29 21:28:03 +03:00
|
|
|
void
|
2016-04-28 03:06:05 +03:00
|
|
|
MediaManager::PostTask(already_AddRefed<Runnable> task)
|
2014-09-12 18:49:39 +04:00
|
|
|
{
|
2017-11-02 18:27:33 +03:00
|
|
|
if (sHasShutdown) {
|
2015-05-29 21:28:03 +03:00
|
|
|
// Can't safely delete task here since it may have items with specific
|
|
|
|
// thread-release requirements.
|
2016-04-28 03:06:05 +03:00
|
|
|
// XXXkhuey well then who is supposed to delete it?! We don't signal
|
|
|
|
// that we failed ...
|
|
|
|
MOZ_CRASH();
|
2015-05-29 21:28:03 +03:00
|
|
|
return;
|
|
|
|
}
|
2014-09-12 18:49:39 +04:00
|
|
|
NS_ASSERTION(Get(), "MediaManager singleton?");
|
|
|
|
NS_ASSERTION(Get()->mMediaThread, "No thread yet");
|
2018-05-30 22:15:35 +03:00
|
|
|
Get()->mMediaThread->message_loop()->PostTask(std::move(task));
|
2014-09-12 18:49:39 +04:00
|
|
|
}
|
|
|
|
|
2018-02-15 17:18:12 +03:00
|
|
|
template<typename MozPromiseType, typename FunctionType>
|
|
|
|
/* static */ RefPtr<MozPromiseType>
|
|
|
|
MediaManager::PostTask(const char* aName, FunctionType&& aFunction)
|
|
|
|
{
|
|
|
|
MozPromiseHolder<MozPromiseType> holder;
|
|
|
|
RefPtr<MozPromiseType> promise = holder.Ensure(aName);
|
|
|
|
MediaManager::PostTask(NS_NewRunnableFunction(aName,
|
2018-06-01 19:30:30 +03:00
|
|
|
[h = std::move(holder), func = std::forward<FunctionType>(aFunction)]() mutable
|
2018-02-15 17:18:12 +03:00
|
|
|
{
|
|
|
|
func(h);
|
|
|
|
}));
|
|
|
|
return promise;
|
|
|
|
}
|
|
|
|
|
2013-11-26 10:22:16 +04:00
|
|
|
/* static */ nsresult
|
2017-11-14 13:50:07 +03:00
|
|
|
MediaManager::NotifyRecordingStatusChange(nsPIDOMWindowInner* aWindow)
|
2013-11-26 10:22:16 +04:00
|
|
|
{
|
|
|
|
NS_ENSURE_ARG(aWindow);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
|
|
|
if (!obs) {
|
|
|
|
NS_WARNING("Could not get the Observer service for GetUserMedia recording notification.");
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
|
2013-11-26 10:22:16 +04:00
|
|
|
|
2016-10-15 04:46:26 +03:00
|
|
|
nsCString pageURL;
|
|
|
|
nsCOMPtr<nsIURI> docURI = aWindow->GetDocumentURI();
|
|
|
|
NS_ENSURE_TRUE(docURI, NS_ERROR_FAILURE);
|
2013-11-26 10:22:16 +04:00
|
|
|
|
2016-10-15 04:46:26 +03:00
|
|
|
nsresult rv = docURI->GetSpec(pageURL);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2013-11-26 10:22:16 +04:00
|
|
|
|
2016-10-15 04:46:26 +03:00
|
|
|
NS_ConvertUTF8toUTF16 requestURL(pageURL);
|
2013-11-26 10:22:16 +04:00
|
|
|
|
|
|
|
props->SetPropertyAsAString(NS_LITERAL_STRING("requestURL"), requestURL);
|
|
|
|
|
|
|
|
obs->NotifyObservers(static_cast<nsIPropertyBag2*>(props),
|
2014-05-01 14:51:00 +04:00
|
|
|
"recording-device-events",
|
2017-11-14 13:50:07 +03:00
|
|
|
nullptr);
|
2013-11-26 10:22:16 +04:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2016-08-11 20:04:49 +03:00
|
|
|
int MediaManager::AddDeviceChangeCallback(DeviceChangeCallback* aCallback)
|
|
|
|
{
|
2016-08-09 11:37:04 +03:00
|
|
|
bool fakeDeviceChangeEventOn = mPrefs.mFakeDeviceChangeEventOn;
|
|
|
|
MediaManager::PostTask(NewTaskFrom([fakeDeviceChangeEventOn]() {
|
2017-09-29 22:06:51 +03:00
|
|
|
MediaManager* manager = MediaManager::GetIfExists();
|
|
|
|
MOZ_RELEASE_ASSERT(manager); // Must exist while media thread is alive
|
2017-12-06 14:09:40 +03:00
|
|
|
// this is needed in case persistent permission is given but no gUM()
|
|
|
|
// or enumeration() has created the real backend yet
|
|
|
|
manager->GetBackend(0);
|
2016-08-09 11:37:04 +03:00
|
|
|
if (fakeDeviceChangeEventOn)
|
|
|
|
manager->GetBackend(0)->SetFakeDeviceChangeEvents();
|
2016-08-11 20:04:49 +03:00
|
|
|
}));
|
|
|
|
|
|
|
|
return DeviceChangeCallback::AddDeviceChangeCallback(aCallback);
|
|
|
|
}
|
|
|
|
|
|
|
|
void MediaManager::OnDeviceChange() {
|
|
|
|
RefPtr<MediaManager> self(this);
|
2017-07-27 11:51:24 +03:00
|
|
|
NS_DispatchToMainThread(media::NewRunnableFrom([self]() mutable {
|
2016-08-11 20:04:49 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2017-11-02 18:27:33 +03:00
|
|
|
if (sHasShutdown) {
|
2017-09-14 06:16:42 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2017-07-27 11:51:24 +03:00
|
|
|
self->DeviceChangeCallback::OnDeviceChange();
|
|
|
|
|
2018-07-16 12:30:46 +03:00
|
|
|
// On some Windows machine, if we call EnumerateRawDevices immediately after receiving
|
2017-07-27 11:51:24 +03:00
|
|
|
// devicechange event, sometimes we would get outdated devices list.
|
|
|
|
PR_Sleep(PR_MillisecondsToInterval(100));
|
2018-09-25 20:03:50 +03:00
|
|
|
RefPtr<MediaDeviceSetPromise> p = self->EnumerateRawDevices(0,
|
2018-07-16 12:30:46 +03:00
|
|
|
MediaSourceEnum::Camera,
|
|
|
|
MediaSourceEnum::Microphone,
|
|
|
|
MediaSinkEnum::Speaker);
|
2018-09-25 20:03:50 +03:00
|
|
|
p->Then(GetCurrentThreadSerialEventTarget(),
|
|
|
|
__func__,
|
|
|
|
[self](RefPtr<MediaDeviceSetRefCnt>&& aDevices) mutable {
|
|
|
|
MediaManager* mgr = MediaManager::GetIfExists();
|
|
|
|
if (!mgr) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-07-27 11:51:24 +03:00
|
|
|
nsTArray<nsString> deviceIDs;
|
|
|
|
|
2018-09-25 20:03:50 +03:00
|
|
|
for (auto& device : **aDevices) {
|
2017-07-27 11:51:24 +03:00
|
|
|
nsString id;
|
|
|
|
device->GetId(id);
|
|
|
|
id.ReplaceSubstring(NS_LITERAL_STRING("default: "), NS_LITERAL_STRING(""));
|
|
|
|
if (!deviceIDs.Contains(id)) {
|
|
|
|
deviceIDs.AppendElement(id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto& id : self->mDeviceIDs) {
|
2018-02-23 17:50:57 +03:00
|
|
|
if (deviceIDs.Contains(id)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stop the coresponding SourceListener
|
|
|
|
nsGlobalWindowInner::InnerWindowByIdTable* windowsById =
|
|
|
|
nsGlobalWindowInner::GetWindowsTable();
|
|
|
|
if (!windowsById) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto iter = windowsById->Iter(); !iter.Done(); iter.Next()) {
|
|
|
|
nsGlobalWindowInner* window = iter.Data();
|
|
|
|
self->IterateWindowListeners(window->AsInner(),
|
|
|
|
[&id](GetUserMediaWindowListener* aListener)
|
|
|
|
{
|
|
|
|
aListener->StopRawID(id);
|
|
|
|
});
|
2017-07-27 11:51:24 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
self->mDeviceIDs = deviceIDs;
|
2018-09-25 20:03:50 +03:00
|
|
|
}, [](RefPtr<MediaStreamError>&& reason) {});
|
2016-08-11 20:04:49 +03:00
|
|
|
return NS_OK;
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
2015-07-03 01:01:52 +03:00
|
|
|
nsresult MediaManager::GenerateUUID(nsAString& aResult)
|
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIUUIDGenerator> uuidgen =
|
|
|
|
do_GetService("@mozilla.org/uuid-generator;1", &rv);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
// Generate a call ID.
|
|
|
|
nsID id;
|
|
|
|
rv = uuidgen->GenerateUUIDInPlace(&id);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
char buffer[NSID_LENGTH];
|
|
|
|
id.ToProvidedString(buffer);
|
|
|
|
aResult.Assign(NS_ConvertUTF8toUTF16(buffer));
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2017-10-04 12:24:35 +03:00
|
|
|
static bool IsFullyActive(nsPIDOMWindowInner* aWindow)
|
|
|
|
{
|
|
|
|
while (true) {
|
|
|
|
if (!aWindow) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
nsIDocument* document = aWindow->GetExtantDoc();
|
|
|
|
if (!document) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!document->IsCurrentActiveDocument()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
nsPIDOMWindowOuter* context = aWindow->GetOuterWindow();
|
|
|
|
if (!context) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (context->IsTopLevelWindow()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
nsCOMPtr<Element> frameElement =
|
2017-11-04 01:25:38 +03:00
|
|
|
nsGlobalWindowOuter::Cast(context)->GetRealFrameElementOuter();
|
2017-10-04 12:24:35 +03:00
|
|
|
if (!frameElement) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
aWindow = frameElement->OwnerDoc()->GetInnerWindow();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-17 15:44:50 +03:00
|
|
|
enum class GetUserMediaSecurityState {
|
|
|
|
Other = 0,
|
|
|
|
HTTPS = 1,
|
|
|
|
File = 2,
|
|
|
|
App = 3,
|
|
|
|
Localhost = 4,
|
|
|
|
Loop = 5,
|
|
|
|
Privileged = 6
|
|
|
|
};
|
|
|
|
|
2017-09-18 12:51:51 +03:00
|
|
|
/**
|
|
|
|
* This function is used in getUserMedia when privacy.resistFingerprinting is true.
|
|
|
|
* Only mediaSource of audio/video constraint will be kept.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
ReduceConstraint(
|
|
|
|
mozilla::dom::OwningBooleanOrMediaTrackConstraints& aConstraint) {
|
|
|
|
// Not requesting stream.
|
|
|
|
if (!IsOn(aConstraint)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// It looks like {audio: true}, do nothing.
|
|
|
|
if (!aConstraint.IsMediaTrackConstraints()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Keep mediaSource, ignore all other constraints.
|
|
|
|
auto& c = aConstraint.GetAsMediaTrackConstraints();
|
|
|
|
nsString mediaSource = c.mMediaSource;
|
|
|
|
aConstraint.SetAsMediaTrackConstraints().mMediaSource = mediaSource;
|
|
|
|
}
|
|
|
|
|
2012-06-03 11:35:15 +04:00
|
|
|
/**
|
|
|
|
* The entry point for this file. A call from Navigator::mozGetUserMedia
|
|
|
|
* will end up here. MediaManager is a singleton that is responsible
|
|
|
|
* for handling all incoming getUserMedia calls from every window.
|
|
|
|
*/
|
|
|
|
nsresult
|
2016-01-30 20:05:36 +03:00
|
|
|
MediaManager::GetUserMedia(nsPIDOMWindowInner* aWindow,
|
2015-07-03 01:01:52 +03:00
|
|
|
const MediaStreamConstraints& aConstraintsPassedIn,
|
2018-07-28 07:40:26 +03:00
|
|
|
GetUserMediaSuccessCallback&& aOnSuccess,
|
|
|
|
GetUserMediaErrorCallback&& aOnFailure,
|
2017-02-01 23:43:38 +03:00
|
|
|
dom::CallerType aCallerType)
|
2012-06-03 11:35:15 +04:00
|
|
|
{
|
2015-06-18 18:46:36 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
MOZ_ASSERT(aWindow);
|
2018-07-28 07:40:26 +03:00
|
|
|
MOZ_ASSERT(aOnFailure.GetISupports());
|
|
|
|
MOZ_ASSERT(aOnSuccess.GetISupports());
|
|
|
|
nsMainThreadPtrHandle<GetUserMediaSuccessCallback> onSuccess(
|
|
|
|
new nsMainThreadPtrHolder<GetUserMediaSuccessCallback>(
|
|
|
|
"GetUserMedia::SuccessCallback", std::move(aOnSuccess)));
|
|
|
|
nsMainThreadPtrHandle<GetUserMediaErrorCallback> onFailure(
|
|
|
|
new nsMainThreadPtrHolder<GetUserMediaErrorCallback>(
|
|
|
|
"GetUserMedia::FailureCallback", std::move(aOnFailure)));
|
2012-08-22 19:56:38 +04:00
|
|
|
uint64_t windowID = aWindow->WindowID();
|
2013-09-16 10:34:57 +04:00
|
|
|
|
2015-07-03 01:01:52 +03:00
|
|
|
MediaStreamConstraints c(aConstraintsPassedIn); // use a modifiable copy
|
2013-01-07 06:31:32 +04:00
|
|
|
|
2015-07-03 01:01:52 +03:00
|
|
|
// Do all the validation we can while we're sync (to return an
|
|
|
|
// already-rejected promise on failure).
|
2012-10-25 03:21:15 +04:00
|
|
|
|
2015-07-03 01:01:52 +03:00
|
|
|
if (!IsOn(c.mVideo) && !IsOn(c.mAudio)) {
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<MediaStreamError> error =
|
2015-07-03 01:01:52 +03:00
|
|
|
new MediaStreamError(aWindow,
|
2018-04-10 08:22:53 +03:00
|
|
|
MediaStreamError::Name::TypeError,
|
2015-07-03 01:01:52 +03:00
|
|
|
NS_LITERAL_STRING("audio and/or video is required"));
|
2018-07-28 07:40:26 +03:00
|
|
|
CallOnError(onFailure, *error);
|
2015-07-03 01:01:52 +03:00
|
|
|
return NS_OK;
|
2012-10-26 04:14:47 +04:00
|
|
|
}
|
2017-10-04 12:24:35 +03:00
|
|
|
|
|
|
|
if (!IsFullyActive(aWindow)) {
|
|
|
|
RefPtr<MediaStreamError> error =
|
2018-04-10 08:22:53 +03:00
|
|
|
new MediaStreamError(aWindow, MediaStreamError::Name::InvalidStateError);
|
2018-07-28 07:40:26 +03:00
|
|
|
CallOnError(onFailure, *error);
|
2017-10-04 12:24:35 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2017-11-02 18:27:33 +03:00
|
|
|
if (sHasShutdown) {
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<MediaStreamError> error =
|
2015-07-03 01:01:52 +03:00
|
|
|
new MediaStreamError(aWindow,
|
2018-04-10 08:22:53 +03:00
|
|
|
MediaStreamError::Name::AbortError,
|
2015-07-03 01:01:52 +03:00
|
|
|
NS_LITERAL_STRING("In shutdown"));
|
2018-07-28 07:40:26 +03:00
|
|
|
CallOnError(onFailure, *error);
|
2015-07-03 01:01:52 +03:00
|
|
|
return NS_OK;
|
2015-05-29 21:28:03 +03:00
|
|
|
}
|
2012-10-25 03:21:15 +04:00
|
|
|
|
2015-07-03 01:01:52 +03:00
|
|
|
// Determine permissions early (while we still have a stack).
|
2014-07-31 01:03:20 +04:00
|
|
|
|
2015-07-03 01:01:52 +03:00
|
|
|
nsIURI* docURI = aWindow->GetDocumentURI();
|
2015-07-14 04:56:29 +03:00
|
|
|
if (!docURI) {
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
2017-02-01 23:43:38 +03:00
|
|
|
bool isChrome = (aCallerType == dom::CallerType::System);
|
2016-08-19 23:39:54 +03:00
|
|
|
bool privileged = isChrome ||
|
|
|
|
Preferences::GetBool("media.navigator.permission.disabled", false);
|
2015-07-03 01:01:52 +03:00
|
|
|
bool isHTTPS = false;
|
2018-01-11 01:59:55 +03:00
|
|
|
bool isHandlingUserInput = EventStateManager::IsHandlingUserInput();;
|
2015-07-14 04:56:29 +03:00
|
|
|
docURI->SchemeIs("https", &isHTTPS);
|
2015-09-17 15:44:50 +03:00
|
|
|
nsCString host;
|
|
|
|
nsresult rv = docURI->GetHost(host);
|
|
|
|
// Test for some other schemes that ServiceWorker recognizes
|
|
|
|
bool isFile;
|
|
|
|
docURI->SchemeIs("file", &isFile);
|
|
|
|
bool isApp;
|
|
|
|
docURI->SchemeIs("app", &isApp);
|
|
|
|
// Same localhost check as ServiceWorkers uses
|
2016-04-26 13:30:43 +03:00
|
|
|
// (see IsOriginPotentiallyTrustworthy())
|
2015-09-17 15:44:50 +03:00
|
|
|
bool isLocalhost = NS_SUCCEEDED(rv) &&
|
|
|
|
(host.LowerCaseEqualsLiteral("localhost") ||
|
|
|
|
host.LowerCaseEqualsLiteral("127.0.0.1") ||
|
|
|
|
host.LowerCaseEqualsLiteral("::1"));
|
|
|
|
|
|
|
|
// Record telemetry about whether the source of the call was secure, i.e.,
|
|
|
|
// privileged or HTTPS. We may handle other cases
|
2017-05-10 08:19:23 +03:00
|
|
|
if (privileged) {
|
2015-09-17 15:44:50 +03:00
|
|
|
Telemetry::Accumulate(Telemetry::WEBRTC_GET_USER_MEDIA_SECURE_ORIGIN,
|
|
|
|
(uint32_t) GetUserMediaSecurityState::Privileged);
|
|
|
|
} else if (isHTTPS) {
|
|
|
|
Telemetry::Accumulate(Telemetry::WEBRTC_GET_USER_MEDIA_SECURE_ORIGIN,
|
|
|
|
(uint32_t) GetUserMediaSecurityState::HTTPS);
|
|
|
|
} else if (isFile) {
|
|
|
|
Telemetry::Accumulate(Telemetry::WEBRTC_GET_USER_MEDIA_SECURE_ORIGIN,
|
|
|
|
(uint32_t) GetUserMediaSecurityState::File);
|
|
|
|
} else if (isApp) {
|
|
|
|
Telemetry::Accumulate(Telemetry::WEBRTC_GET_USER_MEDIA_SECURE_ORIGIN,
|
|
|
|
(uint32_t) GetUserMediaSecurityState::App);
|
|
|
|
} else if (isLocalhost) {
|
|
|
|
Telemetry::Accumulate(Telemetry::WEBRTC_GET_USER_MEDIA_SECURE_ORIGIN,
|
|
|
|
(uint32_t) GetUserMediaSecurityState::Localhost);
|
|
|
|
} else {
|
|
|
|
Telemetry::Accumulate(Telemetry::WEBRTC_GET_USER_MEDIA_SECURE_ORIGIN,
|
|
|
|
(uint32_t) GetUserMediaSecurityState::Other);
|
|
|
|
}
|
2015-07-14 04:56:29 +03:00
|
|
|
|
2016-11-22 14:38:41 +03:00
|
|
|
nsCOMPtr<nsIPrincipal> principal =
|
2017-11-04 01:25:38 +03:00
|
|
|
nsGlobalWindowInner::Cast(aWindow)->GetPrincipal();
|
2016-11-22 14:38:41 +03:00
|
|
|
if (NS_WARN_IF(!principal)) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2017-01-28 20:29:13 +03:00
|
|
|
// This principal needs to be sent to different threads and so via IPC.
|
|
|
|
// For this reason it's better to convert it to PrincipalInfo right now.
|
|
|
|
ipc::PrincipalInfo principalInfo;
|
|
|
|
rv = PrincipalToPrincipalInfo(principal, &principalInfo);
|
2015-07-14 04:56:29 +03:00
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
return rv;
|
2015-07-03 01:01:52 +03:00
|
|
|
}
|
2015-02-03 00:53:19 +03:00
|
|
|
|
2017-09-18 12:51:51 +03:00
|
|
|
const bool resistFingerprinting = nsContentUtils::ResistFingerprinting(aCallerType);
|
|
|
|
|
|
|
|
if (resistFingerprinting) {
|
|
|
|
ReduceConstraint(c.mVideo);
|
|
|
|
ReduceConstraint(c.mAudio);
|
|
|
|
}
|
|
|
|
|
2015-07-03 01:01:52 +03:00
|
|
|
if (!Preferences::GetBool("media.navigator.video.enabled", true)) {
|
|
|
|
c.mVideo.SetAsBoolean() = false;
|
2015-02-03 00:53:19 +03:00
|
|
|
}
|
|
|
|
|
2016-02-17 00:55:33 +03:00
|
|
|
MediaSourceEnum videoType = MediaSourceEnum::Other; // none
|
|
|
|
MediaSourceEnum audioType = MediaSourceEnum::Other; // none
|
2015-07-03 01:01:52 +03:00
|
|
|
|
2014-07-31 01:03:20 +04:00
|
|
|
if (c.mVideo.IsMediaTrackConstraints()) {
|
2015-02-21 01:06:26 +03:00
|
|
|
auto& vc = c.mVideo.GetAsMediaTrackConstraints();
|
2015-07-03 01:01:52 +03:00
|
|
|
videoType = StringToEnum(dom::MediaSourceEnumValues::strings,
|
|
|
|
vc.mMediaSource,
|
2016-02-17 00:55:33 +03:00
|
|
|
MediaSourceEnum::Other);
|
2016-09-23 18:55:48 +03:00
|
|
|
Telemetry::Accumulate(Telemetry::WEBRTC_GET_USER_MEDIA_TYPE,
|
2015-09-22 05:20:45 +03:00
|
|
|
(uint32_t) videoType);
|
2015-07-03 01:01:52 +03:00
|
|
|
switch (videoType) {
|
2016-02-17 00:55:33 +03:00
|
|
|
case MediaSourceEnum::Camera:
|
2015-07-03 01:01:52 +03:00
|
|
|
break;
|
|
|
|
|
2016-02-17 00:55:33 +03:00
|
|
|
case MediaSourceEnum::Browser:
|
2015-10-23 00:03:47 +03:00
|
|
|
// If no window id is passed in then default to the caller's window.
|
|
|
|
// Functional defaults are helpful in tests, but also a natural outcome
|
|
|
|
// of the constraints API's limited semantics for requiring input.
|
|
|
|
if (!vc.mBrowserWindow.WasPassed()) {
|
2016-01-30 20:05:36 +03:00
|
|
|
nsPIDOMWindowOuter* outer = aWindow->GetOuterWindow();
|
2015-10-23 00:03:47 +03:00
|
|
|
vc.mBrowserWindow.Construct(outer->WindowID());
|
|
|
|
}
|
2016-01-14 12:42:18 +03:00
|
|
|
MOZ_FALLTHROUGH;
|
2016-02-17 00:55:33 +03:00
|
|
|
case MediaSourceEnum::Screen:
|
|
|
|
case MediaSourceEnum::Application:
|
|
|
|
case MediaSourceEnum::Window:
|
2015-07-03 01:01:52 +03:00
|
|
|
// Deny screensharing request if support is disabled, or
|
2017-01-08 23:12:03 +03:00
|
|
|
// the requesting document is not from a host on the whitelist.
|
2016-02-17 00:55:33 +03:00
|
|
|
if (!Preferences::GetBool(((videoType == MediaSourceEnum::Browser)?
|
2015-07-03 01:01:52 +03:00
|
|
|
"media.getusermedia.browser.enabled" :
|
|
|
|
"media.getusermedia.screensharing.enabled"),
|
|
|
|
false) ||
|
2017-10-26 19:09:29 +03:00
|
|
|
(!privileged && !aWindow->IsSecureContext())) {
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<MediaStreamError> error =
|
2015-07-03 01:01:52 +03:00
|
|
|
new MediaStreamError(aWindow,
|
2018-04-10 08:22:53 +03:00
|
|
|
MediaStreamError::Name::NotAllowedError);
|
2018-07-28 07:40:26 +03:00
|
|
|
CallOnError(onFailure, *error);
|
2015-07-03 01:01:52 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2016-02-17 00:55:33 +03:00
|
|
|
case MediaSourceEnum::Microphone:
|
|
|
|
case MediaSourceEnum::Other:
|
2015-07-03 01:01:52 +03:00
|
|
|
default: {
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<MediaStreamError> error =
|
2015-09-18 21:04:41 +03:00
|
|
|
new MediaStreamError(aWindow,
|
2018-04-10 08:22:53 +03:00
|
|
|
MediaStreamError::Name::OverconstrainedError,
|
2015-09-18 21:04:41 +03:00
|
|
|
NS_LITERAL_STRING(""),
|
|
|
|
NS_LITERAL_STRING("mediaSource"));
|
2018-07-28 07:40:26 +03:00
|
|
|
CallOnError(onFailure, *error);
|
2015-07-03 01:01:52 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-17 00:55:33 +03:00
|
|
|
if (vc.mAdvanced.WasPassed() && videoType != MediaSourceEnum::Camera) {
|
2015-08-10 19:16:30 +03:00
|
|
|
// iterate through advanced, forcing all unset mediaSources to match "root"
|
|
|
|
const char *unset = EnumToASCII(dom::MediaSourceEnumValues::strings,
|
2016-02-17 00:55:33 +03:00
|
|
|
MediaSourceEnum::Camera);
|
2015-07-03 01:01:52 +03:00
|
|
|
for (MediaTrackConstraintSet& cs : vc.mAdvanced.Value()) {
|
2015-08-10 19:16:30 +03:00
|
|
|
if (cs.mMediaSource.EqualsASCII(unset)) {
|
2015-07-03 01:01:52 +03:00
|
|
|
cs.mMediaSource = vc.mMediaSource;
|
2015-02-21 01:06:26 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!privileged) {
|
|
|
|
// only allow privileged content to set the window id
|
|
|
|
if (vc.mBrowserWindow.WasPassed()) {
|
2015-07-23 07:44:52 +03:00
|
|
|
vc.mBrowserWindow.Value() = -1;
|
2015-02-21 01:06:26 +03:00
|
|
|
}
|
|
|
|
if (vc.mAdvanced.WasPassed()) {
|
|
|
|
for (MediaTrackConstraintSet& cs : vc.mAdvanced.Value()) {
|
|
|
|
if (cs.mBrowserWindow.WasPassed()) {
|
2015-07-23 07:44:52 +03:00
|
|
|
cs.mBrowserWindow.Value() = -1;
|
2015-02-21 01:06:26 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-12-03 06:51:03 +03:00
|
|
|
} else if (IsOn(c.mVideo)) {
|
2016-02-17 00:55:33 +03:00
|
|
|
videoType = MediaSourceEnum::Camera;
|
2017-05-31 04:57:37 +03:00
|
|
|
Telemetry::Accumulate(Telemetry::WEBRTC_GET_USER_MEDIA_TYPE,
|
|
|
|
(uint32_t) videoType);
|
2014-07-08 10:01:27 +04:00
|
|
|
}
|
2015-07-24 15:28:17 +03:00
|
|
|
|
|
|
|
if (c.mAudio.IsMediaTrackConstraints()) {
|
|
|
|
auto& ac = c.mAudio.GetAsMediaTrackConstraints();
|
2017-05-20 03:57:44 +03:00
|
|
|
MediaConstraintsHelper::ConvertOldWithWarning(ac.mMozAutoGainControl,
|
|
|
|
ac.mAutoGainControl,
|
|
|
|
"MozAutoGainControlWarning",
|
|
|
|
aWindow);
|
|
|
|
MediaConstraintsHelper::ConvertOldWithWarning(ac.mMozNoiseSuppression,
|
|
|
|
ac.mNoiseSuppression,
|
|
|
|
"MozNoiseSuppressionWarning",
|
|
|
|
aWindow);
|
2015-07-24 15:28:17 +03:00
|
|
|
audioType = StringToEnum(dom::MediaSourceEnumValues::strings,
|
|
|
|
ac.mMediaSource,
|
2016-02-17 00:55:33 +03:00
|
|
|
MediaSourceEnum::Other);
|
2015-08-10 19:16:30 +03:00
|
|
|
// Work around WebIDL default since spec uses same dictionary w/audio & video.
|
2016-02-17 00:55:33 +03:00
|
|
|
if (audioType == MediaSourceEnum::Camera) {
|
|
|
|
audioType = MediaSourceEnum::Microphone;
|
2015-08-10 19:16:30 +03:00
|
|
|
ac.mMediaSource.AssignASCII(EnumToASCII(dom::MediaSourceEnumValues::strings,
|
|
|
|
audioType));
|
|
|
|
}
|
2016-09-23 18:55:48 +03:00
|
|
|
Telemetry::Accumulate(Telemetry::WEBRTC_GET_USER_MEDIA_TYPE,
|
2015-09-22 05:20:45 +03:00
|
|
|
(uint32_t) audioType);
|
2015-08-10 19:16:30 +03:00
|
|
|
|
|
|
|
switch (audioType) {
|
2016-02-17 00:55:33 +03:00
|
|
|
case MediaSourceEnum::Microphone:
|
2015-08-10 19:16:30 +03:00
|
|
|
break;
|
|
|
|
|
2016-02-17 00:55:33 +03:00
|
|
|
case MediaSourceEnum::AudioCapture:
|
2015-08-10 19:16:30 +03:00
|
|
|
// Only enable AudioCapture if the pref is enabled. If it's not, we can
|
|
|
|
// deny right away.
|
|
|
|
if (!Preferences::GetBool("media.getusermedia.audiocapture.enabled")) {
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<MediaStreamError> error =
|
2015-08-10 19:16:30 +03:00
|
|
|
new MediaStreamError(aWindow,
|
2018-04-10 08:22:53 +03:00
|
|
|
MediaStreamError::Name::NotAllowedError);
|
2018-07-28 07:40:26 +03:00
|
|
|
CallOnError(onFailure, *error);
|
2015-08-10 19:16:30 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2016-02-17 00:55:33 +03:00
|
|
|
case MediaSourceEnum::Other:
|
2015-08-10 19:16:30 +03:00
|
|
|
default: {
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<MediaStreamError> error =
|
2015-09-18 21:04:41 +03:00
|
|
|
new MediaStreamError(aWindow,
|
2018-04-10 08:22:53 +03:00
|
|
|
MediaStreamError::Name::OverconstrainedError,
|
2015-09-18 21:04:41 +03:00
|
|
|
NS_LITERAL_STRING(""),
|
|
|
|
NS_LITERAL_STRING("mediaSource"));
|
2018-07-28 07:40:26 +03:00
|
|
|
CallOnError(onFailure, *error);
|
2015-08-10 19:16:30 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ac.mAdvanced.WasPassed()) {
|
|
|
|
// iterate through advanced, forcing all unset mediaSources to match "root"
|
|
|
|
const char *unset = EnumToASCII(dom::MediaSourceEnumValues::strings,
|
2016-02-17 00:55:33 +03:00
|
|
|
MediaSourceEnum::Camera);
|
2015-08-10 19:16:30 +03:00
|
|
|
for (MediaTrackConstraintSet& cs : ac.mAdvanced.Value()) {
|
|
|
|
if (cs.mMediaSource.EqualsASCII(unset)) {
|
|
|
|
cs.mMediaSource = ac.mMediaSource;
|
|
|
|
}
|
|
|
|
}
|
2015-07-24 15:28:17 +03:00
|
|
|
}
|
2015-12-03 06:51:03 +03:00
|
|
|
} else if (IsOn(c.mAudio)) {
|
2017-05-31 04:57:37 +03:00
|
|
|
audioType = MediaSourceEnum::Microphone;
|
|
|
|
Telemetry::Accumulate(Telemetry::WEBRTC_GET_USER_MEDIA_TYPE,
|
|
|
|
(uint32_t) audioType);
|
2015-07-24 15:28:17 +03:00
|
|
|
}
|
2015-12-03 06:51:03 +03:00
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
// Create a window listener if it doesn't already exist.
|
|
|
|
RefPtr<GetUserMediaWindowListener> windowListener =
|
|
|
|
GetWindowListener(windowID);
|
|
|
|
if (windowListener) {
|
|
|
|
PrincipalHandle existingPrincipalHandle = windowListener->GetPrincipalHandle();
|
|
|
|
MOZ_ASSERT(PrincipalHandleMatches(existingPrincipalHandle, principal));
|
|
|
|
} else {
|
|
|
|
windowListener = new GetUserMediaWindowListener(mMediaThread, windowID,
|
|
|
|
MakePrincipalHandle(principal));
|
|
|
|
AddWindowID(windowID, windowListener);
|
|
|
|
}
|
2013-05-02 16:00:12 +04:00
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
RefPtr<SourceListener> sourceListener = new SourceListener();
|
|
|
|
windowListener->Register(sourceListener);
|
2014-04-16 10:22:19 +04:00
|
|
|
|
2015-07-03 01:01:52 +03:00
|
|
|
if (!privileged) {
|
|
|
|
// Check if this site has had persistent permissions denied.
|
2014-02-25 15:50:42 +04:00
|
|
|
nsCOMPtr<nsIPermissionManager> permManager =
|
|
|
|
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
uint32_t audioPerm = nsIPermissionManager::UNKNOWN_ACTION;
|
2014-04-04 13:54:25 +04:00
|
|
|
if (IsOn(c.mAudio)) {
|
2017-06-28 22:09:14 +03:00
|
|
|
if (audioType == MediaSourceEnum::Microphone &&
|
|
|
|
Preferences::GetBool("media.getusermedia.microphone.deny", false)) {
|
|
|
|
audioPerm = nsIPermissionManager::DENY_ACTION;
|
|
|
|
} else {
|
|
|
|
rv = permManager->TestExactPermissionFromPrincipal(
|
|
|
|
principal, "microphone", &audioPerm);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
2014-02-25 15:50:42 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t videoPerm = nsIPermissionManager::UNKNOWN_ACTION;
|
2014-04-04 13:54:25 +04:00
|
|
|
if (IsOn(c.mVideo)) {
|
2017-06-28 22:09:14 +03:00
|
|
|
if (videoType == MediaSourceEnum::Camera &&
|
|
|
|
Preferences::GetBool("media.getusermedia.camera.deny", false)) {
|
|
|
|
videoPerm = nsIPermissionManager::DENY_ACTION;
|
|
|
|
} else {
|
|
|
|
rv = permManager->TestExactPermissionFromPrincipal(
|
|
|
|
principal, videoType == MediaSourceEnum::Camera ? "camera" : "screen",
|
|
|
|
&videoPerm);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
2014-02-25 15:50:42 +04:00
|
|
|
}
|
|
|
|
|
2016-05-06 04:54:04 +03:00
|
|
|
if ((!IsOn(c.mAudio) && !IsOn(c.mVideo)) ||
|
|
|
|
(IsOn(c.mAudio) && audioPerm == nsIPermissionManager::DENY_ACTION) ||
|
|
|
|
(IsOn(c.mVideo) && videoPerm == nsIPermissionManager::DENY_ACTION)) {
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<MediaStreamError> error =
|
2018-04-10 08:22:53 +03:00
|
|
|
new MediaStreamError(aWindow, MediaStreamError::Name::NotAllowedError);
|
2018-07-28 07:40:26 +03:00
|
|
|
CallOnError(onFailure, *error);
|
2017-04-26 12:13:40 +03:00
|
|
|
windowListener->Remove(sourceListener);
|
2015-07-03 01:01:52 +03:00
|
|
|
return NS_OK;
|
2014-02-25 15:50:42 +04:00
|
|
|
}
|
2015-07-03 01:01:52 +03:00
|
|
|
}
|
2014-02-25 15:50:42 +04:00
|
|
|
|
2015-07-03 01:01:52 +03:00
|
|
|
// Get list of all devices, with origin-specific device ids.
|
|
|
|
|
|
|
|
MediaEnginePrefs prefs = mPrefs;
|
|
|
|
|
|
|
|
nsString callID;
|
2015-07-14 04:56:29 +03:00
|
|
|
rv = GenerateUUID(callID);
|
2015-07-03 01:01:52 +03:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2017-12-04 19:56:28 +03:00
|
|
|
bool hasVideo = videoType != MediaSourceEnum::Other;
|
|
|
|
bool hasAudio = audioType != MediaSourceEnum::Other;
|
2018-03-16 22:09:26 +03:00
|
|
|
DeviceEnumerationType videoEnumerationType = DeviceEnumerationType::Normal;
|
|
|
|
DeviceEnumerationType audioEnumerationType = DeviceEnumerationType::Normal;
|
Bug 1436523 - Rework media manager enumeration to prefer loopback to fake devices, allow mixing of fake and loopback. r=achronop
Change the media manager so that if fake and loopback devices are requested,
loopback is preferred. With this change loopback and fake devices can also be
mixed. Since the fake flag is coarse, and does not specify fake audio or video,
we would previously just make everything fake. As loopback sets flags for video
and audio separately, we can now request a single loopback device, while also
setting the fake flag to get a mix. E.g. if we request a loopback audio device,
and set the fake flag, we should get loopback audio and fake video.
This change also attempts to somewhat consolidate where these settings take
place. Previously, EnumerateRawDevices did much of the loopback setup. However,
other steps around fingerprint resistance or fake devices were done in earlier
functions (EnumerateDevices and GetUserMedia). This changeset moves the loopback
setup so that it's more consolidated with the other setup code in these
functions.
MozReview-Commit-ID: FF0bR0Nyws9
--HG--
extra : rebase_source : 374a6fd0842a430e27c695bcf956e2e072a77fc3
2018-02-13 00:56:26 +03:00
|
|
|
|
|
|
|
// Handle loopback and fake requests. For gUM we don't consider resist
|
|
|
|
// fingerprinting as users should be prompted anyway.
|
|
|
|
bool wantFakes = c.mFake.WasPassed() ? c.mFake.Value() :
|
|
|
|
Preferences::GetBool("media.navigator.streams.fake");
|
|
|
|
nsAutoCString videoLoopDev, audioLoopDev;
|
|
|
|
// Video
|
|
|
|
if (videoType == MediaSourceEnum::Camera) {
|
|
|
|
Preferences::GetCString("media.video_loopback_dev", videoLoopDev);
|
|
|
|
// Loopback prefs take precedence over fake prefs
|
|
|
|
if (!videoLoopDev.IsEmpty()) {
|
2018-03-16 22:09:26 +03:00
|
|
|
videoEnumerationType = DeviceEnumerationType::Loopback;
|
Bug 1436523 - Rework media manager enumeration to prefer loopback to fake devices, allow mixing of fake and loopback. r=achronop
Change the media manager so that if fake and loopback devices are requested,
loopback is preferred. With this change loopback and fake devices can also be
mixed. Since the fake flag is coarse, and does not specify fake audio or video,
we would previously just make everything fake. As loopback sets flags for video
and audio separately, we can now request a single loopback device, while also
setting the fake flag to get a mix. E.g. if we request a loopback audio device,
and set the fake flag, we should get loopback audio and fake video.
This change also attempts to somewhat consolidate where these settings take
place. Previously, EnumerateRawDevices did much of the loopback setup. However,
other steps around fingerprint resistance or fake devices were done in earlier
functions (EnumerateDevices and GetUserMedia). This changeset moves the loopback
setup so that it's more consolidated with the other setup code in these
functions.
MozReview-Commit-ID: FF0bR0Nyws9
--HG--
extra : rebase_source : 374a6fd0842a430e27c695bcf956e2e072a77fc3
2018-02-13 00:56:26 +03:00
|
|
|
} else if (wantFakes) {
|
2018-03-16 22:09:26 +03:00
|
|
|
videoEnumerationType = DeviceEnumerationType::Fake;
|
Bug 1436523 - Rework media manager enumeration to prefer loopback to fake devices, allow mixing of fake and loopback. r=achronop
Change the media manager so that if fake and loopback devices are requested,
loopback is preferred. With this change loopback and fake devices can also be
mixed. Since the fake flag is coarse, and does not specify fake audio or video,
we would previously just make everything fake. As loopback sets flags for video
and audio separately, we can now request a single loopback device, while also
setting the fake flag to get a mix. E.g. if we request a loopback audio device,
and set the fake flag, we should get loopback audio and fake video.
This change also attempts to somewhat consolidate where these settings take
place. Previously, EnumerateRawDevices did much of the loopback setup. However,
other steps around fingerprint resistance or fake devices were done in earlier
functions (EnumerateDevices and GetUserMedia). This changeset moves the loopback
setup so that it's more consolidated with the other setup code in these
functions.
MozReview-Commit-ID: FF0bR0Nyws9
--HG--
extra : rebase_source : 374a6fd0842a430e27c695bcf956e2e072a77fc3
2018-02-13 00:56:26 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// Audio
|
|
|
|
if (audioType == MediaSourceEnum::Microphone) {
|
|
|
|
Preferences::GetCString("media.audio_loopback_dev", audioLoopDev);
|
|
|
|
// Loopback prefs take precedence over fake prefs
|
|
|
|
if (!audioLoopDev.IsEmpty()) {
|
2018-03-16 22:09:26 +03:00
|
|
|
audioEnumerationType = DeviceEnumerationType::Loopback;
|
Bug 1436523 - Rework media manager enumeration to prefer loopback to fake devices, allow mixing of fake and loopback. r=achronop
Change the media manager so that if fake and loopback devices are requested,
loopback is preferred. With this change loopback and fake devices can also be
mixed. Since the fake flag is coarse, and does not specify fake audio or video,
we would previously just make everything fake. As loopback sets flags for video
and audio separately, we can now request a single loopback device, while also
setting the fake flag to get a mix. E.g. if we request a loopback audio device,
and set the fake flag, we should get loopback audio and fake video.
This change also attempts to somewhat consolidate where these settings take
place. Previously, EnumerateRawDevices did much of the loopback setup. However,
other steps around fingerprint resistance or fake devices were done in earlier
functions (EnumerateDevices and GetUserMedia). This changeset moves the loopback
setup so that it's more consolidated with the other setup code in these
functions.
MozReview-Commit-ID: FF0bR0Nyws9
--HG--
extra : rebase_source : 374a6fd0842a430e27c695bcf956e2e072a77fc3
2018-02-13 00:56:26 +03:00
|
|
|
} else if (wantFakes) {
|
2018-03-16 22:09:26 +03:00
|
|
|
audioEnumerationType = DeviceEnumerationType::Fake;
|
Bug 1436523 - Rework media manager enumeration to prefer loopback to fake devices, allow mixing of fake and loopback. r=achronop
Change the media manager so that if fake and loopback devices are requested,
loopback is preferred. With this change loopback and fake devices can also be
mixed. Since the fake flag is coarse, and does not specify fake audio or video,
we would previously just make everything fake. As loopback sets flags for video
and audio separately, we can now request a single loopback device, while also
setting the fake flag to get a mix. E.g. if we request a loopback audio device,
and set the fake flag, we should get loopback audio and fake video.
This change also attempts to somewhat consolidate where these settings take
place. Previously, EnumerateRawDevices did much of the loopback setup. However,
other steps around fingerprint resistance or fake devices were done in earlier
functions (EnumerateDevices and GetUserMedia). This changeset moves the loopback
setup so that it's more consolidated with the other setup code in these
functions.
MozReview-Commit-ID: FF0bR0Nyws9
--HG--
extra : rebase_source : 374a6fd0842a430e27c695bcf956e2e072a77fc3
2018-02-13 00:56:26 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-16 22:09:26 +03:00
|
|
|
bool realDevicesRequested = (videoEnumerationType != DeviceEnumerationType::Fake && hasVideo) ||
|
|
|
|
(audioEnumerationType != DeviceEnumerationType::Fake && hasAudio);
|
2016-11-07 20:20:41 +03:00
|
|
|
bool askPermission =
|
2018-02-13 00:55:45 +03:00
|
|
|
(!privileged || Preferences::GetBool("media.navigator.permission.force")) &&
|
|
|
|
(realDevicesRequested || Preferences::GetBool("media.navigator.permission.fake"));
|
2015-07-03 01:01:52 +03:00
|
|
|
|
2018-03-16 22:09:26 +03:00
|
|
|
LOG(("%s: Preparing to enumerate devices. windowId=%" PRIu64
|
|
|
|
", videoType=%" PRIu8 ", audioType=%" PRIu8
|
|
|
|
", videoEnumerationType=%" PRIu8 ", audioEnumerationType=%" PRIu8
|
|
|
|
", askPermission=%s",
|
|
|
|
__func__, windowID,
|
|
|
|
static_cast<uint8_t>(videoType), static_cast<uint8_t>(audioType),
|
|
|
|
static_cast<uint8_t>(videoEnumerationType), static_cast<uint8_t>(audioEnumerationType),
|
|
|
|
askPermission ? "true" : "false"));
|
|
|
|
|
2018-09-25 20:03:50 +03:00
|
|
|
RefPtr<MediaDeviceSetPromise> p = EnumerateDevicesImpl(windowID,
|
|
|
|
videoType,
|
|
|
|
audioType,
|
|
|
|
MediaSinkEnum::Other,
|
|
|
|
videoEnumerationType,
|
|
|
|
audioEnumerationType);
|
2017-02-04 00:57:49 +03:00
|
|
|
RefPtr<MediaManager> self = this;
|
2018-09-25 20:03:50 +03:00
|
|
|
p->Then(GetCurrentThreadSerialEventTarget(), __func__,
|
|
|
|
[self, onSuccess, onFailure, windowID, c, windowListener,
|
|
|
|
sourceListener, askPermission, prefs, isHTTPS, isHandlingUserInput,
|
|
|
|
callID, principalInfo, isChrome, resistFingerprinting](RefPtr<MediaDeviceSetRefCnt>&& aDevices) mutable {
|
|
|
|
LOG(("GetUserMedia: post enumeration promise success callback starting"));
|
2015-07-03 01:01:52 +03:00
|
|
|
|
2017-02-04 00:57:49 +03:00
|
|
|
// Ensure that our windowID is still good.
|
2018-09-21 11:29:12 +03:00
|
|
|
if (!nsGlobalWindowInner::GetInnerWindowWithId(windowID) ||
|
|
|
|
!self->IsWindowListenerStillActive(windowListener)) {
|
|
|
|
LOG(("GetUserMedia: bad window (%" PRIu64 ") in post enumeration "
|
|
|
|
"success callback!", windowID));
|
2015-07-03 01:01:52 +03:00
|
|
|
return;
|
|
|
|
}
|
2012-10-06 04:20:47 +04:00
|
|
|
|
2015-10-04 03:42:26 +03:00
|
|
|
// Apply any constraints. This modifies the passed-in list.
|
2018-09-25 20:03:50 +03:00
|
|
|
RefPtr<BadConstraintsPromise> p2 = self->SelectSettings(c, isChrome, aDevices);
|
2015-10-04 03:42:26 +03:00
|
|
|
|
2018-09-25 20:03:50 +03:00
|
|
|
p2->Then(GetCurrentThreadSerialEventTarget(), __func__,
|
|
|
|
[self, onSuccess, onFailure, windowID, c,
|
2017-04-26 12:13:40 +03:00
|
|
|
windowListener, sourceListener, askPermission, prefs, isHTTPS,
|
2018-09-25 20:03:50 +03:00
|
|
|
isHandlingUserInput, callID, principalInfo, isChrome, aDevices,
|
2018-01-11 01:59:55 +03:00
|
|
|
resistFingerprinting
|
2018-09-25 20:03:50 +03:00
|
|
|
](const char* badConstraint) mutable {
|
|
|
|
LOG(("GetUserMedia: starting post enumeration promise2 success "
|
2018-03-16 22:09:55 +03:00
|
|
|
"callback!"));
|
2015-10-04 03:42:26 +03:00
|
|
|
|
2018-09-21 11:29:12 +03:00
|
|
|
// Ensure that the window is still good.
|
2017-11-06 21:09:35 +03:00
|
|
|
auto* globalWindow = nsGlobalWindowInner::GetInnerWindowWithId(windowID);
|
2016-01-30 20:05:36 +03:00
|
|
|
RefPtr<nsPIDOMWindowInner> window = globalWindow ? globalWindow->AsInner()
|
|
|
|
: nullptr;
|
2018-09-21 11:29:12 +03:00
|
|
|
if (!window || !self->IsWindowListenerStillActive(windowListener)) {
|
|
|
|
LOG(("GetUserMedia: bad window (%" PRIu64 ") in post enumeration "
|
|
|
|
"success callback 2!", windowID));
|
2015-10-04 03:42:26 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (badConstraint) {
|
2018-09-25 20:03:50 +03:00
|
|
|
LOG(("GetUserMedia: bad constraint found in post enumeration promise2 "
|
2018-03-16 22:09:55 +03:00
|
|
|
"success callback! Calling error handler!"));
|
2015-10-04 03:42:26 +03:00
|
|
|
nsString constraint;
|
|
|
|
constraint.AssignASCII(badConstraint);
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<MediaStreamError> error =
|
2015-10-04 03:42:26 +03:00
|
|
|
new MediaStreamError(window,
|
2018-04-10 08:22:53 +03:00
|
|
|
MediaStreamError::Name::OverconstrainedError,
|
2015-10-04 03:42:26 +03:00
|
|
|
NS_LITERAL_STRING(""),
|
|
|
|
constraint);
|
2018-07-28 07:40:26 +03:00
|
|
|
CallOnError(onFailure, *error);
|
2015-10-04 03:42:26 +03:00
|
|
|
return;
|
|
|
|
}
|
2018-09-25 20:03:50 +03:00
|
|
|
if (!(*aDevices)->Length()) {
|
|
|
|
LOG(("GetUserMedia: no devices found in post enumeration promise2 "
|
2018-03-16 22:09:55 +03:00
|
|
|
"success callback! Calling error handler!"));
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<MediaStreamError> error =
|
2017-09-18 12:51:51 +03:00
|
|
|
new MediaStreamError(
|
|
|
|
window,
|
|
|
|
// When privacy.resistFingerprinting = true, no available
|
|
|
|
// device implies content script is requesting a fake
|
|
|
|
// device, so report NotAllowedError.
|
2018-04-10 08:22:53 +03:00
|
|
|
resistFingerprinting ? MediaStreamError::Name::NotAllowedError
|
|
|
|
: MediaStreamError::Name::NotFoundError);
|
2018-07-28 07:40:26 +03:00
|
|
|
CallOnError(onFailure, *error);
|
2015-07-03 01:01:52 +03:00
|
|
|
return;
|
|
|
|
}
|
2015-10-04 03:42:26 +03:00
|
|
|
|
2016-10-14 20:06:37 +03:00
|
|
|
nsCOMPtr<nsIMutableArray> devicesCopy = nsArray::Create(); // before we give up devices below
|
2015-10-04 03:42:26 +03:00
|
|
|
if (!askPermission) {
|
2018-09-25 20:03:50 +03:00
|
|
|
for (auto& device : **aDevices) {
|
2017-10-21 17:53:02 +03:00
|
|
|
nsresult rv = devicesCopy->AppendElement(device);
|
2015-10-04 03:42:26 +03:00
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2015-07-03 01:01:52 +03:00
|
|
|
}
|
2012-10-06 04:20:47 +04:00
|
|
|
|
2018-05-29 23:14:38 +03:00
|
|
|
bool focusSource;
|
|
|
|
focusSource = mozilla::Preferences::GetBool("media.getusermedia.window.focus_source.enabled", true);
|
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
// Pass callbacks and listeners along to GetUserMediaTask.
|
|
|
|
RefPtr<GetUserMediaTask> task (new GetUserMediaTask(c,
|
2017-11-15 20:40:35 +03:00
|
|
|
onSuccess,
|
|
|
|
onFailure,
|
2017-04-26 12:13:40 +03:00
|
|
|
windowID,
|
|
|
|
windowListener,
|
|
|
|
sourceListener,
|
|
|
|
prefs,
|
|
|
|
principalInfo,
|
2016-08-19 23:39:54 +03:00
|
|
|
isChrome,
|
2018-09-25 20:03:50 +03:00
|
|
|
aDevices->release(),
|
2018-05-29 23:14:38 +03:00
|
|
|
focusSource));
|
2015-10-04 03:42:26 +03:00
|
|
|
// Store the task w/callbacks.
|
2017-02-04 00:57:49 +03:00
|
|
|
self->mActiveCallbacks.Put(callID, task.forget());
|
2015-10-04 03:42:26 +03:00
|
|
|
|
|
|
|
// Add a WindowID cross-reference so OnNavigation can tear things down
|
|
|
|
nsTArray<nsString>* array;
|
2017-02-04 00:57:49 +03:00
|
|
|
if (!self->mCallIds.Get(windowID, &array)) {
|
2015-10-04 03:42:26 +03:00
|
|
|
array = new nsTArray<nsString>();
|
2017-02-04 00:57:49 +03:00
|
|
|
self->mCallIds.Put(windowID, array);
|
2015-10-04 03:42:26 +03:00
|
|
|
}
|
|
|
|
array->AppendElement(callID);
|
2015-07-03 01:01:52 +03:00
|
|
|
|
2015-10-04 03:42:26 +03:00
|
|
|
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
|
|
|
if (!askPermission) {
|
|
|
|
obs->NotifyObservers(devicesCopy, "getUserMedia:privileged:allow",
|
|
|
|
callID.BeginReading());
|
|
|
|
} else {
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<GetUserMediaRequest> req =
|
2018-01-11 01:59:55 +03:00
|
|
|
new GetUserMediaRequest(window, callID, c, isHTTPS, isHandlingUserInput);
|
2017-05-12 06:32:14 +03:00
|
|
|
if (!Preferences::GetBool("media.navigator.permission.force") && array->Length() > 1) {
|
|
|
|
// there is at least 1 pending gUM request
|
|
|
|
// For the scarySources test case, always send the request
|
|
|
|
self->mPendingGUMRequest.AppendElement(req.forget());
|
|
|
|
} else {
|
|
|
|
obs->NotifyObservers(req, "getUserMedia:request", nullptr);
|
|
|
|
}
|
2015-10-04 03:42:26 +03:00
|
|
|
}
|
2012-10-06 04:20:47 +04:00
|
|
|
|
2014-06-09 22:45:14 +04:00
|
|
|
#ifdef MOZ_WEBRTC
|
2015-10-04 03:42:26 +03:00
|
|
|
EnableWebRtcLog();
|
2014-06-09 22:45:14 +04:00
|
|
|
#endif
|
2018-09-25 20:03:50 +03:00
|
|
|
}, [onFailure, windowID](nsresult reason) mutable {
|
|
|
|
LOG(("GetUserMedia: post enumeration promse2 failure callback called!"));
|
|
|
|
nsPIDOMWindowInner* window =
|
|
|
|
nsGlobalWindowInner::GetInnerWindowWithId(windowID)->AsInner();
|
|
|
|
auto error = MakeRefPtr<MediaStreamError>(window, MediaStreamError::Name::AbortError);
|
|
|
|
CallOnError(onFailure, *error);
|
2015-10-04 03:42:26 +03:00
|
|
|
});
|
2018-09-25 20:03:50 +03:00
|
|
|
}, [onFailure](RefPtr<MediaStreamError>&& reason) mutable {
|
|
|
|
LOG(("GetUserMedia: post enumeration promise failure callback called!"));
|
2018-07-28 07:40:26 +03:00
|
|
|
CallOnError(onFailure, *reason);
|
2015-07-03 01:01:52 +03:00
|
|
|
});
|
2012-06-03 11:35:15 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2015-06-18 18:46:36 +03:00
|
|
|
/* static */ void
|
2018-07-16 12:30:46 +03:00
|
|
|
MediaManager::AnonymizeDevices(MediaDeviceSet& aDevices, const nsACString& aOriginKey)
|
2012-09-20 23:54:00 +04:00
|
|
|
{
|
2015-06-18 18:46:36 +03:00
|
|
|
if (!aOriginKey.IsEmpty()) {
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
for (RefPtr<MediaDevice>& device : aDevices) {
|
2015-06-18 18:46:36 +03:00
|
|
|
nsString id;
|
|
|
|
device->GetId(id);
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
nsString rawId(id);
|
2015-06-18 18:46:36 +03:00
|
|
|
AnonymizeId(id, aOriginKey);
|
2018-07-16 12:29:12 +03:00
|
|
|
device = new MediaDevice(device, id, rawId);
|
2015-06-18 18:46:36 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-09-20 23:54:00 +04:00
|
|
|
|
2015-06-18 18:46:36 +03:00
|
|
|
/* static */ nsresult
|
|
|
|
MediaManager::AnonymizeId(nsAString& aId, const nsACString& aOriginKey)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2012-10-18 22:31:00 +04:00
|
|
|
|
2015-06-18 18:46:36 +03:00
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIKeyObjectFactory> factory =
|
|
|
|
do_GetService("@mozilla.org/security/keyobjectfactory;1", &rv);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
nsCString rawKey;
|
|
|
|
rv = Base64Decode(aOriginKey, rawKey);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
nsCOMPtr<nsIKeyObject> key;
|
|
|
|
rv = factory->KeyFromString(nsIKeyObject::HMAC, rawKey, getter_AddRefs(key));
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsICryptoHMAC> hasher =
|
|
|
|
do_CreateInstance(NS_CRYPTO_HMAC_CONTRACTID, &rv);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
rv = hasher->Init(nsICryptoHMAC::SHA256, key);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
NS_ConvertUTF16toUTF8 id(aId);
|
|
|
|
rv = hasher->Update(reinterpret_cast<const uint8_t*> (id.get()), id.Length());
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
nsCString mac;
|
|
|
|
rv = hasher->Finish(true, mac);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
aId = NS_ConvertUTF8toUTF16(mac);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
already_AddRefed<nsIWritableVariant>
|
2018-07-16 12:30:46 +03:00
|
|
|
MediaManager::ToJSArray(MediaDeviceSet& aDevices)
|
2015-06-18 18:46:36 +03:00
|
|
|
{
|
2015-10-09 20:24:23 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<nsVariantCC> var = new nsVariantCC();
|
2015-06-18 18:46:36 +03:00
|
|
|
size_t len = aDevices.Length();
|
|
|
|
if (len) {
|
|
|
|
nsTArray<nsIMediaDevice*> tmp(len);
|
|
|
|
for (auto& device : aDevices) {
|
|
|
|
tmp.AppendElement(device);
|
|
|
|
}
|
|
|
|
auto* elements = static_cast<const void*>(tmp.Elements());
|
|
|
|
nsresult rv = var->SetAsArray(nsIDataType::VTYPE_INTERFACE,
|
|
|
|
&NS_GET_IID(nsIMediaDevice), len,
|
|
|
|
const_cast<void*>(elements));
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
var->SetAsEmptyArray(); // because SetAsArray() fails on zero length arrays.
|
|
|
|
}
|
|
|
|
return var.forget();
|
|
|
|
}
|
2014-03-27 01:57:46 +04:00
|
|
|
|
2018-09-25 20:03:50 +03:00
|
|
|
RefPtr<MediaManager::MediaDeviceSetPromise>
|
2015-07-24 15:28:17 +03:00
|
|
|
MediaManager::EnumerateDevicesImpl(uint64_t aWindowId,
|
2018-07-16 12:30:46 +03:00
|
|
|
MediaSourceEnum aVideoInputType,
|
|
|
|
MediaSourceEnum aAudioInputType,
|
|
|
|
MediaSinkEnum aAudioOutputType,
|
|
|
|
DeviceEnumerationType aVideoInputEnumType,
|
|
|
|
DeviceEnumerationType aAudioInputEnumType)
|
2015-06-18 18:46:36 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2018-03-16 22:09:26 +03:00
|
|
|
|
2018-07-16 12:30:46 +03:00
|
|
|
LOG(("%s: aWindowId=%" PRIu64 ", aVideoInputType=%" PRIu8 ", aAudioInputType=%" PRIu8
|
|
|
|
", aVideoInputEnumType=%" PRIu8 ", aAudioInputEnumType=%" PRIu8,
|
2018-03-16 22:09:26 +03:00
|
|
|
__func__, aWindowId,
|
2018-07-16 12:30:46 +03:00
|
|
|
static_cast<uint8_t>(aVideoInputType), static_cast<uint8_t>(aAudioInputType),
|
|
|
|
static_cast<uint8_t>(aVideoInputEnumType), static_cast<uint8_t>(aAudioInputEnumType)));
|
2016-01-05 05:16:20 +03:00
|
|
|
nsPIDOMWindowInner* window =
|
2017-11-06 21:09:35 +03:00
|
|
|
nsGlobalWindowInner::GetInnerWindowWithId(aWindowId)->AsInner();
|
2015-06-18 18:46:36 +03:00
|
|
|
|
|
|
|
// To get a device list anonymized for a particular origin, we must:
|
|
|
|
// 1. Get an origin-key (for either regular or private browsing)
|
|
|
|
// 2. Get the raw devices list
|
|
|
|
// 3. Anonymize the raw list with the origin-key.
|
2012-09-20 23:54:00 +04:00
|
|
|
|
2016-11-22 14:38:41 +03:00
|
|
|
nsCOMPtr<nsIPrincipal> principal =
|
2017-11-04 01:25:38 +03:00
|
|
|
nsGlobalWindowInner::Cast(window)->GetPrincipal();
|
2016-11-22 14:38:41 +03:00
|
|
|
MOZ_ASSERT(principal);
|
|
|
|
|
2017-01-28 20:29:13 +03:00
|
|
|
ipc::PrincipalInfo principalInfo;
|
|
|
|
nsresult rv = PrincipalToPrincipalInfo(principal, &principalInfo);
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
2018-09-25 20:03:50 +03:00
|
|
|
nsPIDOMWindowInner* window =
|
|
|
|
nsGlobalWindowInner::GetInnerWindowWithId(aWindowId)->AsInner();
|
|
|
|
return MediaDeviceSetPromise::CreateAndReject(
|
|
|
|
MakeRefPtr<MediaStreamError>(window, MediaStreamError::Name::NotAllowedError), __func__);
|
2017-01-28 20:29:13 +03:00
|
|
|
}
|
2015-06-18 18:46:36 +03:00
|
|
|
|
2015-07-10 17:15:19 +03:00
|
|
|
bool persist = IsActivelyCapturingOrHasAPermission(aWindowId);
|
|
|
|
|
2018-09-25 20:03:50 +03:00
|
|
|
// GetPrincipalKey is an async API that returns a promise.
|
|
|
|
// We use .Then() to pass in a lambda to run back on this same
|
2017-01-28 20:29:13 +03:00
|
|
|
// thread later once GetPrincipalKey resolves. Needed variables are "captured"
|
2015-06-18 18:46:36 +03:00
|
|
|
// (passed by value) safely into the lambda.
|
2018-09-25 20:03:50 +03:00
|
|
|
return media::GetPrincipalKey(principalInfo, persist)
|
|
|
|
->Then(GetMainThreadSerialEventTarget(), __func__,
|
|
|
|
[aWindowId, aVideoInputType,
|
|
|
|
aAudioInputType, aVideoInputEnumType,
|
|
|
|
aAudioInputEnumType, aAudioOutputType](const nsCString& aOriginKey) -> RefPtr<MediaDeviceSetPromise> {
|
2015-06-18 18:46:36 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2017-09-29 22:06:51 +03:00
|
|
|
MediaManager* mgr = MediaManager::GetIfExists();
|
2018-09-25 20:03:50 +03:00
|
|
|
MOZ_ASSERT(mgr);
|
|
|
|
if (!mgr->IsWindowStillActive(aWindowId)) {
|
|
|
|
nsPIDOMWindowInner* window =
|
|
|
|
nsGlobalWindowInner::GetInnerWindowWithId(aWindowId)->AsInner();
|
|
|
|
return MediaDeviceSetPromise::CreateAndReject(
|
|
|
|
MakeRefPtr<MediaStreamError>(window, MediaStreamError::Name::AbortError), __func__);
|
|
|
|
}
|
|
|
|
|
|
|
|
return mgr->EnumerateRawDevices(aWindowId,
|
|
|
|
aVideoInputType,
|
|
|
|
aAudioInputType,
|
|
|
|
aAudioOutputType,
|
|
|
|
aVideoInputEnumType,
|
|
|
|
aAudioInputEnumType)
|
|
|
|
->Then(GetMainThreadSerialEventTarget(), __func__,
|
|
|
|
[aWindowId, aOriginKey,
|
2018-07-16 12:30:46 +03:00
|
|
|
aVideoInputEnumType,
|
|
|
|
aAudioInputEnumType,
|
|
|
|
aVideoInputType,
|
2018-09-25 20:03:50 +03:00
|
|
|
aAudioInputType](RefPtr<MediaDeviceSetRefCnt>&& aDevices) -> RefPtr<MediaDeviceSetPromise> {
|
2015-06-18 18:46:36 +03:00
|
|
|
// Only run if window is still on our active list.
|
2017-09-29 22:06:51 +03:00
|
|
|
MediaManager* mgr = MediaManager::GetIfExists();
|
2018-09-25 20:03:50 +03:00
|
|
|
if (!mgr || !mgr->IsWindowStillActive(aWindowId)) {
|
|
|
|
nsPIDOMWindowInner* window =
|
|
|
|
nsGlobalWindowInner::GetInnerWindowWithId(aWindowId)->AsInner();
|
|
|
|
return MediaDeviceSetPromise::CreateAndReject(
|
|
|
|
MakeRefPtr<MediaStreamError>(window, MediaStreamError::Name::AbortError), __func__);
|
2015-06-18 18:46:36 +03:00
|
|
|
}
|
2017-07-27 11:51:24 +03:00
|
|
|
|
2018-02-13 00:55:45 +03:00
|
|
|
// If we fetched any real cameras or mics, remove the "default" part of
|
|
|
|
// their IDs.
|
2018-07-16 12:30:46 +03:00
|
|
|
if (aVideoInputType == MediaSourceEnum::Camera &&
|
|
|
|
aAudioInputType == MediaSourceEnum::Microphone &&
|
|
|
|
(aVideoInputEnumType != DeviceEnumerationType::Fake ||
|
|
|
|
aAudioInputEnumType != DeviceEnumerationType::Fake)) {
|
2017-07-27 11:51:24 +03:00
|
|
|
mgr->mDeviceIDs.Clear();
|
2018-09-25 20:03:50 +03:00
|
|
|
for (auto& device : **aDevices) {
|
2017-07-27 11:51:24 +03:00
|
|
|
nsString id;
|
|
|
|
device->GetId(id);
|
|
|
|
id.ReplaceSubstring(NS_LITERAL_STRING("default: "), NS_LITERAL_STRING(""));
|
|
|
|
if (!mgr->mDeviceIDs.Contains(id)) {
|
|
|
|
mgr->mDeviceIDs.AppendElement(id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-25 20:03:50 +03:00
|
|
|
if (!mgr->IsWindowStillActive(aWindowId)) {
|
|
|
|
nsPIDOMWindowInner* window =
|
|
|
|
nsGlobalWindowInner::GetInnerWindowWithId(aWindowId)->AsInner();
|
|
|
|
return MediaDeviceSetPromise::CreateAndReject(
|
|
|
|
MakeRefPtr<MediaStreamError>(window, MediaStreamError::Name::AbortError), __func__);
|
2015-06-18 18:46:36 +03:00
|
|
|
}
|
2018-09-25 20:03:50 +03:00
|
|
|
|
|
|
|
MediaManager_AnonymizeDevices(**aDevices, aOriginKey);
|
|
|
|
return MediaDeviceSetPromise::CreateAndResolve(std::move(aDevices), __func__);
|
|
|
|
},
|
|
|
|
[](RefPtr<MediaStreamError>&& reason) {
|
|
|
|
return MediaDeviceSetPromise::CreateAndReject(std::move(reason), __func__);
|
2015-06-18 18:46:36 +03:00
|
|
|
});
|
2018-09-25 20:03:50 +03:00
|
|
|
},
|
|
|
|
[aWindowId](nsresult rs) {
|
|
|
|
NS_WARNING("EnumerateDevicesImpl failed to get Principal Key. Enumeration will not continue.");
|
|
|
|
nsPIDOMWindowInner* window =
|
|
|
|
nsGlobalWindowInner::GetInnerWindowWithId(aWindowId)->AsInner();
|
|
|
|
return MediaDeviceSetPromise::CreateAndReject(
|
|
|
|
MakeRefPtr<MediaStreamError>(window, MediaStreamError::Name::AbortError), __func__);
|
2015-06-18 18:46:36 +03:00
|
|
|
});
|
2012-09-20 23:54:00 +04:00
|
|
|
}
|
|
|
|
|
2015-03-03 17:51:05 +03:00
|
|
|
nsresult
|
2016-01-30 20:05:36 +03:00
|
|
|
MediaManager::EnumerateDevices(nsPIDOMWindowInner* aWindow,
|
2015-03-03 17:51:05 +03:00
|
|
|
nsIGetUserMediaDevicesSuccessCallback* aOnSuccess,
|
2017-09-18 04:52:06 +03:00
|
|
|
nsIDOMGetUserMediaErrorCallback* aOnFailure,
|
|
|
|
dom::CallerType aCallerType)
|
2015-03-03 17:51:05 +03:00
|
|
|
{
|
2015-06-18 18:46:36 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2017-11-02 18:27:33 +03:00
|
|
|
NS_ENSURE_TRUE(!sHasShutdown, NS_ERROR_FAILURE);
|
2015-06-18 18:46:36 +03:00
|
|
|
nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> onSuccess(aOnSuccess);
|
|
|
|
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onFailure(aOnFailure);
|
|
|
|
uint64_t windowId = aWindow->WindowID();
|
|
|
|
|
2016-04-06 15:56:44 +03:00
|
|
|
nsIPrincipal* principal = aWindow->GetExtantDoc()->NodePrincipal();
|
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
RefPtr<GetUserMediaWindowListener> windowListener =
|
|
|
|
GetWindowListener(windowId);
|
|
|
|
if (windowListener) {
|
|
|
|
PrincipalHandle existingPrincipalHandle =
|
|
|
|
windowListener->GetPrincipalHandle();
|
|
|
|
MOZ_ASSERT(PrincipalHandleMatches(existingPrincipalHandle, principal));
|
|
|
|
} else {
|
|
|
|
windowListener = new GetUserMediaWindowListener(mMediaThread, windowId,
|
|
|
|
MakePrincipalHandle(principal));
|
|
|
|
AddWindowID(windowId, windowListener);
|
|
|
|
}
|
2015-09-04 02:09:34 +03:00
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
// Create an inactive SourceListener to act as a placeholder, so the
|
|
|
|
// window listener doesn't clean itself up until we're done.
|
|
|
|
RefPtr<SourceListener> sourceListener = new SourceListener();
|
|
|
|
windowListener->Register(sourceListener);
|
2015-03-03 17:51:05 +03:00
|
|
|
|
2018-03-16 22:09:26 +03:00
|
|
|
DeviceEnumerationType videoEnumerationType = DeviceEnumerationType::Normal;
|
|
|
|
DeviceEnumerationType audioEnumerationType = DeviceEnumerationType::Normal;
|
Bug 1436523 - Rework media manager enumeration to prefer loopback to fake devices, allow mixing of fake and loopback. r=achronop
Change the media manager so that if fake and loopback devices are requested,
loopback is preferred. With this change loopback and fake devices can also be
mixed. Since the fake flag is coarse, and does not specify fake audio or video,
we would previously just make everything fake. As loopback sets flags for video
and audio separately, we can now request a single loopback device, while also
setting the fake flag to get a mix. E.g. if we request a loopback audio device,
and set the fake flag, we should get loopback audio and fake video.
This change also attempts to somewhat consolidate where these settings take
place. Previously, EnumerateRawDevices did much of the loopback setup. However,
other steps around fingerprint resistance or fake devices were done in earlier
functions (EnumerateDevices and GetUserMedia). This changeset moves the loopback
setup so that it's more consolidated with the other setup code in these
functions.
MozReview-Commit-ID: FF0bR0Nyws9
--HG--
extra : rebase_source : 374a6fd0842a430e27c695bcf956e2e072a77fc3
2018-02-13 00:56:26 +03:00
|
|
|
bool resistFingerprinting = nsContentUtils::ResistFingerprinting(aCallerType);
|
|
|
|
|
|
|
|
// In order of precedence: resist fingerprinting > loopback > fake pref
|
|
|
|
if (resistFingerprinting) {
|
2018-03-16 22:09:26 +03:00
|
|
|
videoEnumerationType = DeviceEnumerationType::Fake;
|
|
|
|
audioEnumerationType = DeviceEnumerationType::Fake;
|
Bug 1436523 - Rework media manager enumeration to prefer loopback to fake devices, allow mixing of fake and loopback. r=achronop
Change the media manager so that if fake and loopback devices are requested,
loopback is preferred. With this change loopback and fake devices can also be
mixed. Since the fake flag is coarse, and does not specify fake audio or video,
we would previously just make everything fake. As loopback sets flags for video
and audio separately, we can now request a single loopback device, while also
setting the fake flag to get a mix. E.g. if we request a loopback audio device,
and set the fake flag, we should get loopback audio and fake video.
This change also attempts to somewhat consolidate where these settings take
place. Previously, EnumerateRawDevices did much of the loopback setup. However,
other steps around fingerprint resistance or fake devices were done in earlier
functions (EnumerateDevices and GetUserMedia). This changeset moves the loopback
setup so that it's more consolidated with the other setup code in these
functions.
MozReview-Commit-ID: FF0bR0Nyws9
--HG--
extra : rebase_source : 374a6fd0842a430e27c695bcf956e2e072a77fc3
2018-02-13 00:56:26 +03:00
|
|
|
} else {
|
|
|
|
// Handle loopback and fake requests
|
|
|
|
nsAutoCString videoLoopDev, audioLoopDev;
|
|
|
|
bool wantFakes = Preferences::GetBool("media.navigator.streams.fake");
|
|
|
|
// Video
|
|
|
|
Preferences::GetCString("media.video_loopback_dev", videoLoopDev);
|
|
|
|
// Loopback prefs take precedence over fake prefs
|
|
|
|
if (!videoLoopDev.IsEmpty()) {
|
2018-03-16 22:09:26 +03:00
|
|
|
videoEnumerationType = DeviceEnumerationType::Loopback;
|
Bug 1436523 - Rework media manager enumeration to prefer loopback to fake devices, allow mixing of fake and loopback. r=achronop
Change the media manager so that if fake and loopback devices are requested,
loopback is preferred. With this change loopback and fake devices can also be
mixed. Since the fake flag is coarse, and does not specify fake audio or video,
we would previously just make everything fake. As loopback sets flags for video
and audio separately, we can now request a single loopback device, while also
setting the fake flag to get a mix. E.g. if we request a loopback audio device,
and set the fake flag, we should get loopback audio and fake video.
This change also attempts to somewhat consolidate where these settings take
place. Previously, EnumerateRawDevices did much of the loopback setup. However,
other steps around fingerprint resistance or fake devices were done in earlier
functions (EnumerateDevices and GetUserMedia). This changeset moves the loopback
setup so that it's more consolidated with the other setup code in these
functions.
MozReview-Commit-ID: FF0bR0Nyws9
--HG--
extra : rebase_source : 374a6fd0842a430e27c695bcf956e2e072a77fc3
2018-02-13 00:56:26 +03:00
|
|
|
} else if (wantFakes) {
|
2018-03-16 22:09:26 +03:00
|
|
|
videoEnumerationType = DeviceEnumerationType::Fake;
|
Bug 1436523 - Rework media manager enumeration to prefer loopback to fake devices, allow mixing of fake and loopback. r=achronop
Change the media manager so that if fake and loopback devices are requested,
loopback is preferred. With this change loopback and fake devices can also be
mixed. Since the fake flag is coarse, and does not specify fake audio or video,
we would previously just make everything fake. As loopback sets flags for video
and audio separately, we can now request a single loopback device, while also
setting the fake flag to get a mix. E.g. if we request a loopback audio device,
and set the fake flag, we should get loopback audio and fake video.
This change also attempts to somewhat consolidate where these settings take
place. Previously, EnumerateRawDevices did much of the loopback setup. However,
other steps around fingerprint resistance or fake devices were done in earlier
functions (EnumerateDevices and GetUserMedia). This changeset moves the loopback
setup so that it's more consolidated with the other setup code in these
functions.
MozReview-Commit-ID: FF0bR0Nyws9
--HG--
extra : rebase_source : 374a6fd0842a430e27c695bcf956e2e072a77fc3
2018-02-13 00:56:26 +03:00
|
|
|
}
|
|
|
|
// Audio
|
|
|
|
Preferences::GetCString("media.audio_loopback_dev", audioLoopDev);
|
|
|
|
// Loopback prefs take precedence over fake prefs
|
|
|
|
if (!audioLoopDev.IsEmpty()) {
|
2018-03-16 22:09:26 +03:00
|
|
|
audioEnumerationType = DeviceEnumerationType::Loopback;
|
Bug 1436523 - Rework media manager enumeration to prefer loopback to fake devices, allow mixing of fake and loopback. r=achronop
Change the media manager so that if fake and loopback devices are requested,
loopback is preferred. With this change loopback and fake devices can also be
mixed. Since the fake flag is coarse, and does not specify fake audio or video,
we would previously just make everything fake. As loopback sets flags for video
and audio separately, we can now request a single loopback device, while also
setting the fake flag to get a mix. E.g. if we request a loopback audio device,
and set the fake flag, we should get loopback audio and fake video.
This change also attempts to somewhat consolidate where these settings take
place. Previously, EnumerateRawDevices did much of the loopback setup. However,
other steps around fingerprint resistance or fake devices were done in earlier
functions (EnumerateDevices and GetUserMedia). This changeset moves the loopback
setup so that it's more consolidated with the other setup code in these
functions.
MozReview-Commit-ID: FF0bR0Nyws9
--HG--
extra : rebase_source : 374a6fd0842a430e27c695bcf956e2e072a77fc3
2018-02-13 00:56:26 +03:00
|
|
|
} else if (wantFakes) {
|
2018-03-16 22:09:26 +03:00
|
|
|
audioEnumerationType = DeviceEnumerationType::Fake;
|
Bug 1436523 - Rework media manager enumeration to prefer loopback to fake devices, allow mixing of fake and loopback. r=achronop
Change the media manager so that if fake and loopback devices are requested,
loopback is preferred. With this change loopback and fake devices can also be
mixed. Since the fake flag is coarse, and does not specify fake audio or video,
we would previously just make everything fake. As loopback sets flags for video
and audio separately, we can now request a single loopback device, while also
setting the fake flag to get a mix. E.g. if we request a loopback audio device,
and set the fake flag, we should get loopback audio and fake video.
This change also attempts to somewhat consolidate where these settings take
place. Previously, EnumerateRawDevices did much of the loopback setup. However,
other steps around fingerprint resistance or fake devices were done in earlier
functions (EnumerateDevices and GetUserMedia). This changeset moves the loopback
setup so that it's more consolidated with the other setup code in these
functions.
MozReview-Commit-ID: FF0bR0Nyws9
--HG--
extra : rebase_source : 374a6fd0842a430e27c695bcf956e2e072a77fc3
2018-02-13 00:56:26 +03:00
|
|
|
}
|
|
|
|
}
|
2015-03-03 17:51:05 +03:00
|
|
|
|
2018-07-16 12:30:46 +03:00
|
|
|
MediaSinkEnum audioOutputType = MediaSinkEnum::Other;
|
|
|
|
if (Preferences::GetBool("media.setsinkid.enabled")) {
|
|
|
|
audioOutputType = MediaSinkEnum::Speaker;
|
|
|
|
}
|
2018-09-25 20:03:50 +03:00
|
|
|
RefPtr<MediaDeviceSetPromise> p = EnumerateDevicesImpl(windowId,
|
|
|
|
MediaSourceEnum::Camera,
|
|
|
|
MediaSourceEnum::Microphone,
|
|
|
|
audioOutputType,
|
|
|
|
videoEnumerationType,
|
|
|
|
audioEnumerationType);
|
|
|
|
p->Then(GetCurrentThreadSerialEventTarget(), __func__,
|
|
|
|
[onSuccess, windowListener, sourceListener](RefPtr<MediaDeviceSetRefCnt>&& aDevices) mutable {
|
2017-04-26 12:13:40 +03:00
|
|
|
DebugOnly<bool> rv = windowListener->Remove(sourceListener);
|
|
|
|
MOZ_ASSERT(rv);
|
2018-09-25 20:03:50 +03:00
|
|
|
nsCOMPtr<nsIWritableVariant> array = MediaManager_ToJSArray(**aDevices);
|
2015-06-18 18:46:36 +03:00
|
|
|
onSuccess->OnSuccess(array);
|
2018-09-25 20:03:50 +03:00
|
|
|
}, [onFailure, windowListener, sourceListener, windowId](RefPtr<MediaStreamError>&& reason) mutable {
|
|
|
|
MediaManager* mgr = MediaManager::GetIfExists();
|
|
|
|
if (!mgr || !mgr->IsWindowStillActive(windowId)) {
|
|
|
|
// If an error happened, like navigate away
|
|
|
|
// leave the promise pending.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// This may fail, if a new doc has been set the OnNavigation method should
|
|
|
|
// have removed all previous active listeners. Attempt to clean it here,
|
|
|
|
// just in case, but ignore the return value.
|
|
|
|
windowListener->Remove(sourceListener);
|
2015-09-20 09:26:41 +03:00
|
|
|
onFailure->OnError(reason);
|
2015-06-18 18:46:36 +03:00
|
|
|
});
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* GetUserMediaDevices - called by the UI-part of getUserMedia from chrome JS.
|
|
|
|
*/
|
|
|
|
|
|
|
|
nsresult
|
2016-01-30 20:05:36 +03:00
|
|
|
MediaManager::GetUserMediaDevices(nsPIDOMWindowInner* aWindow,
|
2015-06-18 18:46:36 +03:00
|
|
|
const MediaStreamConstraints& aConstraints,
|
2018-07-28 07:40:29 +03:00
|
|
|
dom::MozGetUserMediaDevicesSuccessCallback& aOnSuccess,
|
2016-01-08 01:30:10 +03:00
|
|
|
uint64_t aWindowId,
|
|
|
|
const nsAString& aCallID)
|
2015-06-18 18:46:36 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
if (!aWindowId) {
|
|
|
|
aWindowId = aWindow->WindowID();
|
|
|
|
}
|
|
|
|
|
2015-07-03 01:01:52 +03:00
|
|
|
// Ignore passed-in constraints, instead locate + return already-constrained list.
|
2015-06-18 18:46:36 +03:00
|
|
|
|
2015-07-03 01:01:52 +03:00
|
|
|
nsTArray<nsString>* callIDs;
|
|
|
|
if (!mCallIds.Get(aWindowId, &callIDs)) {
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto& callID : *callIDs) {
|
2016-04-28 03:06:05 +03:00
|
|
|
RefPtr<GetUserMediaTask> task;
|
2016-01-08 01:30:10 +03:00
|
|
|
if (!aCallID.Length() || aCallID == callID) {
|
2016-04-28 03:06:05 +03:00
|
|
|
if (mActiveCallbacks.Get(callID, getter_AddRefs(task))) {
|
2018-07-16 12:30:46 +03:00
|
|
|
nsCOMPtr<nsIWritableVariant> array = MediaManager_ToJSArray(*task->mMediaDeviceSet);
|
2018-07-28 07:40:29 +03:00
|
|
|
aOnSuccess.Call(array);
|
2016-01-08 01:30:10 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2015-06-18 18:46:36 +03:00
|
|
|
}
|
2015-07-03 01:01:52 +03:00
|
|
|
}
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
2015-03-03 17:51:05 +03:00
|
|
|
}
|
|
|
|
|
2012-06-03 11:35:15 +04:00
|
|
|
MediaEngine*
|
2013-11-06 07:32:42 +04:00
|
|
|
MediaManager::GetBackend(uint64_t aWindowId)
|
2012-06-03 11:35:15 +04:00
|
|
|
{
|
2015-11-18 23:03:13 +03:00
|
|
|
MOZ_ASSERT(MediaManager::IsInMediaThread());
|
2012-07-12 15:53:08 +04:00
|
|
|
// Plugin backends as appropriate. The default engine also currently
|
|
|
|
// includes picture support for Android.
|
2012-10-26 04:14:47 +04:00
|
|
|
// This IS called off main-thread.
|
2012-06-03 11:35:15 +04:00
|
|
|
if (!mBackend) {
|
2017-11-02 18:27:33 +03:00
|
|
|
MOZ_RELEASE_ASSERT(!sHasShutdown); // we should never create a new backend in shutdown
|
2012-07-12 15:53:08 +04:00
|
|
|
#if defined(MOZ_WEBRTC)
|
2013-12-06 23:34:40 +04:00
|
|
|
mBackend = new MediaEngineWebRTC(mPrefs);
|
2012-07-12 15:53:08 +04:00
|
|
|
#else
|
2013-11-06 07:32:42 +04:00
|
|
|
mBackend = new MediaEngineDefault();
|
2012-07-12 15:53:08 +04:00
|
|
|
#endif
|
2017-12-06 14:09:40 +03:00
|
|
|
mBackend->AddDeviceChangeCallback(this);
|
2012-06-03 11:35:15 +04:00
|
|
|
}
|
|
|
|
return mBackend;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2012-08-22 19:56:38 +04:00
|
|
|
MediaManager::OnNavigation(uint64_t aWindowID)
|
2012-06-03 11:35:15 +04:00
|
|
|
{
|
2015-09-30 09:08:22 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-12-16 06:16:31 +03:00
|
|
|
LOG(("OnNavigation for %" PRIu64, aWindowID));
|
2012-10-26 04:14:47 +04:00
|
|
|
|
2016-02-05 15:20:20 +03:00
|
|
|
// Stop the streams for this window. The runnables check this value before
|
|
|
|
// making a call to content.
|
2012-06-03 11:35:15 +04:00
|
|
|
|
2015-07-03 01:01:52 +03:00
|
|
|
nsTArray<nsString>* callIDs;
|
|
|
|
if (mCallIds.Get(aWindowID, &callIDs)) {
|
|
|
|
for (auto& callID : *callIDs) {
|
|
|
|
mActiveCallbacks.Remove(callID);
|
2014-01-09 01:51:33 +04:00
|
|
|
}
|
|
|
|
mCallIds.Remove(aWindowID);
|
|
|
|
}
|
|
|
|
|
2012-10-26 04:14:47 +04:00
|
|
|
// This is safe since we're on main-thread, and the windowlist can only
|
2013-01-04 22:11:12 +04:00
|
|
|
// be added to from the main-thread
|
2017-11-06 21:09:35 +03:00
|
|
|
auto* window = nsGlobalWindowInner::GetInnerWindowWithId(aWindowID);
|
2014-09-20 01:24:28 +04:00
|
|
|
if (window) {
|
2018-02-23 17:50:57 +03:00
|
|
|
IterateWindowListeners(window->AsInner(),
|
|
|
|
[self = RefPtr<MediaManager>(this),
|
|
|
|
windowID = DebugOnly<decltype(aWindowID)>(aWindowID)]
|
|
|
|
(GetUserMediaWindowListener* aListener)
|
|
|
|
{
|
|
|
|
// Grab a strong ref since RemoveAll() might destroy the listener
|
|
|
|
// mid-way when clearing the mActiveWindows reference.
|
|
|
|
RefPtr<GetUserMediaWindowListener> listener(aListener);
|
|
|
|
|
|
|
|
listener->Stop();
|
|
|
|
listener->RemoveAll();
|
|
|
|
MOZ_ASSERT(!self->GetWindowListener(windowID));
|
|
|
|
});
|
2014-09-20 01:24:28 +04:00
|
|
|
} else {
|
|
|
|
RemoveWindowID(aWindowID);
|
2012-10-25 03:21:15 +04:00
|
|
|
}
|
2017-04-26 12:13:40 +03:00
|
|
|
MOZ_ASSERT(!GetWindowListener(aWindowID));
|
2016-08-11 20:04:49 +03:00
|
|
|
|
|
|
|
RemoveMediaDevicesCallback(aWindowID);
|
2018-01-31 21:03:39 +03:00
|
|
|
|
|
|
|
RefPtr<MediaManager> self = this;
|
|
|
|
MediaManager::PostTask(NewTaskFrom([self, aWindowID]() {
|
|
|
|
self->GetBackend()->ReleaseResourcesForWindow(aWindowID);
|
|
|
|
}));
|
2016-08-11 20:04:49 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MediaManager::RemoveMediaDevicesCallback(uint64_t aWindowID)
|
|
|
|
{
|
2016-11-20 10:39:08 +03:00
|
|
|
MutexAutoLock lock(mCallbackMutex);
|
2016-08-11 20:04:49 +03:00
|
|
|
for (DeviceChangeCallback* observer : mDeviceChangeCallbackList)
|
|
|
|
{
|
|
|
|
dom::MediaDevices* mediadevices = static_cast<dom::MediaDevices *>(observer);
|
|
|
|
MOZ_ASSERT(mediadevices);
|
|
|
|
if (mediadevices) {
|
|
|
|
nsPIDOMWindowInner* window = mediadevices->GetOwner();
|
|
|
|
MOZ_ASSERT(window);
|
2016-08-25 09:07:42 +03:00
|
|
|
if (window && window->WindowID() == aWindowID) {
|
2016-11-20 10:39:08 +03:00
|
|
|
DeviceChangeCallback::RemoveDeviceChangeCallbackLocked(observer);
|
2016-08-11 20:04:49 +03:00
|
|
|
return;
|
2016-08-25 09:07:42 +03:00
|
|
|
}
|
2016-08-11 20:04:49 +03:00
|
|
|
}
|
|
|
|
}
|
2013-01-07 06:31:32 +04:00
|
|
|
}
|
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
void
|
|
|
|
MediaManager::AddWindowID(uint64_t aWindowId,
|
|
|
|
GetUserMediaWindowListener* aListener)
|
2015-03-03 17:51:05 +03:00
|
|
|
{
|
2015-09-30 09:08:22 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2015-03-03 17:51:05 +03:00
|
|
|
// Store the WindowID in a hash table and mark as active. The entry is removed
|
|
|
|
// when this window is closed or navigated away from.
|
|
|
|
// This is safe since we're on main-thread, and the windowlist can only
|
|
|
|
// be invalidated from the main-thread (see OnNavigation)
|
2017-04-26 12:13:40 +03:00
|
|
|
if (IsWindowStillActive(aWindowId)) {
|
|
|
|
MOZ_ASSERT(false, "Window already added");
|
|
|
|
return;
|
2015-03-03 17:51:05 +03:00
|
|
|
}
|
2017-09-01 11:32:33 +03:00
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
GetActiveWindows()->Put(aWindowId, aListener);
|
2015-03-03 17:51:05 +03:00
|
|
|
}
|
|
|
|
|
2014-08-22 14:21:48 +04:00
|
|
|
void
|
|
|
|
MediaManager::RemoveWindowID(uint64_t aWindowId)
|
|
|
|
{
|
|
|
|
mActiveWindows.Remove(aWindowId);
|
|
|
|
|
|
|
|
// get outer windowID
|
2017-11-06 21:09:35 +03:00
|
|
|
auto* window = nsGlobalWindowInner::GetInnerWindowWithId(aWindowId);
|
2014-08-22 14:21:48 +04:00
|
|
|
if (!window) {
|
2016-12-16 06:16:31 +03:00
|
|
|
LOG(("No inner window for %" PRIu64, aWindowId));
|
2014-08-22 14:21:48 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-01-30 20:05:36 +03:00
|
|
|
nsPIDOMWindowOuter* outer = window->AsInner()->GetOuterWindow();
|
2014-08-22 14:21:48 +04:00
|
|
|
if (!outer) {
|
2016-12-16 06:16:31 +03:00
|
|
|
LOG(("No outer window for inner %" PRIu64, aWindowId));
|
2014-08-22 14:21:48 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t outerID = outer->WindowID();
|
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
// Notify the UI that this window no longer has gUM active
|
|
|
|
char windowBuffer[32];
|
|
|
|
SprintfLiteral(windowBuffer, "%" PRIu64, outerID);
|
|
|
|
nsString data = NS_ConvertUTF8toUTF16(windowBuffer);
|
2017-05-03 14:14:18 +03:00
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
|
|
|
obs->NotifyObservers(nullptr, "recording-window-ended", data.get());
|
|
|
|
LOG(("Sent recording-window-ended for window %" PRIu64 " (outer %" PRIu64 ")",
|
|
|
|
aWindowId, outerID));
|
2017-04-27 01:21:54 +03:00
|
|
|
}
|
|
|
|
|
2018-03-19 11:40:38 +03:00
|
|
|
bool
|
|
|
|
MediaManager::IsWindowListenerStillActive(GetUserMediaWindowListener* aListener)
|
|
|
|
{
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(aListener);
|
|
|
|
return aListener && aListener == GetWindowListener(aListener->WindowID());
|
|
|
|
}
|
|
|
|
|
2013-03-05 01:02:17 +04:00
|
|
|
void
|
|
|
|
MediaManager::GetPref(nsIPrefBranch *aBranch, const char *aPref,
|
|
|
|
const char *aData, int32_t *aVal)
|
|
|
|
{
|
|
|
|
int32_t temp;
|
|
|
|
if (aData == nullptr || strcmp(aPref,aData) == 0) {
|
|
|
|
if (NS_SUCCEEDED(aBranch->GetIntPref(aPref, &temp))) {
|
|
|
|
*aVal = temp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-06 23:34:40 +04:00
|
|
|
void
|
|
|
|
MediaManager::GetPrefBool(nsIPrefBranch *aBranch, const char *aPref,
|
|
|
|
const char *aData, bool *aVal)
|
|
|
|
{
|
|
|
|
bool temp;
|
|
|
|
if (aData == nullptr || strcmp(aPref,aData) == 0) {
|
|
|
|
if (NS_SUCCEEDED(aBranch->GetBoolPref(aPref, &temp))) {
|
|
|
|
*aVal = temp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-05 01:02:17 +04:00
|
|
|
void
|
|
|
|
MediaManager::GetPrefs(nsIPrefBranch *aBranch, const char *aData)
|
|
|
|
{
|
|
|
|
GetPref(aBranch, "media.navigator.video.default_width", aData, &mPrefs.mWidth);
|
|
|
|
GetPref(aBranch, "media.navigator.video.default_height", aData, &mPrefs.mHeight);
|
|
|
|
GetPref(aBranch, "media.navigator.video.default_fps", aData, &mPrefs.mFPS);
|
2015-09-24 16:23:37 +03:00
|
|
|
GetPref(aBranch, "media.navigator.audio.fake_frequency", aData, &mPrefs.mFreq);
|
2016-01-23 00:46:38 +03:00
|
|
|
#ifdef MOZ_WEBRTC
|
|
|
|
GetPrefBool(aBranch, "media.getusermedia.aec_enabled", aData, &mPrefs.mAecOn);
|
|
|
|
GetPrefBool(aBranch, "media.getusermedia.agc_enabled", aData, &mPrefs.mAgcOn);
|
|
|
|
GetPrefBool(aBranch, "media.getusermedia.noise_enabled", aData, &mPrefs.mNoiseOn);
|
|
|
|
GetPref(aBranch, "media.getusermedia.aec", aData, &mPrefs.mAec);
|
|
|
|
GetPref(aBranch, "media.getusermedia.agc", aData, &mPrefs.mAgc);
|
|
|
|
GetPref(aBranch, "media.getusermedia.noise", aData, &mPrefs.mNoise);
|
2016-04-20 03:20:45 +03:00
|
|
|
GetPrefBool(aBranch, "media.getusermedia.aec_extended_filter", aData, &mPrefs.mExtendedFilter);
|
|
|
|
GetPrefBool(aBranch, "media.getusermedia.aec_aec_delay_agnostic", aData, &mPrefs.mDelayAgnostic);
|
2017-06-30 07:01:17 +03:00
|
|
|
GetPref(aBranch, "media.getusermedia.channels", aData, &mPrefs.mChannels);
|
2016-08-09 11:37:04 +03:00
|
|
|
GetPrefBool(aBranch, "media.ondevicechange.fakeDeviceChangeEvent.enabled", aData, &mPrefs.mFakeDeviceChangeEventOn);
|
2016-01-23 00:46:38 +03:00
|
|
|
#endif
|
2016-01-21 19:51:36 +03:00
|
|
|
GetPrefBool(aBranch, "media.navigator.audio.full_duplex", aData, &mPrefs.mFullDuplex);
|
2013-03-05 01:02:17 +04:00
|
|
|
}
|
|
|
|
|
2015-10-15 06:54:39 +03:00
|
|
|
void
|
|
|
|
MediaManager::Shutdown()
|
2012-06-03 11:35:15 +04:00
|
|
|
{
|
2015-09-30 09:08:22 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2017-11-02 18:27:33 +03:00
|
|
|
if (sHasShutdown) {
|
2015-10-15 06:54:39 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-08-28 08:14:57 +04:00
|
|
|
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
2012-10-06 04:20:47 +04:00
|
|
|
|
2015-10-15 06:54:39 +03:00
|
|
|
obs->RemoveObserver(this, "last-pb-context-exited");
|
|
|
|
obs->RemoveObserver(this, "getUserMedia:privileged:allow");
|
|
|
|
obs->RemoveObserver(this, "getUserMedia:response:allow");
|
|
|
|
obs->RemoveObserver(this, "getUserMedia:response:deny");
|
2018-10-10 11:28:41 +03:00
|
|
|
obs->RemoveObserver(this, "getUserMedia:response:noOSPermission");
|
2015-10-15 06:54:39 +03:00
|
|
|
obs->RemoveObserver(this, "getUserMedia:revoke");
|
|
|
|
|
|
|
|
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
|
|
|
if (prefs) {
|
|
|
|
prefs->RemoveObserver("media.navigator.video.default_width", this);
|
|
|
|
prefs->RemoveObserver("media.navigator.video.default_height", this);
|
|
|
|
prefs->RemoveObserver("media.navigator.video.default_fps", this);
|
|
|
|
prefs->RemoveObserver("media.navigator.audio.fake_frequency", this);
|
2016-01-23 00:46:38 +03:00
|
|
|
#ifdef MOZ_WEBRTC
|
|
|
|
prefs->RemoveObserver("media.getusermedia.aec_enabled", this);
|
|
|
|
prefs->RemoveObserver("media.getusermedia.aec", this);
|
|
|
|
prefs->RemoveObserver("media.getusermedia.agc_enabled", this);
|
|
|
|
prefs->RemoveObserver("media.getusermedia.agc", this);
|
|
|
|
prefs->RemoveObserver("media.getusermedia.noise_enabled", this);
|
|
|
|
prefs->RemoveObserver("media.getusermedia.noise", this);
|
2016-08-09 11:37:04 +03:00
|
|
|
prefs->RemoveObserver("media.ondevicechange.fakeDeviceChangeEvent.enabled", this);
|
2017-06-30 07:01:17 +03:00
|
|
|
prefs->RemoveObserver("media.getusermedia.channels", this);
|
2016-01-23 00:46:38 +03:00
|
|
|
#endif
|
2016-01-21 19:51:36 +03:00
|
|
|
prefs->RemoveObserver("media.navigator.audio.full_duplex", this);
|
2015-10-15 06:54:39 +03:00
|
|
|
}
|
|
|
|
|
2017-11-06 17:27:36 +03:00
|
|
|
{
|
|
|
|
// Close off any remaining active windows.
|
|
|
|
|
|
|
|
// Live capture at this point is rare but can happen. Stopping it will make
|
|
|
|
// the window listeners attempt to remove themselves from the active windows
|
|
|
|
// table. We cannot touch the table at point so we grab a copy of the window
|
|
|
|
// listeners first.
|
|
|
|
nsTArray<RefPtr<GetUserMediaWindowListener>> listeners(GetActiveWindows()->Count());
|
|
|
|
for (auto iter = GetActiveWindows()->Iter(); !iter.Done(); iter.Next()) {
|
|
|
|
listeners.AppendElement(iter.UserData());
|
|
|
|
}
|
|
|
|
for (auto& listener : listeners) {
|
|
|
|
listener->Stop();
|
|
|
|
listener->RemoveAll();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
MOZ_ASSERT(GetActiveWindows()->Count() == 0);
|
|
|
|
|
2015-10-15 06:54:39 +03:00
|
|
|
GetActiveWindows()->Clear();
|
|
|
|
mActiveCallbacks.Clear();
|
|
|
|
mCallIds.Clear();
|
2017-05-12 06:32:14 +03:00
|
|
|
mPendingGUMRequest.Clear();
|
2017-07-27 11:51:24 +03:00
|
|
|
mDeviceIDs.Clear();
|
2016-02-11 00:10:46 +03:00
|
|
|
#ifdef MOZ_WEBRTC
|
|
|
|
StopWebRtcLog();
|
|
|
|
#endif
|
2012-10-06 04:20:47 +04:00
|
|
|
|
2017-11-02 18:27:33 +03:00
|
|
|
// From main thread's point of view, shutdown is now done.
|
|
|
|
// All that remains is shutting down the media thread.
|
|
|
|
sHasShutdown = true;
|
|
|
|
|
2015-10-15 06:54:39 +03:00
|
|
|
// Because mMediaThread is not an nsThread, we must dispatch to it so it can
|
|
|
|
// clean up BackgroundChild. Continue stopping thread once this is done.
|
2013-03-05 01:02:17 +04:00
|
|
|
|
2016-04-28 03:06:05 +03:00
|
|
|
class ShutdownTask : public Runnable
|
2015-10-15 06:54:39 +03:00
|
|
|
{
|
|
|
|
public:
|
2017-06-12 22:34:10 +03:00
|
|
|
ShutdownTask(MediaManager* aManager, already_AddRefed<Runnable> aReply)
|
|
|
|
: mozilla::Runnable("ShutdownTask")
|
|
|
|
, mManager(aManager)
|
|
|
|
, mReply(aReply)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2015-10-15 06:54:39 +03:00
|
|
|
private:
|
2016-04-28 03:06:05 +03:00
|
|
|
NS_IMETHOD
|
2016-01-18 06:50:29 +03:00
|
|
|
Run() override
|
2015-05-29 21:28:03 +03:00
|
|
|
{
|
2015-10-15 06:54:39 +03:00
|
|
|
LOG(("MediaManager Thread Shutdown"));
|
|
|
|
MOZ_ASSERT(MediaManager::IsInMediaThread());
|
2015-11-18 23:03:13 +03:00
|
|
|
// Must shutdown backend on MediaManager thread, since that's where we started it from!
|
|
|
|
{
|
|
|
|
if (mManager->mBackend) {
|
|
|
|
mManager->mBackend->Shutdown(); // ok to invoke multiple times
|
2016-08-11 20:04:49 +03:00
|
|
|
mManager->mBackend->RemoveDeviceChangeCallback(mManager);
|
2015-11-18 23:03:13 +03:00
|
|
|
}
|
|
|
|
}
|
2015-10-15 06:54:39 +03:00
|
|
|
mozilla::ipc::BackgroundChild::CloseForCurrentThread();
|
|
|
|
// must explicitly do this before dispatching the reply, since the reply may kill us with Stop()
|
2015-11-18 23:03:13 +03:00
|
|
|
mManager->mBackend = nullptr; // last reference, will invoke Shutdown() again
|
2015-10-15 06:54:39 +03:00
|
|
|
|
|
|
|
if (NS_FAILED(NS_DispatchToMainThread(mReply.forget()))) {
|
|
|
|
LOG(("Will leak thread: DispatchToMainthread of reply runnable failed in MediaManager shutdown"));
|
2015-05-29 21:28:03 +03:00
|
|
|
}
|
2016-04-28 03:06:05 +03:00
|
|
|
|
|
|
|
return NS_OK;
|
2015-05-29 21:28:03 +03:00
|
|
|
}
|
2015-11-18 23:03:13 +03:00
|
|
|
RefPtr<MediaManager> mManager;
|
2016-04-26 03:23:21 +03:00
|
|
|
RefPtr<Runnable> mReply;
|
2015-10-15 06:54:39 +03:00
|
|
|
};
|
2015-05-29 21:28:03 +03:00
|
|
|
|
2015-10-15 06:54:39 +03:00
|
|
|
// Post ShutdownTask to execute on mMediaThread and pass in a lambda
|
|
|
|
// callback to be executed back on this thread once it is done.
|
|
|
|
//
|
|
|
|
// The lambda callback "captures" the 'this' pointer for member access.
|
|
|
|
// This is safe since this is guaranteed to be here since sSingleton isn't
|
|
|
|
// cleared until the lambda function clears it.
|
|
|
|
|
|
|
|
// note that this == sSingleton
|
2017-02-04 00:57:49 +03:00
|
|
|
MOZ_ASSERT(this == sSingleton);
|
|
|
|
RefPtr<MediaManager> that = this;
|
|
|
|
|
2015-10-15 06:54:39 +03:00
|
|
|
// Release the backend (and call Shutdown()) from within the MediaManager thread
|
2017-11-02 18:27:33 +03:00
|
|
|
// Don't use MediaManager::PostTask() because we're sHasShutdown=true here!
|
2016-04-28 03:06:05 +03:00
|
|
|
RefPtr<ShutdownTask> shutdown = new ShutdownTask(this,
|
2015-10-15 06:54:39 +03:00
|
|
|
media::NewRunnableFrom([this, that]() mutable {
|
|
|
|
LOG(("MediaManager shutdown lambda running, releasing MediaManager singleton and thread"));
|
|
|
|
if (mMediaThread) {
|
|
|
|
mMediaThread->Stop();
|
|
|
|
}
|
2015-03-29 20:43:43 +03:00
|
|
|
|
2015-10-15 06:54:39 +03:00
|
|
|
// Remove async shutdown blocker
|
2015-03-29 20:43:43 +03:00
|
|
|
|
2015-11-18 23:42:16 +03:00
|
|
|
nsCOMPtr<nsIAsyncShutdownClient> shutdownPhase = GetShutdownPhase();
|
|
|
|
shutdownPhase->RemoveBlocker(sSingleton->mShutdownBlocker);
|
2015-10-15 06:54:39 +03:00
|
|
|
|
|
|
|
// we hold a ref to 'that' which is the same as sSingleton
|
|
|
|
sSingleton = nullptr;
|
2015-05-29 21:28:03 +03:00
|
|
|
|
2012-06-03 11:35:15 +04:00
|
|
|
return NS_OK;
|
2016-04-28 03:06:05 +03:00
|
|
|
}));
|
|
|
|
mMediaThread->message_loop()->PostTask(shutdown.forget());
|
2015-10-15 06:54:39 +03:00
|
|
|
}
|
2012-06-03 11:35:15 +04:00
|
|
|
|
2017-05-12 06:32:14 +03:00
|
|
|
void
|
|
|
|
MediaManager::SendPendingGUMRequest()
|
|
|
|
{
|
|
|
|
if (mPendingGUMRequest.Length() > 0) {
|
|
|
|
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
|
|
|
obs->NotifyObservers(mPendingGUMRequest[0], "getUserMedia:request", nullptr);
|
|
|
|
mPendingGUMRequest.RemoveElementAt(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-10 11:28:41 +03:00
|
|
|
bool
|
|
|
|
IsGUMResponseNoAccess(const char* aTopic, MediaMgrError::Name& aErrorName)
|
|
|
|
{
|
|
|
|
if (!strcmp(aTopic, "getUserMedia:response:deny")) {
|
|
|
|
aErrorName = MediaMgrError::Name::NotAllowedError;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(aTopic, "getUserMedia:response:noOSPermission")) {
|
|
|
|
aErrorName = MediaMgrError::Name::NotFoundError;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-10-15 06:54:39 +03:00
|
|
|
nsresult
|
|
|
|
MediaManager::Observe(nsISupports* aSubject, const char* aTopic,
|
|
|
|
const char16_t* aData)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
2018-10-10 11:28:41 +03:00
|
|
|
MediaMgrError::Name gumNoAccessError = MediaMgrError::Name::NotAllowedError;
|
|
|
|
|
2015-10-15 06:54:39 +03:00
|
|
|
if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
|
|
|
|
nsCOMPtr<nsIPrefBranch> branch( do_QueryInterface(aSubject) );
|
|
|
|
if (branch) {
|
|
|
|
GetPrefs(branch,NS_ConvertUTF16toUTF8(aData).get());
|
2017-10-26 19:37:16 +03:00
|
|
|
LOG(("%s: %dx%d @%dfps", __FUNCTION__,
|
|
|
|
mPrefs.mWidth, mPrefs.mHeight, mPrefs.mFPS));
|
2015-10-15 06:54:39 +03:00
|
|
|
}
|
2015-07-13 06:55:02 +03:00
|
|
|
} else if (!strcmp(aTopic, "last-pb-context-exited")) {
|
|
|
|
// Clear memory of private-browsing-specific deviceIds. Fire and forget.
|
|
|
|
media::SanitizeOriginKeys(0, true);
|
|
|
|
return NS_OK;
|
2017-06-02 23:11:53 +03:00
|
|
|
} else if (!strcmp(aTopic, "getUserMedia:got-device-permission")) {
|
|
|
|
MOZ_ASSERT(aSubject);
|
|
|
|
nsCOMPtr<nsIRunnable> task = do_QueryInterface(aSubject);
|
|
|
|
MediaManager::PostTask(NewTaskFrom([task] {
|
|
|
|
task->Run();
|
|
|
|
}));
|
|
|
|
return NS_OK;
|
2015-07-03 01:01:52 +03:00
|
|
|
} else if (!strcmp(aTopic, "getUserMedia:privileged:allow") ||
|
|
|
|
!strcmp(aTopic, "getUserMedia:response:allow")) {
|
2012-10-06 04:20:47 +04:00
|
|
|
nsString key(aData);
|
2016-04-28 03:06:05 +03:00
|
|
|
RefPtr<GetUserMediaTask> task;
|
|
|
|
mActiveCallbacks.Remove(key, getter_AddRefs(task));
|
2014-09-12 18:49:39 +04:00
|
|
|
if (!task) {
|
2012-10-26 04:14:47 +04:00
|
|
|
return NS_OK;
|
2012-10-06 04:20:47 +04:00
|
|
|
}
|
|
|
|
|
2017-04-24 10:11:51 +03:00
|
|
|
nsTArray<nsString>* array;
|
|
|
|
if (!mCallIds.Get(task->GetWindowID(), &array)) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
array->RemoveElement(key);
|
|
|
|
|
2012-10-06 04:20:47 +04:00
|
|
|
if (aSubject) {
|
2012-12-20 21:03:07 +04:00
|
|
|
// A particular device or devices were chosen by the user.
|
2012-10-16 00:41:46 +04:00
|
|
|
// NOTE: does not allow setting a device to null; assumes nullptr
|
2016-10-14 20:06:37 +03:00
|
|
|
nsCOMPtr<nsIArray> array(do_QueryInterface(aSubject));
|
2012-12-20 21:03:07 +04:00
|
|
|
MOZ_ASSERT(array);
|
|
|
|
uint32_t len = 0;
|
2016-10-14 20:06:37 +03:00
|
|
|
array->GetLength(&len);
|
2015-07-03 01:01:52 +03:00
|
|
|
bool videoFound = false, audioFound = false;
|
2012-12-20 21:03:07 +04:00
|
|
|
for (uint32_t i = 0; i < len; i++) {
|
2016-10-14 20:06:37 +03:00
|
|
|
nsCOMPtr<nsIMediaDevice> device;
|
|
|
|
array->QueryElementAt(i, NS_GET_IID(nsIMediaDevice),
|
|
|
|
getter_AddRefs(device));
|
2012-12-20 21:03:07 +04:00
|
|
|
MOZ_ASSERT(device); // shouldn't be returning anything else...
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
if (!device) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-07-16 12:29:12 +03:00
|
|
|
// Casting here is safe because a MediaDevice is created
|
|
|
|
// only in Gecko side, JS can only query for an instance.
|
|
|
|
MediaDevice* dev = static_cast<MediaDevice*>(device.get());
|
|
|
|
if (dev->mKind == dom::MediaDeviceKind::Videoinput) {
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
if (!videoFound) {
|
2018-07-16 12:29:12 +03:00
|
|
|
task->SetVideoDevice(dev);
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
videoFound = true;
|
2012-12-20 21:03:07 +04:00
|
|
|
}
|
2018-07-16 12:29:12 +03:00
|
|
|
} else if (dev->mKind == dom::MediaDeviceKind::Audioinput) {
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
if (!audioFound) {
|
2018-07-16 12:29:12 +03:00
|
|
|
task->SetAudioDevice(dev);
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
audioFound = true;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
NS_WARNING("Unknown device type in getUserMedia");
|
2012-10-16 00:41:46 +04:00
|
|
|
}
|
2012-10-06 04:20:47 +04:00
|
|
|
}
|
2016-05-06 04:54:04 +03:00
|
|
|
bool needVideo = IsOn(task->GetConstraints().mVideo);
|
|
|
|
bool needAudio = IsOn(task->GetConstraints().mAudio);
|
|
|
|
MOZ_ASSERT(needVideo || needAudio);
|
|
|
|
|
|
|
|
if ((needVideo && !videoFound) || (needAudio && !audioFound)) {
|
2018-04-10 08:22:53 +03:00
|
|
|
task->Denied(MediaMgrError::Name::NotAllowedError);
|
2016-05-06 04:54:04 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2012-10-06 04:20:47 +04:00
|
|
|
}
|
|
|
|
|
2017-11-02 18:27:33 +03:00
|
|
|
if (sHasShutdown) {
|
2018-04-10 08:22:53 +03:00
|
|
|
return task->Denied(MediaMgrError::Name::AbortError,
|
|
|
|
NS_LITERAL_STRING("In shutdown"));
|
2015-05-29 21:28:03 +03:00
|
|
|
}
|
2012-10-26 04:14:47 +04:00
|
|
|
// Reuse the same thread to save memory.
|
2016-04-28 03:06:05 +03:00
|
|
|
MediaManager::PostTask(task.forget());
|
2012-10-06 04:20:47 +04:00
|
|
|
return NS_OK;
|
|
|
|
|
2018-10-10 11:28:41 +03:00
|
|
|
} else if (IsGUMResponseNoAccess(aTopic, gumNoAccessError)) {
|
2012-10-06 04:20:47 +04:00
|
|
|
nsString key(aData);
|
2016-04-28 03:06:05 +03:00
|
|
|
RefPtr<GetUserMediaTask> task;
|
|
|
|
mActiveCallbacks.Remove(key, getter_AddRefs(task));
|
2014-09-12 18:49:39 +04:00
|
|
|
if (task) {
|
2018-10-10 11:28:41 +03:00
|
|
|
task->Denied(gumNoAccessError);
|
2017-04-24 10:11:51 +03:00
|
|
|
nsTArray<nsString>* array;
|
|
|
|
if (!mCallIds.Get(task->GetWindowID(), &array)) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
array->RemoveElement(key);
|
2017-05-12 06:32:14 +03:00
|
|
|
SendPendingGUMRequest();
|
2012-10-06 04:20:47 +04:00
|
|
|
}
|
|
|
|
return NS_OK;
|
2012-06-03 11:35:15 +04:00
|
|
|
|
2013-03-05 01:02:17 +04:00
|
|
|
} else if (!strcmp(aTopic, "getUserMedia:revoke")) {
|
2013-01-04 22:11:12 +04:00
|
|
|
nsresult rv;
|
2014-08-22 13:27:16 +04:00
|
|
|
// may be windowid or screen:windowid
|
|
|
|
nsDependentString data(aData);
|
|
|
|
if (Substring(data, 0, strlen("screen:")).EqualsLiteral("screen:")) {
|
|
|
|
uint64_t windowID = PromiseFlatString(Substring(data, strlen("screen:"))).ToInteger64(&rv);
|
|
|
|
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
2016-12-16 06:16:31 +03:00
|
|
|
LOG(("Revoking Screen/windowCapture access for window %" PRIu64, windowID));
|
2014-08-22 13:27:16 +04:00
|
|
|
StopScreensharing(windowID);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
uint64_t windowID = nsString(aData).ToInteger64(&rv);
|
|
|
|
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
2016-12-16 06:16:31 +03:00
|
|
|
LOG(("Revoking MediaCapture access for window %" PRIu64, windowID));
|
2014-08-22 13:27:16 +04:00
|
|
|
OnNavigation(windowID);
|
|
|
|
}
|
2013-01-04 22:11:12 +04:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-06-03 11:35:15 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2015-09-30 16:40:54 +03:00
|
|
|
nsresult
|
2016-10-14 20:06:27 +03:00
|
|
|
MediaManager::GetActiveMediaCaptureWindows(nsIArray** aArray)
|
2012-12-22 12:09:36 +04:00
|
|
|
{
|
2015-09-30 16:40:54 +03:00
|
|
|
MOZ_ASSERT(aArray);
|
2016-10-14 20:06:27 +03:00
|
|
|
|
|
|
|
nsCOMPtr<nsIMutableArray> array = nsArray::Create();
|
2014-02-24 19:33:32 +04:00
|
|
|
|
2015-09-30 16:40:54 +03:00
|
|
|
for (auto iter = mActiveWindows.Iter(); !iter.Done(); iter.Next()) {
|
|
|
|
const uint64_t& id = iter.Key();
|
2017-04-26 12:13:40 +03:00
|
|
|
RefPtr<GetUserMediaWindowListener> winListener = iter.UserData();
|
|
|
|
if (!winListener) {
|
|
|
|
continue;
|
|
|
|
}
|
2015-09-30 16:40:54 +03:00
|
|
|
|
2016-01-30 20:05:36 +03:00
|
|
|
nsPIDOMWindowInner* window =
|
2017-11-06 21:09:35 +03:00
|
|
|
nsGlobalWindowInner::GetInnerWindowWithId(id)->AsInner();
|
2015-09-30 16:40:54 +03:00
|
|
|
MOZ_ASSERT(window);
|
2016-01-30 20:05:36 +03:00
|
|
|
// XXXkhuey ...
|
2015-09-30 16:40:54 +03:00
|
|
|
if (!window) {
|
|
|
|
continue;
|
|
|
|
}
|
2017-04-26 12:13:40 +03:00
|
|
|
|
2017-11-17 22:13:06 +03:00
|
|
|
if (winListener->CapturingVideo() || winListener->CapturingAudio()) {
|
2017-10-21 17:53:02 +03:00
|
|
|
array->AppendElement(window);
|
2015-09-30 16:40:54 +03:00
|
|
|
}
|
2014-02-24 19:33:32 +04:00
|
|
|
}
|
2012-12-22 12:09:36 +04:00
|
|
|
|
2016-10-14 20:06:27 +03:00
|
|
|
array.forget(aArray);
|
2012-12-22 12:09:36 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2014-09-20 01:24:28 +04:00
|
|
|
struct CaptureWindowStateData {
|
2017-11-17 22:13:06 +03:00
|
|
|
uint16_t* mCamera;
|
|
|
|
uint16_t* mMicrophone;
|
|
|
|
uint16_t* mScreenShare;
|
|
|
|
uint16_t* mWindowShare;
|
|
|
|
uint16_t* mAppShare;
|
|
|
|
uint16_t* mBrowserShare;
|
2014-09-20 01:24:28 +04:00
|
|
|
};
|
|
|
|
|
2013-02-28 00:36:06 +04:00
|
|
|
NS_IMETHODIMP
|
2018-02-23 17:50:57 +03:00
|
|
|
MediaManager::MediaCaptureWindowState(nsIDOMWindow* aCapturedWindow,
|
2017-11-17 22:13:06 +03:00
|
|
|
uint16_t* aCamera,
|
|
|
|
uint16_t* aMicrophone,
|
2018-02-23 17:50:57 +03:00
|
|
|
uint16_t* aScreen,
|
|
|
|
uint16_t* aWindow,
|
|
|
|
uint16_t* aApplication,
|
|
|
|
uint16_t* aBrowser)
|
2013-02-28 00:36:06 +04:00
|
|
|
{
|
2015-09-30 09:08:22 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2018-02-23 17:50:57 +03:00
|
|
|
|
|
|
|
CaptureState camera = CaptureState::Off;
|
|
|
|
CaptureState microphone = CaptureState::Off;
|
|
|
|
CaptureState screen = CaptureState::Off;
|
|
|
|
CaptureState window = CaptureState::Off;
|
|
|
|
CaptureState application = CaptureState::Off;
|
|
|
|
CaptureState browser = CaptureState::Off;
|
|
|
|
|
|
|
|
nsCOMPtr<nsPIDOMWindowInner> piWin = do_QueryInterface(aCapturedWindow);
|
2014-09-20 01:24:28 +04:00
|
|
|
if (piWin) {
|
2018-02-23 17:50:57 +03:00
|
|
|
IterateWindowListeners(piWin,
|
|
|
|
[&camera, µphone, &screen, &window, &application, &browser]
|
|
|
|
(GetUserMediaWindowListener* aListener)
|
|
|
|
{
|
2018-02-23 17:52:03 +03:00
|
|
|
camera = CombineCaptureState(
|
|
|
|
camera, aListener->CapturingSource(MediaSourceEnum::Camera));
|
|
|
|
microphone = CombineCaptureState(
|
|
|
|
microphone, aListener->CapturingSource(MediaSourceEnum::Microphone));
|
|
|
|
screen = CombineCaptureState(
|
|
|
|
screen, aListener->CapturingSource(MediaSourceEnum::Screen));
|
|
|
|
window = CombineCaptureState(
|
|
|
|
window, aListener->CapturingSource(MediaSourceEnum::Window));
|
|
|
|
application = CombineCaptureState(
|
|
|
|
application, aListener->CapturingSource(MediaSourceEnum::Application));
|
|
|
|
browser = CombineCaptureState(
|
|
|
|
browser, aListener->CapturingSource(MediaSourceEnum::Browser));
|
2018-02-23 17:50:57 +03:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
*aCamera = FromCaptureState(camera);
|
|
|
|
*aMicrophone= FromCaptureState(microphone);
|
|
|
|
*aScreen = FromCaptureState(screen);
|
|
|
|
*aWindow = FromCaptureState(window);
|
|
|
|
*aApplication = FromCaptureState(application);
|
|
|
|
*aBrowser = FromCaptureState(browser);
|
|
|
|
|
2014-09-20 01:24:28 +04:00
|
|
|
#ifdef DEBUG
|
2016-12-16 06:16:31 +03:00
|
|
|
LOG(("%s: window %" PRIu64 " capturing %s %s %s %s %s %s", __FUNCTION__, piWin ? piWin->WindowID() : -1,
|
2017-11-17 22:13:06 +03:00
|
|
|
*aCamera == nsIMediaManagerService::STATE_CAPTURE_ENABLED
|
|
|
|
? "camera (enabled)"
|
|
|
|
: (*aCamera == nsIMediaManagerService::STATE_CAPTURE_DISABLED
|
|
|
|
? "camera (disabled)" : ""),
|
|
|
|
*aMicrophone == nsIMediaManagerService::STATE_CAPTURE_ENABLED
|
|
|
|
? "microphone (enabled)"
|
|
|
|
: (*aMicrophone == nsIMediaManagerService::STATE_CAPTURE_DISABLED
|
|
|
|
? "microphone (disabled)" : ""),
|
2018-02-23 17:50:57 +03:00
|
|
|
*aScreen ? "screenshare" : "",
|
|
|
|
*aWindow ? "windowshare" : "",
|
|
|
|
*aApplication ? "appshare" : "",
|
|
|
|
*aBrowser ? "browsershare" : ""));
|
2013-02-28 00:36:06 +04:00
|
|
|
#endif
|
2014-09-20 01:24:28 +04:00
|
|
|
return NS_OK;
|
2015-03-03 17:51:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
MediaManager::SanitizeDeviceIds(int64_t aSinceWhen)
|
|
|
|
{
|
2015-09-30 09:08:22 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-12-16 06:16:31 +03:00
|
|
|
LOG(("%s: sinceWhen = %" PRId64, __FUNCTION__, aSinceWhen));
|
2015-03-03 17:51:05 +03:00
|
|
|
|
2015-07-13 06:55:02 +03:00
|
|
|
media::SanitizeOriginKeys(aSinceWhen, false); // we fire and forget
|
2015-03-03 17:51:05 +03:00
|
|
|
return NS_OK;
|
2015-03-03 17:51:05 +03:00
|
|
|
}
|
|
|
|
|
2014-08-22 13:27:16 +04:00
|
|
|
void
|
|
|
|
MediaManager::StopScreensharing(uint64_t aWindowID)
|
|
|
|
{
|
|
|
|
// We need to stop window/screensharing for all streams in all innerwindows that
|
|
|
|
// correspond to that outerwindow.
|
|
|
|
|
2017-11-06 21:09:35 +03:00
|
|
|
auto* window = nsGlobalWindowInner::GetInnerWindowWithId(aWindowID);
|
2014-08-22 13:27:16 +04:00
|
|
|
if (!window) {
|
|
|
|
return;
|
|
|
|
}
|
2018-02-23 17:50:57 +03:00
|
|
|
IterateWindowListeners(window->AsInner(),
|
|
|
|
[](GetUserMediaWindowListener* aListener)
|
|
|
|
{
|
|
|
|
aListener->StopSharing();
|
|
|
|
});
|
2014-08-22 13:27:16 +04:00
|
|
|
}
|
|
|
|
|
2018-02-23 17:50:57 +03:00
|
|
|
template<typename FunctionType>
|
2014-08-22 13:27:16 +04:00
|
|
|
void
|
2016-01-30 20:05:36 +03:00
|
|
|
MediaManager::IterateWindowListeners(nsPIDOMWindowInner* aWindow,
|
2018-02-23 17:50:57 +03:00
|
|
|
const FunctionType& aCallback)
|
2014-08-22 13:27:16 +04:00
|
|
|
{
|
2014-09-20 01:24:28 +04:00
|
|
|
// Iterate the docshell tree to find all the child windows, and for each
|
|
|
|
// invoke the callback
|
2016-01-30 20:05:36 +03:00
|
|
|
if (aWindow) {
|
2017-04-26 12:13:40 +03:00
|
|
|
{
|
|
|
|
uint64_t windowID = aWindow->WindowID();
|
|
|
|
GetUserMediaWindowListener* listener = GetWindowListener(windowID);
|
2018-02-23 18:34:32 +03:00
|
|
|
if (listener) {
|
|
|
|
aCallback(listener);
|
|
|
|
}
|
2017-04-26 12:13:40 +03:00
|
|
|
// NB: `listener` might have been destroyed.
|
|
|
|
}
|
2014-08-22 13:27:16 +04:00
|
|
|
|
|
|
|
// iterate any children of *this* window (iframes, etc)
|
2016-01-30 20:05:36 +03:00
|
|
|
nsCOMPtr<nsIDocShell> docShell = aWindow->GetDocShell();
|
2014-08-22 13:27:16 +04:00
|
|
|
if (docShell) {
|
|
|
|
int32_t i, count;
|
|
|
|
docShell->GetChildCount(&count);
|
|
|
|
for (i = 0; i < count; ++i) {
|
|
|
|
nsCOMPtr<nsIDocShellTreeItem> item;
|
|
|
|
docShell->GetChildAt(i, getter_AddRefs(item));
|
2016-01-30 20:05:36 +03:00
|
|
|
nsCOMPtr<nsPIDOMWindowOuter> winOuter = item ? item->GetWindow() : nullptr;
|
2014-08-22 13:27:16 +04:00
|
|
|
|
2016-01-30 20:05:36 +03:00
|
|
|
if (winOuter) {
|
2018-02-23 17:50:57 +03:00
|
|
|
IterateWindowListeners(winOuter->GetCurrentInnerWindow(), aCallback);
|
2014-08-22 13:27:16 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-20 01:24:28 +04:00
|
|
|
|
2013-09-13 12:51:48 +04:00
|
|
|
void
|
|
|
|
MediaManager::StopMediaStreams()
|
|
|
|
{
|
2016-10-14 20:06:27 +03:00
|
|
|
nsCOMPtr<nsIArray> array;
|
2013-09-13 12:51:48 +04:00
|
|
|
GetActiveMediaCaptureWindows(getter_AddRefs(array));
|
|
|
|
uint32_t len;
|
2016-10-14 20:06:27 +03:00
|
|
|
array->GetLength(&len);
|
2013-09-13 12:51:48 +04:00
|
|
|
for (uint32_t i = 0; i < len; i++) {
|
2016-10-14 20:06:27 +03:00
|
|
|
nsCOMPtr<nsPIDOMWindowInner> win;
|
|
|
|
array->QueryElementAt(i, NS_GET_IID(nsPIDOMWindowInner),
|
|
|
|
getter_AddRefs(win));
|
2013-09-13 12:51:48 +04:00
|
|
|
if (win) {
|
|
|
|
OnNavigation(win->WindowID());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-03 17:51:05 +03:00
|
|
|
bool
|
2015-07-10 06:07:42 +03:00
|
|
|
MediaManager::IsActivelyCapturingOrHasAPermission(uint64_t aWindowId)
|
2015-03-03 17:51:05 +03:00
|
|
|
{
|
2015-07-10 06:07:42 +03:00
|
|
|
// Does page currently have a gUM stream active?
|
|
|
|
|
2016-10-14 20:06:27 +03:00
|
|
|
nsCOMPtr<nsIArray> array;
|
2015-03-03 17:51:05 +03:00
|
|
|
GetActiveMediaCaptureWindows(getter_AddRefs(array));
|
|
|
|
uint32_t len;
|
2016-10-14 20:06:27 +03:00
|
|
|
array->GetLength(&len);
|
2015-03-03 17:51:05 +03:00
|
|
|
for (uint32_t i = 0; i < len; i++) {
|
2016-10-14 20:06:27 +03:00
|
|
|
nsCOMPtr<nsPIDOMWindowInner> win;
|
|
|
|
array->QueryElementAt(i, NS_GET_IID(nsPIDOMWindowInner),
|
|
|
|
getter_AddRefs(win));
|
2015-03-03 17:51:05 +03:00
|
|
|
if (win && win->WindowID() == aWindowId) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2015-07-10 06:07:42 +03:00
|
|
|
|
|
|
|
// Or are persistent permissions (audio or video) granted?
|
|
|
|
|
2017-11-06 21:09:35 +03:00
|
|
|
auto* window = nsGlobalWindowInner::GetInnerWindowWithId(aWindowId);
|
2018-07-04 03:53:18 +03:00
|
|
|
if (NS_WARN_IF(!window) || NS_WARN_IF(!window->GetPrincipal())) {
|
2015-07-10 06:07:42 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// Check if this site has persistent permissions.
|
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIPermissionManager> mgr =
|
|
|
|
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
return false; // no permission manager no permissions!
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t audio = nsIPermissionManager::UNKNOWN_ACTION;
|
|
|
|
uint32_t video = nsIPermissionManager::UNKNOWN_ACTION;
|
|
|
|
{
|
2018-07-04 03:53:18 +03:00
|
|
|
auto* principal = window->GetPrincipal();
|
2015-07-10 06:07:42 +03:00
|
|
|
rv = mgr->TestExactPermissionFromPrincipal(principal, "microphone", &audio);
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
rv = mgr->TestExactPermissionFromPrincipal(principal, "camera", &video);
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return audio == nsIPermissionManager::ALLOW_ACTION ||
|
|
|
|
video == nsIPermissionManager::ALLOW_ACTION;
|
2015-03-03 17:51:05 +03:00
|
|
|
}
|
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
SourceListener::SourceListener()
|
2017-10-02 16:13:15 +03:00
|
|
|
: mStopped(false)
|
2017-04-26 12:13:40 +03:00
|
|
|
, mFinished(false)
|
|
|
|
, mRemoved(false)
|
|
|
|
, mMainThreadCheck(nullptr)
|
|
|
|
, mPrincipalHandle(PRINCIPAL_HANDLE_NONE)
|
|
|
|
, mWindowListener(nullptr)
|
|
|
|
{}
|
|
|
|
|
|
|
|
void
|
|
|
|
SourceListener::Register(GetUserMediaWindowListener* aListener)
|
|
|
|
{
|
2017-03-29 13:07:45 +03:00
|
|
|
LOG(("SourceListener %p registering with window listener %p", this, aListener));
|
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
MOZ_ASSERT(aListener, "No listener");
|
|
|
|
MOZ_ASSERT(!mWindowListener, "Already registered");
|
|
|
|
MOZ_ASSERT(!Activated(), "Already activated");
|
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
mPrincipalHandle = aListener->GetPrincipalHandle();
|
|
|
|
mWindowListener = aListener;
|
|
|
|
}
|
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
void
|
2017-04-26 12:13:40 +03:00
|
|
|
SourceListener::Activate(SourceMediaStream* aStream,
|
Bug 1299515 - Flatten MediaEngineSource class hierarchy. r=jib
The scope of flattening this hierarchy quickly grows large, so this patch does
a couple more things:
- Creates a pure interface MediaEngineSourceInterface and a base class
MediaEngineSource with common defaults and refcount support (no state!)
- Breaks out some of the helper classes to dedicated files, e.g.,
AllocationHandle, MediaEnginePrefs.
- Clarifies the threading model (written on one thread *and* under lock,
read under either)
- Fixes style, indentation, include-sorting in the affected files
- Adds comments, especially for clarifying what responsibilities methods have,
and thread usage of class members
- Changes Monitors to Mutexes since we only use them as Mutexes anyhow
- Makes MediaEngineRemoteVideoSource no longer a shared source since we now
support scaling in this source and CamerasChild can act as a broker of frames.
This greatly simplifies it. The only shared source is now
MediaEngineWebRTCMicrophoneSource, so the sharing specific common methods have
been moved to that source.
MozReview-Commit-ID: KeVZQo6gLm2
--HG--
rename : dom/media/webrtc/MediaEngine.h => dom/media/webrtc/MediaEnginePrefs.h
extra : rebase_source : c785a5feb896312912170475d6b8d997e712e48f
2018-01-24 18:49:13 +03:00
|
|
|
MediaDevice* aAudioDevice,
|
|
|
|
MediaDevice* aVideoDevice)
|
2017-04-26 12:13:40 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread");
|
2017-04-26 12:13:40 +03:00
|
|
|
|
2017-03-29 13:07:45 +03:00
|
|
|
LOG(("SourceListener %p activating audio=%p video=%p", this, aAudioDevice, aVideoDevice));
|
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
MOZ_ASSERT(!mStopped, "Cannot activate stopped source listener");
|
|
|
|
MOZ_ASSERT(!Activated(), "Already activated");
|
|
|
|
|
|
|
|
mMainThreadCheck = GetCurrentVirtualThread();
|
|
|
|
mStream = aStream;
|
2018-01-23 13:31:22 +03:00
|
|
|
mStreamListener = new SourceStreamListener(this);
|
2017-11-17 21:56:00 +03:00
|
|
|
if (aAudioDevice) {
|
|
|
|
mAudioDeviceState =
|
|
|
|
MakeUnique<DeviceState>(
|
|
|
|
aAudioDevice,
|
|
|
|
aAudioDevice->GetMediaSource() == dom::MediaSourceEnum::Microphone &&
|
2018-02-19 18:13:43 +03:00
|
|
|
Preferences::GetBool("media.getusermedia.microphone.off_while_disabled.enabled", true));
|
2017-10-02 16:13:15 +03:00
|
|
|
}
|
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
if (aVideoDevice) {
|
|
|
|
mVideoDeviceState =
|
|
|
|
MakeUnique<DeviceState>(
|
|
|
|
aVideoDevice,
|
|
|
|
aVideoDevice->GetMediaSource() == dom::MediaSourceEnum::Camera &&
|
|
|
|
Preferences::GetBool("media.getusermedia.camera.off_while_disabled.enabled", true));
|
2017-04-26 12:13:40 +03:00
|
|
|
}
|
|
|
|
|
2018-01-23 13:31:22 +03:00
|
|
|
mStream->AddListener(mStreamListener);
|
2017-04-26 12:13:40 +03:00
|
|
|
}
|
|
|
|
|
2018-02-16 13:55:27 +03:00
|
|
|
RefPtr<SourceListener::InitPromise>
|
|
|
|
SourceListener::InitializeAsync()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread");
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!mStopped);
|
|
|
|
|
|
|
|
RefPtr<InitPromise> init = MediaManager::PostTask<InitPromise>(__func__,
|
|
|
|
[ stream = mStream
|
|
|
|
, principal = GetPrincipalHandle()
|
|
|
|
, audioDevice = mAudioDeviceState ? mAudioDeviceState->mDevice : nullptr
|
|
|
|
, videoDevice = mVideoDeviceState ? mVideoDeviceState->mDevice : nullptr
|
|
|
|
](MozPromiseHolder<InitPromise>& aHolder)
|
|
|
|
{
|
|
|
|
if (audioDevice) {
|
|
|
|
nsresult rv = audioDevice->SetTrack(stream, kAudioTrack, principal);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
rv = audioDevice->Start();
|
|
|
|
}
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
nsString log;
|
|
|
|
if (rv == NS_ERROR_NOT_AVAILABLE) {
|
2018-09-08 01:12:01 +03:00
|
|
|
log.AssignLiteral("Concurrent mic process limit.");
|
2018-02-16 13:55:27 +03:00
|
|
|
aHolder.Reject(MakeRefPtr<MediaMgrError>(
|
2018-04-10 08:22:53 +03:00
|
|
|
MediaMgrError::Name::NotReadableError, log), __func__);
|
2018-02-16 13:55:27 +03:00
|
|
|
return;
|
|
|
|
}
|
2018-09-08 01:12:01 +03:00
|
|
|
log.AssignLiteral("Starting audio failed");
|
2018-02-16 13:55:27 +03:00
|
|
|
aHolder.Reject(MakeRefPtr<MediaMgrError>(
|
2018-04-06 22:06:16 +03:00
|
|
|
MediaMgrError::Name::AbortError, log), __func__);
|
2018-02-16 13:55:27 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (videoDevice) {
|
|
|
|
nsresult rv = videoDevice->SetTrack(stream, kVideoTrack, principal);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
rv = videoDevice->Start();
|
|
|
|
}
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
if (audioDevice) {
|
|
|
|
if (NS_WARN_IF(NS_FAILED(audioDevice->Stop()))) {
|
|
|
|
MOZ_ASSERT_UNREACHABLE("Stopping audio failed");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nsString log;
|
2018-09-08 01:12:01 +03:00
|
|
|
log.AssignLiteral("Starting video failed");
|
2018-04-06 22:06:16 +03:00
|
|
|
aHolder.Reject(MakeRefPtr<MediaMgrError>(MediaMgrError::Name::AbortError, log), __func__);
|
2018-02-16 13:55:27 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Start() queued the tracks to be added synchronously to avoid races
|
|
|
|
stream->FinishAddTracks();
|
|
|
|
stream->AdvanceKnownTracksTime(STREAM_TIME_MAX);
|
|
|
|
LOG(("started all sources"));
|
|
|
|
|
|
|
|
aHolder.Resolve(true, __func__);
|
|
|
|
});
|
|
|
|
|
|
|
|
return init->Then(GetMainThreadSerialEventTarget(), __func__,
|
|
|
|
[self = RefPtr<SourceListener>(this), this]()
|
|
|
|
{
|
|
|
|
if (mStopped) {
|
|
|
|
// We were shut down during the async init
|
|
|
|
return InitPromise::CreateAndResolve(true, __func__);
|
|
|
|
}
|
|
|
|
|
|
|
|
mStream->SetPullEnabled(true);
|
|
|
|
|
|
|
|
for (DeviceState* state : {mAudioDeviceState.get(),
|
|
|
|
mVideoDeviceState.get()}) {
|
|
|
|
if (!state) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!state->mTrackEnabled);
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!state->mDeviceEnabled);
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!state->mStopped);
|
|
|
|
|
|
|
|
state->mDeviceEnabled = true;
|
|
|
|
state->mTrackEnabled = true;
|
2018-02-14 18:35:45 +03:00
|
|
|
state->mTrackEnabledTime = TimeStamp::Now();
|
2018-02-16 13:55:27 +03:00
|
|
|
}
|
|
|
|
return InitPromise::CreateAndResolve(true, __func__);
|
|
|
|
}, [self = RefPtr<SourceListener>(this), this](RefPtr<MediaMgrError>&& aResult)
|
|
|
|
{
|
|
|
|
if (mStopped) {
|
2018-05-30 22:15:35 +03:00
|
|
|
return InitPromise::CreateAndReject(std::move(aResult), __func__);
|
2018-02-16 13:55:27 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
for (DeviceState* state : {mAudioDeviceState.get(),
|
|
|
|
mVideoDeviceState.get()}) {
|
|
|
|
if (!state) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!state->mTrackEnabled);
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!state->mDeviceEnabled);
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(!state->mStopped);
|
|
|
|
|
|
|
|
state->mStopped = true;
|
|
|
|
}
|
2018-05-30 22:15:35 +03:00
|
|
|
return InitPromise::CreateAndReject(std::move(aResult), __func__);
|
2018-02-16 13:55:27 +03:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
void
|
|
|
|
SourceListener::Stop()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread");
|
|
|
|
|
2015-09-30 09:08:26 +03:00
|
|
|
if (mStopped) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-03-29 13:07:45 +03:00
|
|
|
LOG(("SourceListener %p stopping", this));
|
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
// StopSharing() has some special logic, at least for audio capture.
|
|
|
|
// It must be called when all tracks have stopped, before setting mStopped.
|
|
|
|
StopSharing();
|
|
|
|
|
|
|
|
mStopped = true;
|
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
MOZ_ASSERT(Activated(), "There are no devices or any source stream to stop");
|
|
|
|
MOZ_ASSERT(mStream, "Can't end tracks. No source stream.");
|
2017-10-02 16:13:15 +03:00
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
if (mAudioDeviceState && !mAudioDeviceState->mStopped) {
|
2017-04-26 12:13:40 +03:00
|
|
|
StopTrack(kAudioTrack);
|
|
|
|
}
|
2017-11-17 21:56:00 +03:00
|
|
|
if (mVideoDeviceState && !mVideoDeviceState->mStopped) {
|
2017-04-26 12:13:40 +03:00
|
|
|
StopTrack(kVideoTrack);
|
|
|
|
}
|
2017-10-02 16:13:15 +03:00
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
MediaManager::PostTask(NewTaskFrom([source = mStream]() {
|
2017-04-26 12:13:40 +03:00
|
|
|
MOZ_ASSERT(MediaManager::IsInMediaThread());
|
|
|
|
source->EndAllTrackAndFinish();
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SourceListener::Remove()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2017-11-17 21:56:00 +03:00
|
|
|
|
|
|
|
if (mAudioDeviceState) {
|
|
|
|
mAudioDeviceState->mDisableTimer->Cancel();
|
|
|
|
}
|
|
|
|
if (mVideoDeviceState) {
|
|
|
|
mVideoDeviceState->mDisableTimer->Cancel();
|
|
|
|
}
|
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
if (!mStream || mRemoved) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-03-29 13:07:45 +03:00
|
|
|
LOG(("SourceListener %p removed on purpose, mFinished = %d", this, (int) mFinished));
|
2017-04-26 12:13:40 +03:00
|
|
|
mRemoved = true; // RemoveListener is async, avoid races
|
|
|
|
mWindowListener = nullptr;
|
|
|
|
|
|
|
|
// If it's destroyed, don't call - listener will be removed and we'll be notified!
|
|
|
|
if (!mStream->IsDestroyed()) {
|
2017-12-05 16:34:08 +03:00
|
|
|
// We disable pulling before removing so we don't risk having live tracks
|
|
|
|
// without a listener attached - that wouldn't produce data and would be
|
|
|
|
// illegal to the graph.
|
|
|
|
mStream->SetPullEnabled(false);
|
2018-01-23 13:31:22 +03:00
|
|
|
mStream->RemoveListener(mStreamListener);
|
2017-04-26 12:13:40 +03:00
|
|
|
}
|
2018-01-23 13:31:22 +03:00
|
|
|
mStreamListener = nullptr;
|
2017-04-26 12:13:40 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SourceListener::StopTrack(TrackID aTrackID)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread");
|
2017-11-17 21:56:00 +03:00
|
|
|
MOZ_ASSERT(Activated(), "No device to stop");
|
|
|
|
MOZ_ASSERT(aTrackID == kAudioTrack || aTrackID == kVideoTrack,
|
|
|
|
"Unknown track id");
|
|
|
|
DeviceState& state = GetDeviceStateFor(aTrackID);
|
2017-04-26 12:13:40 +03:00
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
LOG(("SourceListener %p stopping %s track %d",
|
|
|
|
this, aTrackID == kAudioTrack ? "audio" : "video", aTrackID));
|
2017-10-02 16:13:15 +03:00
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
if (state.mStopped) {
|
|
|
|
// device already stopped.
|
2017-10-02 16:13:15 +03:00
|
|
|
return;
|
|
|
|
}
|
2017-11-17 21:56:00 +03:00
|
|
|
state.mStopped = true;
|
2017-04-26 12:13:40 +03:00
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
state.mDisableTimer->Cancel();
|
2017-04-26 12:13:40 +03:00
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
MediaManager::PostTask(NewTaskFrom([device = state.mDevice]() {
|
2017-12-18 18:19:33 +03:00
|
|
|
device->Stop();
|
2017-04-26 12:13:40 +03:00
|
|
|
device->Deallocate();
|
|
|
|
}));
|
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
if ((!mAudioDeviceState || mAudioDeviceState->mStopped) &&
|
|
|
|
(!mVideoDeviceState || mVideoDeviceState->mStopped)) {
|
2017-03-29 13:07:45 +03:00
|
|
|
LOG(("SourceListener %p this was the last track stopped", this));
|
2017-04-26 12:13:40 +03:00
|
|
|
Stop();
|
|
|
|
}
|
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
MOZ_ASSERT(mWindowListener, "Should still have window listener");
|
2017-11-14 13:50:07 +03:00
|
|
|
mWindowListener->ChromeAffectingStateChanged();
|
2013-01-01 03:12:15 +04:00
|
|
|
}
|
|
|
|
|
2017-11-10 17:55:42 +03:00
|
|
|
void
|
2017-11-17 21:56:00 +03:00
|
|
|
SourceListener::GetSettingsFor(TrackID aTrackID,
|
|
|
|
dom::MediaTrackSettings& aOutSettings) const
|
2017-11-10 17:55:42 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread");
|
2017-11-17 21:56:00 +03:00
|
|
|
GetDeviceStateFor(aTrackID).mDevice->GetSettings(aOutSettings);
|
|
|
|
}
|
2017-11-10 17:55:42 +03:00
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
void
|
|
|
|
SourceListener::SetEnabledFor(TrackID aTrackID, bool aEnable)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread");
|
|
|
|
MOZ_ASSERT(Activated(), "No device to set enabled state for");
|
|
|
|
MOZ_ASSERT(aTrackID == kAudioTrack || aTrackID == kVideoTrack,
|
|
|
|
"Unknown track id");
|
|
|
|
|
|
|
|
if (mRemoved) {
|
2017-11-10 17:55:42 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
LOG(("SourceListener %p %s %s track %d",
|
|
|
|
this, aEnable ? "enabling" : "disabling",
|
|
|
|
aTrackID == kAudioTrack ? "audio" : "video", aTrackID));
|
2017-11-10 17:55:42 +03:00
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
DeviceState& state = GetDeviceStateFor(aTrackID);
|
|
|
|
|
|
|
|
state.mTrackEnabled = aEnable;
|
|
|
|
|
|
|
|
if (state.mStopped) {
|
|
|
|
// Device terminally stopped. Updating device state is pointless.
|
|
|
|
return;
|
2017-11-10 17:55:42 +03:00
|
|
|
}
|
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
if (state.mOperationInProgress) {
|
|
|
|
// If a timer is in progress, it needs to be canceled now so the next
|
|
|
|
// DisableTrack() gets a fresh start. Canceling will trigger another
|
|
|
|
// operation.
|
|
|
|
state.mDisableTimer->Cancel();
|
|
|
|
return;
|
|
|
|
}
|
2017-11-10 17:55:42 +03:00
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
if (state.mDeviceEnabled == aEnable) {
|
|
|
|
// Device is already in the desired state.
|
2017-11-10 17:55:42 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
// All paths from here on must end in setting `state.mOperationInProgress`
|
|
|
|
// to false.
|
|
|
|
state.mOperationInProgress = true;
|
2017-11-10 17:55:42 +03:00
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
RefPtr<MediaTimerPromise> timerPromise;
|
|
|
|
if (aEnable) {
|
|
|
|
timerPromise = MediaTimerPromise::CreateAndResolve(true, __func__);
|
2018-02-14 18:35:45 +03:00
|
|
|
state.mTrackEnabledTime = TimeStamp::Now();
|
2017-11-17 21:56:00 +03:00
|
|
|
} else {
|
2018-02-14 18:35:45 +03:00
|
|
|
const TimeDuration maxDelay = TimeDuration::FromMilliseconds(
|
2017-11-17 21:56:00 +03:00
|
|
|
Preferences::GetUint(
|
|
|
|
aTrackID == kAudioTrack
|
|
|
|
? "media.getusermedia.microphone.off_while_disabled.delay_ms"
|
|
|
|
: "media.getusermedia.camera.off_while_disabled.delay_ms",
|
|
|
|
3000));
|
2018-02-14 18:35:45 +03:00
|
|
|
const TimeDuration durationEnabled =
|
|
|
|
TimeStamp::Now() - state.mTrackEnabledTime;
|
|
|
|
const TimeDuration delay =
|
|
|
|
TimeDuration::Max(TimeDuration::FromMilliseconds(0),
|
|
|
|
maxDelay - durationEnabled);
|
|
|
|
timerPromise = state.mDisableTimer->WaitFor(delay, __func__);
|
2017-11-17 21:56:00 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
typedef MozPromise<nsresult, bool, /* IsExclusive = */ true> DeviceOperationPromise;
|
|
|
|
RefPtr<SourceListener> self = this;
|
|
|
|
timerPromise->Then(GetMainThreadSerialEventTarget(), __func__,
|
2018-02-16 13:55:27 +03:00
|
|
|
[self, this, &state, aTrackID, aEnable]() mutable {
|
2017-11-17 21:56:00 +03:00
|
|
|
MOZ_ASSERT(state.mDeviceEnabled != aEnable,
|
|
|
|
"Device operation hasn't started");
|
|
|
|
MOZ_ASSERT(state.mOperationInProgress,
|
|
|
|
"It's our responsibility to reset the inProgress state");
|
|
|
|
|
|
|
|
LOG(("SourceListener %p %s %s track %d - starting device operation",
|
|
|
|
this, aEnable ? "enabling" : "disabling",
|
|
|
|
aTrackID == kAudioTrack ? "audio" : "video",
|
|
|
|
aTrackID));
|
|
|
|
|
2018-04-09 14:53:32 +03:00
|
|
|
if (mRemoved) {
|
|
|
|
// Listener was removed between timer resolving and this runnable.
|
|
|
|
return DeviceOperationPromise::CreateAndResolve(NS_ERROR_ABORT, __func__);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (state.mStopped) {
|
|
|
|
// Source was stopped between timer resolving and this runnable.
|
|
|
|
return DeviceOperationPromise::CreateAndResolve(NS_ERROR_ABORT, __func__);
|
|
|
|
}
|
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
state.mDeviceEnabled = aEnable;
|
|
|
|
|
|
|
|
if (mWindowListener) {
|
|
|
|
mWindowListener->ChromeAffectingStateChanged();
|
2017-11-10 17:55:42 +03:00
|
|
|
}
|
2017-11-17 21:56:00 +03:00
|
|
|
|
|
|
|
if (!state.mOffWhileDisabled) {
|
|
|
|
// If the feature to turn a device off while disabled is itself disabled
|
|
|
|
// we shortcut the device operation and tell the ux-updating code
|
|
|
|
// that everything went fine.
|
|
|
|
return DeviceOperationPromise::CreateAndResolve(NS_OK, __func__);
|
|
|
|
}
|
|
|
|
|
2018-02-15 17:18:12 +03:00
|
|
|
return MediaManager::PostTask<DeviceOperationPromise>(__func__,
|
|
|
|
[self, device = state.mDevice, aEnable]
|
|
|
|
(MozPromiseHolder<DeviceOperationPromise>& h) {
|
|
|
|
h.Resolve(aEnable ? device->Start() : device->Stop(), __func__);
|
|
|
|
});
|
2018-02-16 13:55:27 +03:00
|
|
|
}, []() {
|
2017-11-17 21:56:00 +03:00
|
|
|
// Timer was canceled by us. We signal this with NS_ERROR_ABORT.
|
|
|
|
return DeviceOperationPromise::CreateAndResolve(NS_ERROR_ABORT, __func__);
|
|
|
|
})->Then(GetMainThreadSerialEventTarget(), __func__,
|
|
|
|
[self, this, &state, aTrackID, aEnable](nsresult aResult) mutable {
|
2018-03-07 14:42:58 +03:00
|
|
|
MOZ_ASSERT_IF(aResult != NS_ERROR_ABORT,
|
|
|
|
state.mDeviceEnabled == aEnable);
|
2017-11-17 21:56:00 +03:00
|
|
|
MOZ_ASSERT(state.mOperationInProgress);
|
|
|
|
state.mOperationInProgress = false;
|
|
|
|
|
|
|
|
if (state.mStopped) {
|
|
|
|
// Device was stopped on main thread during the operation. Nothing to do.
|
2017-11-10 17:55:42 +03:00
|
|
|
return;
|
|
|
|
}
|
2017-11-17 21:56:00 +03:00
|
|
|
|
|
|
|
LOG(("SourceListener %p %s %s track %d %s",
|
|
|
|
this,
|
|
|
|
aEnable ? "enabling" : "disabling",
|
|
|
|
aTrackID == kAudioTrack ? "audio" : "video",
|
|
|
|
aTrackID,
|
|
|
|
NS_SUCCEEDED(aResult) ? "succeeded" : "failed"));
|
|
|
|
|
|
|
|
if (NS_FAILED(aResult) && aResult != NS_ERROR_ABORT) {
|
|
|
|
// This path handles errors from starting or stopping the device.
|
|
|
|
// NS_ERROR_ABORT are for cases where *we* aborted. They need graceful
|
|
|
|
// handling.
|
|
|
|
if (aEnable) {
|
|
|
|
// Starting the device failed. Stopping the track here will make the
|
|
|
|
// MediaStreamTrack end after a pass through the MediaStreamGraph.
|
|
|
|
StopTrack(aTrackID);
|
|
|
|
} else {
|
|
|
|
// Stopping the device failed. This is odd, but not fatal.
|
|
|
|
MOZ_ASSERT_UNREACHABLE("The device should be stoppable");
|
|
|
|
|
|
|
|
// To keep our internal state sane in this case, we disallow future
|
|
|
|
// stops due to disable.
|
|
|
|
state.mOffWhileDisabled = false;
|
|
|
|
}
|
2017-11-10 17:55:42 +03:00
|
|
|
return;
|
|
|
|
}
|
2017-11-17 21:56:00 +03:00
|
|
|
|
|
|
|
// This path is for a device operation aResult that was success or
|
|
|
|
// NS_ERROR_ABORT (*we* canceled the operation).
|
|
|
|
// At this point we have to follow up on the intended state, i.e., update
|
|
|
|
// the device state if the track state changed in the meantime.
|
|
|
|
|
|
|
|
if (state.mTrackEnabled == state.mDeviceEnabled) {
|
|
|
|
// Intended state is same as device's current state.
|
|
|
|
// Nothing more to do.
|
2017-11-10 17:55:42 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
// Track state changed during this operation. We'll start over.
|
|
|
|
if (state.mTrackEnabled) {
|
|
|
|
SetEnabledFor(aTrackID, true);
|
|
|
|
} else {
|
|
|
|
SetEnabledFor(aTrackID, false);
|
|
|
|
}
|
2018-02-16 13:55:27 +03:00
|
|
|
}, []() {
|
2017-11-17 21:56:00 +03:00
|
|
|
MOZ_ASSERT_UNREACHABLE("Unexpected and unhandled reject");
|
|
|
|
});
|
2017-11-10 17:55:42 +03:00
|
|
|
}
|
|
|
|
|
2014-08-22 13:27:16 +04:00
|
|
|
void
|
2017-04-26 12:13:40 +03:00
|
|
|
SourceListener::StopSharing()
|
2014-08-22 13:27:16 +04:00
|
|
|
{
|
2015-09-30 09:08:22 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2017-04-26 12:13:40 +03:00
|
|
|
MOZ_RELEASE_ASSERT(mWindowListener);
|
|
|
|
|
|
|
|
if (mStopped) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-03-29 13:07:45 +03:00
|
|
|
LOG(("SourceListener %p StopSharing", this));
|
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
if (mVideoDeviceState &&
|
|
|
|
(mVideoDeviceState->mDevice->GetMediaSource() == MediaSourceEnum::Screen ||
|
|
|
|
mVideoDeviceState->mDevice->GetMediaSource() == MediaSourceEnum::Application ||
|
|
|
|
mVideoDeviceState->mDevice->GetMediaSource() == MediaSourceEnum::Window)) {
|
2016-02-05 15:20:20 +03:00
|
|
|
// We want to stop the whole stream if there's no audio;
|
|
|
|
// just the video track if we have both.
|
|
|
|
// StopTrack figures this out for us.
|
|
|
|
StopTrack(kVideoTrack);
|
2017-04-26 12:13:40 +03:00
|
|
|
}
|
2017-11-17 21:56:00 +03:00
|
|
|
if (mAudioDeviceState &&
|
|
|
|
mAudioDeviceState->mDevice->GetMediaSource() == MediaSourceEnum::AudioCapture) {
|
2017-04-26 12:13:40 +03:00
|
|
|
uint64_t windowID = mWindowListener->WindowID();
|
2017-11-06 21:09:35 +03:00
|
|
|
nsCOMPtr<nsPIDOMWindowInner> window = nsGlobalWindowInner::GetInnerWindowWithId(windowID)->AsInner();
|
2017-04-26 12:13:40 +03:00
|
|
|
MOZ_RELEASE_ASSERT(window);
|
2015-07-24 15:28:16 +03:00
|
|
|
window->SetAudioCapture(false);
|
2018-04-10 18:06:32 +03:00
|
|
|
MediaStreamGraph* graph = mStream->Graph();
|
2017-04-26 12:13:40 +03:00
|
|
|
graph->UnregisterCaptureStreamForWindow(windowID);
|
2015-07-24 15:28:16 +03:00
|
|
|
mStream->Destroy();
|
2014-08-22 13:27:16 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
SourceMediaStream*
|
|
|
|
SourceListener::GetSourceStream()
|
|
|
|
{
|
|
|
|
NS_ASSERTION(mStream,"Getting stream from never-activated SourceListener");
|
2017-10-02 16:13:15 +03:00
|
|
|
return mStream;
|
2017-04-26 12:13:40 +03:00
|
|
|
}
|
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
// Proxy NotifyPull() to sources
|
|
|
|
void
|
|
|
|
SourceListener::NotifyPull(MediaStreamGraph* aGraph,
|
|
|
|
StreamTime aDesiredTime)
|
|
|
|
{
|
2017-11-17 21:56:00 +03:00
|
|
|
if (mAudioDeviceState) {
|
|
|
|
mAudioDeviceState->mDevice->Pull(mStream, kAudioTrack,
|
|
|
|
aDesiredTime, mPrincipalHandle);
|
2017-04-26 12:13:40 +03:00
|
|
|
}
|
2017-11-17 21:56:00 +03:00
|
|
|
if (mVideoDeviceState) {
|
|
|
|
mVideoDeviceState->mDevice->Pull(mStream, kVideoTrack,
|
|
|
|
aDesiredTime, mPrincipalHandle);
|
2017-04-26 12:13:40 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SourceListener::NotifyFinished()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
mFinished = true;
|
|
|
|
if (!mWindowListener) {
|
|
|
|
// Removed explicitly before finished.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-03-29 13:07:45 +03:00
|
|
|
LOG(("SourceListener %p NotifyFinished", this));
|
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
Stop(); // we know it's been activated
|
|
|
|
mWindowListener->Remove(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SourceListener::NotifyRemoved()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2017-03-29 13:06:49 +03:00
|
|
|
LOG(("SourceListener removed, mFinished = %d", (int) mFinished));
|
2017-04-26 12:13:40 +03:00
|
|
|
mRemoved = true;
|
|
|
|
|
2017-10-02 16:13:15 +03:00
|
|
|
if (Activated() && !mFinished) {
|
2017-04-26 12:13:40 +03:00
|
|
|
NotifyFinished();
|
|
|
|
}
|
|
|
|
|
|
|
|
mWindowListener = nullptr;
|
2018-01-23 13:31:22 +03:00
|
|
|
mStreamListener = nullptr;
|
2017-04-26 12:13:40 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
SourceListener::CapturingVideo() const
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2017-11-17 22:13:06 +03:00
|
|
|
return Activated() && mVideoDeviceState && !mVideoDeviceState->mStopped &&
|
2017-11-17 21:56:00 +03:00
|
|
|
(!mVideoDeviceState->mDevice->mSource->IsFake() ||
|
2017-04-26 12:13:40 +03:00
|
|
|
Preferences::GetBool("media.navigator.permission.fake"));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
SourceListener::CapturingAudio() const
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2017-11-17 22:13:06 +03:00
|
|
|
return Activated() && mAudioDeviceState && !mAudioDeviceState->mStopped &&
|
2018-02-20 15:40:46 +03:00
|
|
|
(!mAudioDeviceState->mDevice->mSource->IsFake() ||
|
2017-04-26 12:13:40 +03:00
|
|
|
Preferences::GetBool("media.navigator.permission.fake"));
|
|
|
|
}
|
|
|
|
|
2017-11-17 22:13:06 +03:00
|
|
|
CaptureState
|
|
|
|
SourceListener::CapturingSource(MediaSourceEnum aSource) const
|
2017-04-26 12:13:40 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2017-11-17 22:13:06 +03:00
|
|
|
if ((!GetVideoDevice() || GetVideoDevice()->GetMediaSource() != aSource) &&
|
|
|
|
(!GetAudioDevice() || GetAudioDevice()->GetMediaSource() != aSource)) {
|
|
|
|
// This SourceListener doesn't capture a matching source
|
|
|
|
return CaptureState::Off;
|
|
|
|
}
|
2017-04-26 12:13:40 +03:00
|
|
|
|
2017-11-17 22:13:06 +03:00
|
|
|
DeviceState& state =
|
|
|
|
(GetAudioDevice() && GetAudioDevice()->GetMediaSource() == aSource)
|
|
|
|
? *mAudioDeviceState : *mVideoDeviceState;
|
|
|
|
MOZ_ASSERT(state.mDevice->GetMediaSource() == aSource);
|
2017-04-26 12:13:40 +03:00
|
|
|
|
2017-11-17 22:13:06 +03:00
|
|
|
if (state.mStopped) {
|
|
|
|
// The source is a match but has been permanently stopped
|
|
|
|
return CaptureState::Off;
|
|
|
|
}
|
2017-04-26 12:13:40 +03:00
|
|
|
|
2017-11-17 22:13:06 +03:00
|
|
|
if ((aSource == MediaSourceEnum::Camera ||
|
|
|
|
aSource == MediaSourceEnum::Microphone) &&
|
|
|
|
state.mDevice->mSource->IsFake() &&
|
|
|
|
!Preferences::GetBool("media.navigator.permission.fake")) {
|
|
|
|
// Fake Camera and Microphone only count if there is no fake permission
|
|
|
|
return CaptureState::Off;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Source is a match and is active
|
|
|
|
|
|
|
|
if (state.mDeviceEnabled) {
|
|
|
|
return CaptureState::Enabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
return CaptureState::Disabled;
|
2017-04-26 12:13:40 +03:00
|
|
|
}
|
2015-09-21 01:45:57 +03:00
|
|
|
|
2018-02-23 12:05:42 +03:00
|
|
|
RefPtr<SourceListener::ApplyConstraintsPromise>
|
2017-05-20 03:57:44 +03:00
|
|
|
SourceListener::ApplyConstraintsToTrack(
|
|
|
|
nsPIDOMWindowInner* aWindow,
|
|
|
|
TrackID aTrackID,
|
|
|
|
const MediaTrackConstraints& aConstraintsPassedIn,
|
|
|
|
dom::CallerType aCallerType)
|
2015-09-21 01:45:57 +03:00
|
|
|
{
|
2015-09-20 17:04:51 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2017-11-17 21:56:00 +03:00
|
|
|
DeviceState& state = GetDeviceStateFor(aTrackID);
|
2018-02-23 12:05:42 +03:00
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
if (mStopped || state.mStopped) {
|
2018-02-23 12:05:42 +03:00
|
|
|
LOG(("gUM %s track %d applyConstraints, but source is stopped",
|
|
|
|
aTrackID == kAudioTrack ? "audio" : "video", aTrackID));
|
|
|
|
return ApplyConstraintsPromise::CreateAndResolve(false, __func__);
|
2015-09-21 01:45:57 +03:00
|
|
|
}
|
2017-05-20 03:57:44 +03:00
|
|
|
|
2018-02-23 12:05:42 +03:00
|
|
|
MediaTrackConstraints c(aConstraintsPassedIn); // use a modifiable copy
|
2017-05-20 03:57:44 +03:00
|
|
|
MediaConstraintsHelper::ConvertOldWithWarning(c.mMozAutoGainControl,
|
|
|
|
c.mAutoGainControl,
|
|
|
|
"MozAutoGainControlWarning",
|
|
|
|
aWindow);
|
|
|
|
MediaConstraintsHelper::ConvertOldWithWarning(c.mMozNoiseSuppression,
|
|
|
|
c.mNoiseSuppression,
|
|
|
|
"MozNoiseSuppressionWarning",
|
|
|
|
aWindow);
|
2015-09-20 17:04:51 +03:00
|
|
|
|
2017-09-29 22:06:51 +03:00
|
|
|
MediaManager* mgr = MediaManager::GetIfExists();
|
|
|
|
if (!mgr) {
|
2018-02-23 12:05:42 +03:00
|
|
|
return ApplyConstraintsPromise::CreateAndResolve(false, __func__);
|
2017-09-29 22:06:51 +03:00
|
|
|
}
|
2015-09-20 17:04:51 +03:00
|
|
|
|
2018-02-23 12:05:42 +03:00
|
|
|
return MediaManager::PostTask<ApplyConstraintsPromise>(__func__,
|
|
|
|
[device = state.mDevice, c,
|
|
|
|
isChrome = aCallerType == dom::CallerType::System]
|
|
|
|
(MozPromiseHolder<ApplyConstraintsPromise>& aHolder) mutable {
|
2015-09-20 17:04:51 +03:00
|
|
|
MOZ_ASSERT(MediaManager::IsInMediaThread());
|
2017-09-29 22:06:51 +03:00
|
|
|
MediaManager* mgr = MediaManager::GetIfExists();
|
|
|
|
MOZ_RELEASE_ASSERT(mgr); // Must exist while media thread is alive
|
2015-09-20 17:04:51 +03:00
|
|
|
const char* badConstraint = nullptr;
|
2017-11-17 21:56:00 +03:00
|
|
|
nsresult rv = device->Reconfigure(c, mgr->mPrefs, &badConstraint);
|
2018-02-23 12:05:42 +03:00
|
|
|
if (rv == NS_ERROR_INVALID_ARG) {
|
|
|
|
// Reconfigure failed due to constraints
|
|
|
|
if (!badConstraint) {
|
|
|
|
nsTArray<RefPtr<MediaDevice>> devices;
|
|
|
|
devices.AppendElement(device);
|
|
|
|
badConstraint = MediaConstraintsHelper::SelectSettings(
|
|
|
|
NormalizedConstraints(c), devices, isChrome);
|
2015-09-20 17:04:51 +03:00
|
|
|
}
|
2018-02-23 12:05:42 +03:00
|
|
|
|
|
|
|
aHolder.Reject(Some(NS_ConvertASCIItoUTF16(badConstraint)), __func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
// Reconfigure failed unexpectedly
|
|
|
|
aHolder.Reject(Nothing(), __func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reconfigure was successful
|
|
|
|
aHolder.Resolve(false, __func__);
|
|
|
|
});
|
2015-09-21 01:45:57 +03:00
|
|
|
}
|
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
PrincipalHandle
|
|
|
|
SourceListener::GetPrincipalHandle() const
|
|
|
|
{
|
|
|
|
return mPrincipalHandle;
|
|
|
|
}
|
2014-08-27 09:03:50 +04:00
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
DeviceState&
|
|
|
|
SourceListener::GetDeviceStateFor(TrackID aTrackID) const
|
|
|
|
{
|
|
|
|
// XXX to support multiple tracks of a type in a stream, this should key off
|
|
|
|
// the TrackID and not just the type
|
|
|
|
switch (aTrackID) {
|
|
|
|
case kAudioTrack:
|
|
|
|
MOZ_ASSERT(mAudioDeviceState, "No audio device");
|
|
|
|
return *mAudioDeviceState;
|
|
|
|
case kVideoTrack:
|
|
|
|
MOZ_ASSERT(mVideoDeviceState, "No video device");
|
|
|
|
return *mVideoDeviceState;
|
|
|
|
default:
|
|
|
|
MOZ_CRASH("Unknown track id");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
// Doesn't kill audio
|
2014-08-27 09:03:50 +04:00
|
|
|
void
|
2017-04-26 12:13:40 +03:00
|
|
|
GetUserMediaWindowListener::StopSharing()
|
2014-08-27 09:03:50 +04:00
|
|
|
{
|
2017-04-26 12:13:40 +03:00
|
|
|
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread");
|
2017-05-03 14:14:18 +03:00
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
for (auto& source : mActiveListeners) {
|
|
|
|
source->StopSharing();
|
2014-08-27 09:03:50 +04:00
|
|
|
}
|
2017-04-26 12:13:40 +03:00
|
|
|
}
|
2016-02-05 15:20:20 +03:00
|
|
|
|
2017-07-27 11:51:24 +03:00
|
|
|
void
|
|
|
|
GetUserMediaWindowListener::StopRawID(const nsString& removedDeviceID)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread");
|
|
|
|
|
|
|
|
for (auto& source : mActiveListeners) {
|
|
|
|
if (source->GetAudioDevice()) {
|
|
|
|
nsString id;
|
|
|
|
source->GetAudioDevice()->GetRawId(id);
|
|
|
|
if (removedDeviceID.Equals(id)) {
|
2017-09-27 05:16:46 +03:00
|
|
|
source->StopTrack(kAudioTrack);
|
2017-07-27 11:51:24 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (source->GetVideoDevice()) {
|
|
|
|
nsString id;
|
|
|
|
source->GetVideoDevice()->GetRawId(id);
|
|
|
|
if (removedDeviceID.Equals(id)) {
|
2017-09-27 05:16:46 +03:00
|
|
|
source->StopTrack(kVideoTrack);
|
2017-07-27 11:51:24 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-26 12:13:40 +03:00
|
|
|
void
|
2017-11-14 13:50:07 +03:00
|
|
|
GetUserMediaWindowListener::ChromeAffectingStateChanged()
|
2017-04-26 12:13:40 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2016-02-05 15:20:20 +03:00
|
|
|
|
2016-09-21 16:17:23 +03:00
|
|
|
// We wait until stable state before notifying chrome so chrome only does one
|
2017-11-17 21:56:00 +03:00
|
|
|
// update if more updates happen in this event loop.
|
2016-09-21 16:17:23 +03:00
|
|
|
|
|
|
|
if (mChromeNotificationTaskPosted) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIRunnable> runnable =
|
2017-11-14 13:50:07 +03:00
|
|
|
NewRunnableMethod("GetUserMediaWindowListener::NotifyChrome",
|
2017-06-12 22:34:10 +03:00
|
|
|
this,
|
2017-11-14 13:50:07 +03:00
|
|
|
&GetUserMediaWindowListener::NotifyChrome);
|
2016-09-21 16:17:23 +03:00
|
|
|
nsContentUtils::RunInStableState(runnable.forget());
|
|
|
|
mChromeNotificationTaskPosted = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2017-11-14 13:50:07 +03:00
|
|
|
GetUserMediaWindowListener::NotifyChrome()
|
2016-09-21 16:17:23 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(mChromeNotificationTaskPosted);
|
|
|
|
mChromeNotificationTaskPosted = false;
|
|
|
|
|
2017-11-14 13:50:07 +03:00
|
|
|
NS_DispatchToMainThread(NS_NewRunnableFunction("MediaManager::NotifyChrome",
|
|
|
|
[windowID = mWindowID]() {
|
|
|
|
nsGlobalWindowInner* window =
|
|
|
|
nsGlobalWindowInner::GetInnerWindowWithId(windowID);
|
|
|
|
if (!window) {
|
|
|
|
MOZ_ASSERT_UNREACHABLE("Should have window");
|
|
|
|
return;
|
|
|
|
}
|
2016-06-30 10:07:48 +03:00
|
|
|
|
2017-11-17 21:56:00 +03:00
|
|
|
nsresult rv = MediaManager::NotifyRecordingStatusChange(window->AsInner());
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
MOZ_ASSERT_UNREACHABLE("Should be able to notify chrome");
|
|
|
|
return;
|
|
|
|
}
|
2017-11-14 13:50:07 +03:00
|
|
|
}));
|
2013-08-28 08:14:57 +04:00
|
|
|
}
|
|
|
|
|
2012-06-03 11:35:15 +04:00
|
|
|
} // namespace mozilla
|