From d4bc9fa2377d9fbd86a5c737b5d4da5dcf55ebaf Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Thu, 18 Jun 2015 11:46:36 -0400 Subject: [PATCH] Bug 1173255 - Cleanup MediaManager e10s code in prep for deviceId constraint. r=jesup --HG-- extra : amend_source : 057f17d55cd44a700abab5595c9f4fc95cfd2419 extra : transplant_source : %B7%5C%7D%FA%E9%3F%29%F9%EBM%9E%B5%1A%A6G%29%25%01%0E- extra : histedit_source : a10d0d5106f5fffb3881604728c1933c90772622%2Cdf022706033cb19f87a8dd58376ab7800d9d2526 --- dom/ipc/ContentChild.cpp | 14 + dom/ipc/ContentChild.h | 3 + dom/ipc/ContentParent.cpp | 14 + dom/ipc/ContentParent.h | 3 + dom/ipc/PContent.ipdl | 4 + dom/media/MediaManager.cpp | 655 +++++++----------- dom/media/MediaManager.h | 33 +- dom/media/PeerConnection.js | 1 + dom/media/nsIDOMNavigatorUserMedia.idl | 3 +- dom/media/systemservices/MediaChild.cpp | 124 ++-- dom/media/systemservices/MediaChild.h | 31 +- dom/media/systemservices/MediaParent.cpp | 264 +++---- dom/media/systemservices/MediaParent.h | 35 +- dom/media/systemservices/MediaUtils.h | 173 ++++- dom/media/systemservices/PMedia.ipdl | 3 +- .../test_getUserMedia_constraints.html | 8 - dom/media/webrtc/MediaEngine.h | 4 +- .../webrtc/MediaEngineCameraVideoSource.cpp | 153 +++- .../webrtc/MediaEngineCameraVideoSource.h | 26 +- dom/media/webrtc/MediaEngineDefault.cpp | 8 +- dom/media/webrtc/MediaEngineDefault.h | 4 +- .../webrtc/MediaEngineGonkVideoSource.cpp | 4 +- .../webrtc/MediaEngineTabVideoSource.cpp | 4 +- dom/media/webrtc/MediaEngineTabVideoSource.h | 2 +- dom/media/webrtc/MediaEngineWebRTC.h | 6 +- dom/media/webrtc/MediaEngineWebRTCAudio.cpp | 2 +- dom/media/webrtc/MediaEngineWebRTCVideo.cpp | 20 +- ipc/glue/BackgroundChildImpl.cpp | 13 - ipc/glue/BackgroundChildImpl.h | 6 - ipc/glue/BackgroundParentImpl.cpp | 13 - ipc/glue/BackgroundParentImpl.h | 6 - ipc/glue/PBackground.ipdl | 3 - 32 files changed, 877 insertions(+), 765 deletions(-) diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index 69e149d723fd..c735ac968958 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -52,6 +52,7 @@ #include "mozilla/plugins/PluginInstanceParent.h" #include "mozilla/plugins/PluginModuleParent.h" #include "mozilla/widget/WidgetMessageUtils.h" +#include "mozilla/media/MediaChild.h" #if defined(MOZ_CONTENT_SANDBOX) #if defined(XP_WIN) @@ -204,6 +205,7 @@ using namespace mozilla::dom::mobileconnection; using namespace mozilla::dom::mobilemessage; using namespace mozilla::dom::telephony; using namespace mozilla::dom::voicemail; +using namespace mozilla::media; using namespace mozilla::embedding; using namespace mozilla::gmp; using namespace mozilla::hal_sandbox; @@ -1750,6 +1752,18 @@ ContentChild::DeallocPVoicemailChild(PVoicemailChild* aActor) return true; } +media::PMediaChild* +ContentChild::AllocPMediaChild() +{ + return media::AllocPMediaChild(); +} + +bool +ContentChild::DeallocPMediaChild(media::PMediaChild *aActor) +{ + return media::DeallocPMediaChild(aActor); +} + PStorageChild* ContentChild::AllocPStorageChild() { diff --git a/dom/ipc/ContentChild.h b/dom/ipc/ContentChild.h index 57c9919e010e..2d73db7cea89 100644 --- a/dom/ipc/ContentChild.h +++ b/dom/ipc/ContentChild.h @@ -262,6 +262,9 @@ public: PVoicemailChild* SendPVoicemailConstructor(PVoicemailChild* aActor); virtual bool DeallocPVoicemailChild(PVoicemailChild*) override; + virtual PMediaChild* AllocPMediaChild() override; + virtual bool DeallocPMediaChild(PMediaChild* aActor) override; + virtual PStorageChild* AllocPStorageChild() override; virtual bool DeallocPStorageChild(PStorageChild* aActor) override; diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 1b80fa383e52..c6cd877bdc9e 100755 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -74,6 +74,7 @@ #include "mozilla/layers/ImageBridgeParent.h" #include "mozilla/layers/SharedBufferManagerParent.h" #include "mozilla/LookAndFeel.h" +#include "mozilla/media/MediaParent.h" #include "mozilla/net/NeckoParent.h" #include "mozilla/plugins/PluginBridge.h" #include "mozilla/Preferences.h" @@ -258,6 +259,7 @@ using namespace mozilla::dom::mobileconnection; using namespace mozilla::dom::mobilemessage; using namespace mozilla::dom::telephony; using namespace mozilla::dom::voicemail; +using namespace mozilla::media; using namespace mozilla::embedding; using namespace mozilla::gmp; using namespace mozilla::hal; @@ -3807,6 +3809,18 @@ ContentParent::DeallocPVoicemailParent(PVoicemailParent* aActor) return true; } +media::PMediaParent* +ContentParent::AllocPMediaParent() +{ + return media::AllocPMediaParent(); +} + +bool +ContentParent::DeallocPMediaParent(media::PMediaParent *aActor) +{ + return media::DeallocPMediaParent(aActor); +} + PStorageParent* ContentParent::AllocPStorageParent() { diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h index 56410e89abd9..0c81bf7aa0a1 100644 --- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -646,6 +646,9 @@ private: virtual bool RecvPVoicemailConstructor(PVoicemailParent* aActor) override; virtual bool DeallocPVoicemailParent(PVoicemailParent* aActor) override; + virtual PMediaParent* AllocPMediaParent() override; + virtual bool DeallocPMediaParent(PMediaParent* aActor) override; + virtual bool DeallocPStorageParent(PStorageParent* aActor) override; virtual PBluetoothParent* AllocPBluetoothParent() override; diff --git a/dom/ipc/PContent.ipdl b/dom/ipc/PContent.ipdl index 33cc91b49880..254e58976aa0 100644 --- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -25,6 +25,7 @@ include protocol PHal; include protocol PIcc; include protocol PProcessHangMonitor; include protocol PImageBridge; +include protocol PMedia; include protocol PMemoryReportRequest; include protocol PMobileConnection; include protocol PNecko; @@ -429,6 +430,7 @@ prio(normal upto urgent) sync protocol PContent manages PFMRadio; manages PHal; manages PIcc; + manages PMedia; manages PMemoryReportRequest; manages PMobileConnection; manages PNecko; @@ -764,6 +766,8 @@ parent: PVoicemail(); + PMedia(); + PBluetooth(); PFMRadio(); diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index 9891dd174403..7ec4e4f19086 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -123,6 +123,9 @@ using dom::Sequence; using dom::OwningBooleanOrMediaTrackConstraints; using dom::SupportedAudioConstraints; using dom::SupportedVideoConstraints; +using media::Pledge; +using media::NewRunnableFrom; +using media::NewTaskFrom; static Atomic sInShutdown; @@ -267,150 +270,6 @@ private: nsRefPtr mManager; // get ref to this when creating the runnable }; -/** - * Invoke the GetUserMediaDevices success callback. Wrapped in a runnable - * so that it may be called on the main thread. The error callback is also - * passed so it can be released correctly. - */ -class DeviceSuccessCallbackRunnable : public nsRunnable -{ -public: - DeviceSuccessCallbackRunnable( - uint64_t aWindowID, - nsCOMPtr& aOnSuccess, - nsCOMPtr& aOnFailure, - nsTArray>* aDevices, - bool aIsGum) - : mDevices(aDevices) - , mWindowID(aWindowID) - , mIsGum(aIsGum) - , mManager(MediaManager::GetInstance()) - { - mOnSuccess.swap(aOnSuccess); - mOnFailure.swap(aOnFailure); - } - - ~DeviceSuccessCallbackRunnable() - { - if (!NS_IsMainThread()) { - // This can happen if the main thread processes the runnable before - // GetUserMediaDevicesTask::Run returns. - nsCOMPtr mainThread = do_GetMainThread(); - - NS_ProxyRelease(mainThread, mOnSuccess); - NS_ProxyRelease(mainThread, mOnFailure); - } - } - - nsresult - AnonymizeId(nsAString& aId, const nsACString& aOriginKey) - { - nsresult rv; - nsCOMPtr 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 key; - rv = factory->KeyFromString(nsIKeyObject::HMAC, rawKey, getter_AddRefs(key)); - if (NS_FAILED(rv)) { - return rv; - } - - nsCOMPtr 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 (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; - } - - NS_IMETHOD - Run() - { - NS_ASSERTION(NS_IsMainThread(), "Only call on main thread"); - - // Only run if window is still on our active list. - if (!mManager->IsWindowStillActive(mWindowID)) { - return NS_OK; - } - - nsCOMPtr devices = - do_CreateInstance("@mozilla.org/variant;1"); - - size_t len = mDevices->Length(); - - if (!len) { - if (mIsGum) { // gUM fails on 0 devices whereas enumerateDevices doesn't. - // XXX - // We should in the future return an empty array, and dynamically add - // devices to the dropdowns if things are hotplugged while the - // requester is up. - nsGlobalWindow* window = nsGlobalWindow::GetInnerWindowWithId(mWindowID); - if (window) { - nsRefPtr error = new MediaStreamError(window, - NS_LITERAL_STRING("NotFoundError")); - mOnFailure->OnError(error); - } - return NS_OK; - } - devices->SetAsEmptyArray(); // SetAsArray() fails on zero length arrays. - } else { - nsTArray tmp(len); - for (auto& device : *mDevices) { - if (!mOriginKey.IsEmpty()) { - nsString id; - device->GetId(id); - AnonymizeId(id, mOriginKey); - device->SetId(id); - } - tmp.AppendElement(device); - } - nsresult rv = devices->SetAsArray(nsIDataType::VTYPE_INTERFACE, - &NS_GET_IID(nsIMediaDevice), - mDevices->Length(), - const_cast( - static_cast(tmp.Elements()) - )); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - } - mOnSuccess->OnSuccess(devices); - return NS_OK; - } - - nsCString mOriginKey; -private: - nsCOMPtr mOnSuccess; - nsCOMPtr mOnFailure; - nsAutoPtr>> mDevices; - uint64_t mWindowID; - bool mIsGum; - nsRefPtr mManager; -}; - // Handle removing GetUserMediaCallbackMediaStreamListener from main thread class GetUserMediaListenerRemove: public nsRunnable { @@ -440,44 +299,15 @@ protected: NS_IMPL_ISUPPORTS(MediaDevice, nsIMediaDevice) MediaDevice::MediaDevice(MediaEngineSource* aSource) - : mHasFacingMode(false) - , mSource(aSource) { + : mSource(aSource) { mSource->GetName(mName); - mSource->GetUUID(mID); + nsCString id; + mSource->GetUUID(id); + CopyUTF8toUTF16(id, mID); } VideoDevice::VideoDevice(MediaEngineVideoSource* aSource) : MediaDevice(aSource) { -#if defined(MOZ_B2G_CAMERA) && defined(MOZ_WIDGET_GONK) - if (mName.EqualsLiteral("back")) { - mHasFacingMode = true; - mFacingMode = dom::VideoFacingModeEnum::Environment; - } else if (mName.EqualsLiteral("front")) { - mHasFacingMode = true; - mFacingMode = dom::VideoFacingModeEnum::User; - } -#endif // MOZ_B2G_CAMERA -#if defined(ANDROID) && !defined(MOZ_WIDGET_GONK) - // Names are generated. Example: "Camera 0, Facing back, Orientation 90" - // - // See media/webrtc/trunk/webrtc/modules/video_capture/android/java/src/org/ - // webrtc/videoengine/VideoCaptureDeviceInfoAndroid.java - - if (mName.Find(NS_LITERAL_STRING("Facing back")) != kNotFound) { - mHasFacingMode = true; - mFacingMode = dom::VideoFacingModeEnum::Environment; - } else if (mName.Find(NS_LITERAL_STRING("Facing front")) != kNotFound) { - mHasFacingMode = true; - mFacingMode = dom::VideoFacingModeEnum::User; - } -#endif // ANDROID -#ifdef XP_MACOSX - // Kludge to test user-facing cameras on OSX. - if (mName.Find(NS_LITERAL_STRING("Face")) != -1) { - mHasFacingMode = true; - mFacingMode = dom::VideoFacingModeEnum::User; - } -#endif mMediaSource = aSource->GetMediaSource(); } @@ -492,63 +322,16 @@ uint32_t VideoDevice::GetBestFitnessDistance( const nsTArray& aConstraintSets) { - // TODO: Minimal kludge to fix plain and ideal facingMode regression, for - // smooth landing and uplift. Proper cleanup is forthcoming (1037389). - uint64_t distance = 0; - // Interrogate device-inherent properties first. - for (size_t i = 0; i < aConstraintSets.Length(); i++) { - auto& c = *aConstraintSets[i]; - if (!c.mFacingMode.IsConstrainDOMStringParameters() || - c.mFacingMode.GetAsConstrainDOMStringParameters().mIdeal.WasPassed() || - c.mFacingMode.GetAsConstrainDOMStringParameters().mExact.WasPassed()) { - nsString deviceFacingMode; - GetFacingMode(deviceFacingMode); - if (c.mFacingMode.IsString()) { - if (c.mFacingMode.GetAsString() != deviceFacingMode) { - if (i == 0) { - distance = 1000; - } - } - } else if (c.mFacingMode.IsStringSequence()) { - if (!c.mFacingMode.GetAsStringSequence().Contains(deviceFacingMode)) { - if (i == 0) { - distance = 1000; - } - } - } else if (c.mFacingMode.GetAsConstrainDOMStringParameters().mExact.WasPassed()) { - auto& exact = c.mFacingMode.GetAsConstrainDOMStringParameters().mExact.Value(); - if (exact.IsString()) { - if (exact.GetAsString() != deviceFacingMode) { - return UINT32_MAX; - } - } else if (!exact.GetAsStringSequence().Contains(deviceFacingMode)) { - return UINT32_MAX; - } - } else if (c.mFacingMode.GetAsConstrainDOMStringParameters().mIdeal.WasPassed()) { - auto& ideal = c.mFacingMode.GetAsConstrainDOMStringParameters().mIdeal.Value(); - if (ideal.IsString()) { - if (ideal.GetAsString() != deviceFacingMode) { - if (i == 0) { - distance = 1000; - } - } - } else if (!ideal.GetAsStringSequence().Contains(deviceFacingMode)) { - if (i == 0) { - distance = 1000; - } - } - } - } + for (const auto& constraint : aConstraintSets) { nsString s; GetMediaSource(s); - if (s != c.mMediaSource) { + if (s != constraint->mMediaSource) { return UINT32_MAX; } } // Forward request to underlying object to interrogate per-mode capabilities. - distance += uint64_t(GetSource()->GetBestFitnessDistance(aConstraintSets)); - return uint32_t(std::min(distance, uint64_t(UINT32_MAX))); + return GetSource()->GetBestFitnessDistance(aConstraintSets); } AudioDevice::AudioDevice(MediaEngineAudioSource* aSource) @@ -602,18 +385,6 @@ MediaDevice::SetId(const nsAString& aID) mID.Assign(aID); } -NS_IMETHODIMP -MediaDevice::GetFacingMode(nsAString& aFacingMode) -{ - if (mHasFacingMode) { - aFacingMode.Assign(NS_ConvertUTF8toUTF16( - dom::VideoFacingModeEnumValues::strings[uint32_t(mFacingMode)].value)); - } else { - aFacingMode.Truncate(0); - } - return NS_OK; -} - NS_IMETHODIMP MediaDevice::GetMediaSource(nsAString& aMediaSource) { @@ -1439,125 +1210,76 @@ private: }; #endif -class SanitizeDeviceIdsTask : public Task -{ -public: - explicit SanitizeDeviceIdsTask(int64_t aSinceWhen) - : mSinceWhen(aSinceWhen) {} +// TODO: Remove once upgraded to GCC 4.8+ on linux. Bogus error on static func: +// error: 'this' was not captured for this lambda function - void // NS_IMETHOD - Run() - { - MOZ_ASSERT(!NS_IsMainThread()); - nsRefPtr> p = - mozilla::media::SanitizeOriginKeys(mSinceWhen); // we fire and forget - } -private: - int64_t mSinceWhen; -}; +static auto& MediaManager_GetInstance = MediaManager::GetInstance; +static auto& MediaManager_ToJSArray = MediaManager::ToJSArray; +static auto& MediaManager_AnonymizeDevices = MediaManager::AnonymizeDevices; /** - * Similar to GetUserMediaTask, but used for the chrome-only - * GetUserMediaDevices function. Enumerates a list of audio & video devices, - * wraps them up in nsIMediaDevice objects and returns it to the success - * callback. - * - * All code in this class runs on the MediaManager thread. + * EnumerateRawDevices - Enumerate a list of audio & video devices that + * satisfy passed-in constraints. List contains raw id's. */ -class GetUserMediaDevicesTask : public Task + +already_AddRefed +MediaManager::EnumerateRawDevices(uint64_t aWindowId, + const MediaStreamConstraints& aConstraints) { -public: - GetUserMediaDevicesTask( - const MediaStreamConstraints& aConstraints, - already_AddRefed aOnSuccess, - already_AddRefed aOnFailure, - uint64_t aWindowId, nsACString& aAudioLoopbackDev, - nsACString& aVideoLoopbackDev, bool aPrivileged, const nsACString& aOrigin, - bool aInPrivateBrowsing, bool aUseFakeDevices) - : mConstraints(aConstraints) - , mOnSuccess(aOnSuccess) - , mOnFailure(aOnFailure) - , mManager(MediaManager::GetInstance()) - , mWindowId(aWindowId) - , mLoopbackAudioDevice(aAudioLoopbackDev) - , mLoopbackVideoDevice(aVideoLoopbackDev) - , mPrivileged(aPrivileged) - , mOrigin(aOrigin) - , mInPrivateBrowsing(aInPrivateBrowsing) - , mUseFakeDevices(aUseFakeDevices) {} + MOZ_ASSERT(NS_IsMainThread()); + nsRefPtr p = new PledgeSourceSet(); + uint32_t id = mOutstandingPledges.Append(*p); - void // NS_IMETHOD - Run() - { - MOZ_ASSERT(!NS_IsMainThread()); + // Check if the preference for using audio/video loopback devices is + // enabled. This is currently used for automated media tests only. + auto audioLoopDev = Preferences::GetCString("media.audio_loopback_dev"); + auto videoLoopDev = Preferences::GetCString("media.video_loopback_dev"); + bool fake = Preferences::GetBool("media.navigator.streams.fake", false); + MediaManager::PostTask(FROM_HERE, NewTaskFrom([id, aConstraints, aWindowId, + audioLoopDev, videoLoopDev, + fake]() mutable { nsRefPtr backend; - if (mConstraints.mFake || mUseFakeDevices) - backend = new MediaEngineDefault(mConstraints.mFakeTracks); - else - backend = mManager->GetBackend(mWindowId); - - typedef nsTArray> SourceSet; + if (aConstraints.mFake || fake) { + backend = new MediaEngineDefault(aConstraints.mFakeTracks); + } else { + nsRefPtr manager = MediaManager_GetInstance(); + backend = manager->GetBackend(aWindowId); + } ScopedDeletePtr result(new SourceSet); - if (IsOn(mConstraints.mVideo)) { + if (IsOn(aConstraints.mVideo)) { nsTArray> sources; - GetSources(backend, GetInvariant(mConstraints.mVideo), - &MediaEngine::EnumerateVideoDevices, sources, - mLoopbackVideoDevice.get()); + GetSources(backend, GetInvariant(aConstraints.mVideo), + &MediaEngine::EnumerateVideoDevices, sources, videoLoopDev); for (auto& source : sources) { result->AppendElement(source); } } - if (IsOn(mConstraints.mAudio)) { + if (IsOn(aConstraints.mAudio)) { nsTArray> sources; - GetSources(backend, GetInvariant(mConstraints.mAudio), - &MediaEngine::EnumerateAudioDevices, sources, - mLoopbackAudioDevice.get()); + GetSources(backend, GetInvariant(aConstraints.mAudio), + &MediaEngine::EnumerateAudioDevices, sources, audioLoopDev); for (auto& source : sources) { result->AppendElement(source); } } - nsRefPtr runnable = - new DeviceSuccessCallbackRunnable(mWindowId, mOnSuccess, mOnFailure, - result.forget(), mPrivileged); - if (mPrivileged) { - NS_DispatchToMainThread(runnable); - } else { - // Get persistent origin-unique uuid to anonymize deviceIds back on main. - // - // GetOriginKey is an async API that returns a pledge (as promise-like - // pattern). We use .Then() to pass in a lambda to run back on this - // thread once GetOriginKey resolves asynchronously . The "runnable" - // pointer is "captured" (passed by value) into the lambda. - nsRefPtr> p = - media::GetOriginKey(mOrigin, mInPrivateBrowsing); - p->Then([runnable](nsCString result) mutable { - runnable->mOriginKey = result; - NS_DispatchToMainThread(runnable); - }); - } - // One of the Runnables have taken these. - MOZ_ASSERT(!mOnSuccess && !mOnFailure); - } - -private: - MediaStreamConstraints mConstraints; - nsCOMPtr mOnSuccess; - nsCOMPtr mOnFailure; - nsRefPtr mManager; - uint64_t mWindowId; - const nsString mCallId; - // Audio & Video loopback devices to be used based on - // the preference settings. This is currently used for - // automated media tests only. - nsCString mLoopbackAudioDevice; - nsCString mLoopbackVideoDevice; - bool mPrivileged; - nsCString mOrigin; - bool mInPrivateBrowsing; - bool mUseFakeDevices; -}; + SourceSet* handoff = result.forget(); + NS_DispatchToMainThread(NewRunnableFrom([id, handoff]() mutable { + ScopedDeletePtr result(handoff); + nsRefPtr mgr = MediaManager_GetInstance(); + if (!mgr) { + return NS_OK; + } + nsRefPtr p = mgr->mOutstandingPledges.Remove(id); + if (p) { + p->Resolve(result.forget()); + } + return NS_OK; + })); + })); + return p.forget(); +} MediaManager::MediaManager() : mMediaThread(nullptr) @@ -1567,7 +1289,6 @@ MediaManager::MediaManager() mPrefs.mHeight = 0; // adaptive default mPrefs.mFPS = MediaEngine::DEFAULT_VIDEO_FPS; mPrefs.mMinFPS = MediaEngine::DEFAULT_VIDEO_MIN_FPS; - nsresult rv; nsCOMPtr prefs = do_GetService("@mozilla.org/preferences-service;1", &rv); if (NS_SUCCEEDED(rv)) { @@ -1654,6 +1375,15 @@ MediaManager::GetInstance() return service.forget(); } +media::Parent* +MediaManager::GetNonE10sParent() +{ + if (!mNonE10sParent) { + mNonE10sParent = new media::Parent(true); + } + return mNonE10sParent; +} + /* static */ void MediaManager::PostTask(const tracked_objects::Location& from_here, Task* task) @@ -1736,22 +1466,20 @@ MediaManager::NotifyRecordingStatusChange(nsPIDOMWindow* aWindow, * for handling all incoming getUserMedia calls from every window. */ nsresult -MediaManager::GetUserMedia( - nsPIDOMWindow* aWindow, const MediaStreamConstraints& aConstraints, - nsIDOMGetUserMediaSuccessCallback* aOnSuccess, - nsIDOMGetUserMediaErrorCallback* aOnFailure) +MediaManager::GetUserMedia(nsPIDOMWindow* aWindow, + const MediaStreamConstraints& aConstraints, + nsIDOMGetUserMediaSuccessCallback* aOnSuccess, + nsIDOMGetUserMediaErrorCallback* aOnFailure) { - NS_ASSERTION(NS_IsMainThread(), "Only call on main thread"); - - NS_ENSURE_TRUE(aWindow, NS_ERROR_NULL_POINTER); - NS_ENSURE_TRUE(aOnFailure, NS_ERROR_NULL_POINTER); - NS_ENSURE_TRUE(aOnSuccess, NS_ERROR_NULL_POINTER); - - bool privileged = nsContentUtils::IsCallerChrome(); - + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aWindow); + MOZ_ASSERT(aOnFailure); + MOZ_ASSERT(aOnSuccess); nsCOMPtr onSuccess(aOnSuccess); nsCOMPtr onFailure(aOnFailure); + bool privileged = nsContentUtils::IsCallerChrome(); + MediaStreamConstraints c(aConstraints); // copy static bool created = false; @@ -1981,47 +1709,144 @@ MediaManager::GetUserMedia( return NS_OK; } -nsresult -MediaManager::GetUserMediaDevices(nsPIDOMWindow* aWindow, - const MediaStreamConstraints& aConstraints, - nsIGetUserMediaDevicesSuccessCallback* aOnSuccess, - nsIDOMGetUserMediaErrorCallback* aOnFailure, - uint64_t aInnerWindowID, - bool aPrivileged) +/* static */ void +MediaManager::AnonymizeDevices(SourceSet& aDevices, const nsACString& aOriginKey) { - NS_ASSERTION(NS_IsMainThread(), "Only call on main thread"); + if (!aOriginKey.IsEmpty()) { + for (auto& device : aDevices) { + nsString id; + device->GetId(id); + AnonymizeId(id, aOriginKey); + device->SetId(id); + } + } +} - NS_ENSURE_TRUE(aOnFailure, NS_ERROR_NULL_POINTER); - NS_ENSURE_TRUE(aOnSuccess, NS_ERROR_NULL_POINTER); - NS_ENSURE_TRUE(!sInShutdown, NS_ERROR_FAILURE); +/* static */ nsresult +MediaManager::AnonymizeId(nsAString& aId, const nsACString& aOriginKey) +{ + MOZ_ASSERT(NS_IsMainThread()); - nsCOMPtr onSuccess(aOnSuccess); - nsCOMPtr onFailure(aOnFailure); + nsresult rv; + nsCOMPtr 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 key; + rv = factory->KeyFromString(nsIKeyObject::HMAC, rawKey, getter_AddRefs(key)); + if (NS_FAILED(rv)) { + return rv; + } - // Check if the preference for using loopback devices is enabled. - nsAdoptingCString loopbackAudioDevice = - Preferences::GetCString("media.audio_loopback_dev"); - nsAdoptingCString loopbackVideoDevice = - Preferences::GetCString("media.video_loopback_dev"); - bool useFakeStreams = - Preferences::GetBool("media.navigator.streams.fake", false); + nsCOMPtr 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 (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 +MediaManager::ToJSArray(SourceSet& aDevices) +{ + nsCOMPtr var = do_CreateInstance("@mozilla.org/variant;1"); + size_t len = aDevices.Length(); + if (len) { + nsTArray tmp(len); + for (auto& device : aDevices) { + tmp.AppendElement(device); + } + auto* elements = static_cast(tmp.Elements()); + nsresult rv = var->SetAsArray(nsIDataType::VTYPE_INTERFACE, + &NS_GET_IID(nsIMediaDevice), len, + const_cast(elements)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return nullptr; + } + } else { + var->SetAsEmptyArray(); // because SetAsArray() fails on zero length arrays. + } + return var.forget(); +} + +already_AddRefed +MediaManager::EnumerateDevicesImpl(uint64_t aWindowId, + const MediaStreamConstraints& aConstraints) +{ + MOZ_ASSERT(NS_IsMainThread()); + + // This function returns a pledge, a promise-like object with the future result + nsRefPtr pledge = new PledgeSourceSet(); + uint32_t id = mOutstandingPledges.Append(*pledge); + + // 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. nsCString origin; - nsPrincipal::GetOriginForURI(aWindow->GetDocumentURI(), origin); - bool inPrivateBrowsing; + bool privateBrowsing; { - nsCOMPtr doc = aWindow->GetDoc(); - nsCOMPtr loadContext = doc->GetLoadContext(); - inPrivateBrowsing = loadContext && loadContext->UsePrivateBrowsing(); - } - MediaManager::PostTask(FROM_HERE, - new GetUserMediaDevicesTask( - aConstraints, onSuccess.forget(), onFailure.forget(), - (aInnerWindowID ? aInnerWindowID : aWindow->WindowID()), - loopbackAudioDevice, loopbackVideoDevice, aPrivileged, origin, - inPrivateBrowsing, useFakeStreams)); + nsPIDOMWindow *window = static_cast + (nsGlobalWindow::GetInnerWindowWithId(aWindowId)); + nsPrincipal::GetOriginForURI(window->GetDocumentURI(), origin); - return NS_OK; + nsCOMPtr doc = window->GetDoc(); + nsCOMPtr loadContext = doc->GetLoadContext(); + privateBrowsing = loadContext && loadContext->UsePrivateBrowsing(); + } + // GetOriginKey is an async API that returns a pledge (a promise-like + // pattern). We use .Then() to pass in a lambda to run back on this same + // thread later once GetOriginKey resolves. Needed variables are "captured" + // (passed by value) safely into the lambda. + + nsRefPtr> p = media::GetOriginKey(origin, privateBrowsing); + p->Then([id, aWindowId, aConstraints](const nsCString& aOriginKey) mutable { + MOZ_ASSERT(NS_IsMainThread()); + nsRefPtr mgr = MediaManager_GetInstance(); + + nsRefPtr p = mgr->EnumerateRawDevices(aWindowId, aConstraints); + p->Then([id, aWindowId, aOriginKey](SourceSet*& aDevices) mutable { + ScopedDeletePtr devices(aDevices); // secondary result + + // Only run if window is still on our active list. + nsRefPtr mgr = MediaManager_GetInstance(); + if (!mgr) { + return NS_OK; + } + nsRefPtr p = mgr->mOutstandingPledges.Remove(id); + if (!p || !mgr->IsWindowStillActive(aWindowId)) { + return NS_OK; + } + MediaManager_AnonymizeDevices(*devices, aOriginKey); + p->Resolve(devices.forget()); + return NS_OK; + }); + }); + return pledge.forget(); } nsresult @@ -2029,14 +1854,68 @@ MediaManager::EnumerateDevices(nsPIDOMWindow* aWindow, nsIGetUserMediaDevicesSuccessCallback* aOnSuccess, nsIDOMGetUserMediaErrorCallback* aOnFailure) { - NS_ASSERTION(NS_IsMainThread(), "Only call on main thread"); + MOZ_ASSERT(NS_IsMainThread()); + NS_ENSURE_TRUE(!sInShutdown, NS_ERROR_FAILURE); + nsCOMPtr onSuccess(aOnSuccess); + nsCOMPtr onFailure(aOnFailure); + uint64_t windowId = aWindow->WindowID(); + + AddWindowID(windowId); MediaStreamConstraints c; c.mVideo.SetAsBoolean() = true; c.mAudio.SetAsBoolean() = true; - AddWindowID(aWindow->WindowID()); - return GetUserMediaDevices(aWindow, c, aOnSuccess, aOnFailure, 0, false); + nsRefPtr p = EnumerateDevicesImpl(windowId, c); + p->Then([onSuccess](SourceSet*& aDevices) mutable { + ScopedDeletePtr devices(aDevices); // grab result + nsCOMPtr array = MediaManager_ToJSArray(*devices); + onSuccess->OnSuccess(array); + }, [onFailure](MediaStreamError& reason) mutable { + onFailure->OnError(&reason); + }); + return NS_OK; +} + +/* + * GetUserMediaDevices - called by the UI-part of getUserMedia from chrome JS. + */ + +nsresult +MediaManager::GetUserMediaDevices(nsPIDOMWindow* aWindow, + const MediaStreamConstraints& aConstraints, + nsIGetUserMediaDevicesSuccessCallback* aOnSuccess, + nsIDOMGetUserMediaErrorCallback* aOnFailure, + uint64_t aWindowId) +{ + MOZ_ASSERT(NS_IsMainThread()); + nsCOMPtr onSuccess(aOnSuccess); + nsCOMPtr onFailure(aOnFailure); + if (!aWindowId) { + aWindowId = aWindow->WindowID(); + } + + nsRefPtr p = EnumerateDevicesImpl(aWindowId, aConstraints); + p->Then([aWindowId, onSuccess, onFailure](SourceSet*& aDevices) mutable { + ScopedDeletePtr devices(aDevices); // grab result + + if (devices->Length()) { + nsCOMPtr array = MediaManager_ToJSArray(*devices); + onSuccess->OnSuccess(array); + } else { + nsRefPtr window = nsGlobalWindow::GetInnerWindowWithId(aWindowId); + if (!window) { + return NS_ERROR_UNEXPECTED; + } + nsRefPtr reason = + new MediaStreamError(window, NS_LITERAL_STRING("NotFoundError")); + onFailure->OnError(reason); + } + return NS_OK; + }, [onFailure](MediaStreamError& reason) mutable { + onFailure->OnError(&reason); + }); + return NS_OK; } MediaEngine* @@ -2550,7 +2429,7 @@ MediaManager::SanitizeDeviceIds(int64_t aSinceWhen) NS_ASSERTION(NS_IsMainThread(), "Only call on main thread"); LOG(("%s: sinceWhen = %llu", __FUNCTION__, aSinceWhen)); - MediaManager::PostTask(FROM_HERE, new SanitizeDeviceIdsTask(aSinceWhen)); + media::SanitizeOriginKeys(aSinceWhen); // we fire and forget return NS_OK; } diff --git a/dom/media/MediaManager.h b/dom/media/MediaManager.h index 77cb026fab94..360d90482691 100644 --- a/dom/media/MediaManager.h +++ b/dom/media/MediaManager.h @@ -27,6 +27,8 @@ #include "mozilla/dom/MediaStreamBinding.h" #include "mozilla/dom/MediaStreamTrackBinding.h" #include "mozilla/dom/MediaStreamError.h" +#include "mozilla/media/MediaChild.h" +#include "mozilla/media/MediaParent.h" #include "mozilla/Logging.h" #include "DOMMediaStream.h" @@ -468,8 +470,6 @@ protected: explicit MediaDevice(MediaEngineSource* aSource); nsString mName; nsString mID; - bool mHasFacingMode; - dom::VideoFacingModeEnum mFacingMode; dom::MediaSourceEnum mMediaSource; nsRefPtr mSource; }; @@ -534,6 +534,7 @@ public: NS_DECL_NSIOBSERVER NS_DECL_NSIMEDIAMANAGERSERVICE + media::Parent* GetNonE10sParent(); MediaEngine* GetBackend(uint64_t aWindowId = 0); StreamListeners *GetWindowListeners(uint64_t aWindowId) { NS_ASSERTION(NS_IsMainThread(), "Only access windowlist on main thread"); @@ -555,11 +556,10 @@ public: nsIDOMGetUserMediaErrorCallback* onError); nsresult GetUserMediaDevices(nsPIDOMWindow* aWindow, - const dom::MediaStreamConstraints& aConstraints, - nsIGetUserMediaDevicesSuccessCallback* onSuccess, - nsIDOMGetUserMediaErrorCallback* onError, - uint64_t aInnerWindowID = 0, - bool aPrivileged = true); + const dom::MediaStreamConstraints& aConstraints, + nsIGetUserMediaDevicesSuccessCallback* onSuccess, + nsIDOMGetUserMediaErrorCallback* onError, + uint64_t aInnerWindowID = 0); nsresult EnumerateDevices(nsPIDOMWindow* aWindow, nsIGetUserMediaDevicesSuccessCallback* aOnSuccess, @@ -572,6 +572,21 @@ public: MediaEnginePrefs mPrefs; private: + typedef nsTArray> SourceSet; + typedef media::Pledge PledgeSourceSet; + + static nsresult AnonymizeId(nsAString& aId, const nsACString& aOriginKey); +public: // TODO: make private once we upgrade to GCC 4.8+ on linux. + static void AnonymizeDevices(SourceSet& aDevices, const nsACString& aOriginKey); + static already_AddRefed ToJSArray(SourceSet& aDevices); +private: + already_AddRefed + EnumerateRawDevices(uint64_t aWindowId, + const dom::MediaStreamConstraints& aConstraints); + already_AddRefed + EnumerateDevicesImpl(uint64_t aWindowId, + const dom::MediaStreamConstraints& aConstraints); + StreamListeners* AddWindowID(uint64_t aWindowId); WindowTable *GetActiveWindows() { NS_ASSERTION(NS_IsMainThread(), "Only access windowlist on main thread"); @@ -610,9 +625,13 @@ private: static StaticRefPtr sSingleton; + media::CoatCheck mOutstandingPledges; #if defined(MOZ_B2G_CAMERA) && defined(MOZ_WIDGET_GONK) nsRefPtr mCameraManager; #endif +public: + media::CoatCheck> mGetOriginKeyPledges; + ScopedDeletePtr> mNonE10sParent; }; } // namespace mozilla diff --git a/dom/media/PeerConnection.js b/dom/media/PeerConnection.js index 8d7ee5321e1b..a5588ed8132f 100644 --- a/dom/media/PeerConnection.js +++ b/dom/media/PeerConnection.js @@ -1004,6 +1004,7 @@ RTCPeerConnection.prototype = { // the name change this.logWarning("Deprecated RTCDataChannelInit dictionary entry outOfOrderAllowed used!", null, 0); } + if (dict.preset != undefined) { dict.negotiated = dict.preset; this.logWarning("Deprecated RTCDataChannelInit dictionary entry preset used!", null, 0); diff --git a/dom/media/nsIDOMNavigatorUserMedia.idl b/dom/media/nsIDOMNavigatorUserMedia.idl index c33ea9e103b2..6a51294d87f5 100644 --- a/dom/media/nsIDOMNavigatorUserMedia.idl +++ b/dom/media/nsIDOMNavigatorUserMedia.idl @@ -5,13 +5,12 @@ #include "nsISupports.idl" #include "nsIVariant.idl" -[scriptable, builtinclass, uuid(bbfebbc6-76eb-407c-b77d-363a69bc5c30)] +[scriptable, builtinclass, uuid(cebcefca-2de1-460d-b253-d0582c50b40f)] interface nsIMediaDevice : nsISupports { readonly attribute DOMString type; readonly attribute DOMString name; readonly attribute DOMString id; - readonly attribute DOMString facingMode; readonly attribute DOMString mediaSource; }; diff --git a/dom/media/systemservices/MediaChild.cpp b/dom/media/systemservices/MediaChild.cpp index 49aecfba9c37..a1bde0e59cfb 100644 --- a/dom/media/systemservices/MediaChild.cpp +++ b/dom/media/systemservices/MediaChild.cpp @@ -5,9 +5,8 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "MediaChild.h" +#include "MediaParent.h" -#include "mozilla/ipc/BackgroundChild.h" -#include "mozilla/ipc/PBackgroundChild.h" #include "nsGlobalWindow.h" #include "mozilla/MediaManager.h" #include "mozilla/Logging.h" @@ -20,84 +19,52 @@ PRLogModuleInfo *gMediaChildLog; namespace mozilla { namespace media { -static Child* sChild; - -template void -ChildPledge::ActorCreated(PBackgroundChild* aActor) -{ - if (!sChild) { - // Create PMedia by sending a message to the parent - sChild = static_cast(aActor->SendPMediaConstructor()); - } - Run(sChild); -} - -template void -ChildPledge::ActorFailed() -{ - Pledge::Reject(NS_ERROR_UNEXPECTED); -} - -template NS_IMPL_ADDREF(ChildPledge) -template NS_IMPL_RELEASE(ChildPledge) -template NS_INTERFACE_MAP_BEGIN(ChildPledge) -NS_INTERFACE_MAP_ENTRY(nsIIPCBackgroundChildCreateCallback) -NS_INTERFACE_MAP_END - -already_AddRefed> +already_AddRefed> GetOriginKey(const nsCString& aOrigin, bool aPrivateBrowsing) { - class Pledge : public ChildPledge - { - public: - explicit Pledge(const nsCString& aOrigin, bool aPrivateBrowsing) - : mOrigin(aOrigin), mPrivateBrowsing(aPrivateBrowsing) {} - private: - ~Pledge() {} - void Run(PMediaChild* aChild) - { - Child* child = static_cast(aChild); + nsRefPtr mgr = MediaManager::GetInstance(); + MOZ_ASSERT(mgr); - uint32_t id = child->AddRequestPledge(*this); - child->SendGetOriginKey(id, mOrigin, mPrivateBrowsing); - } - const nsCString mOrigin; - const bool mPrivateBrowsing; - }; + nsRefPtr> p = new Pledge(); + uint32_t id = mgr->mGetOriginKeyPledges.Append(*p); - nsRefPtr> p = new Pledge(aOrigin, aPrivateBrowsing); - nsCOMPtr cb = do_QueryObject(p); - bool ok = ipc::BackgroundChild::GetOrCreateForCurrentThread(cb); - MOZ_RELEASE_ASSERT(ok); + if (XRE_GetProcessType() == GeckoProcessType_Default) { + mgr->GetNonE10sParent()->RecvGetOriginKey(id, aOrigin, aPrivateBrowsing); + } else { + Child::Get()->SendGetOriginKey(id, aOrigin, aPrivateBrowsing); + } return p.forget(); } -already_AddRefed> +void SanitizeOriginKeys(const uint64_t& aSinceWhen) { - class Pledge : public ChildPledge - { - public: - explicit Pledge(const uint64_t& aSinceWhen) : mSinceWhen(aSinceWhen) {} - private: - void Run(PMediaChild* aMedia) - { - aMedia->SendSanitizeOriginKeys(mSinceWhen); - mValue = true; - LOG(("SanitizeOriginKeys since %llu", mSinceWhen)); - Resolve(); - } - const uint64_t mSinceWhen; - }; + LOG(("SanitizeOriginKeys since %llu", aSinceWhen)); - nsRefPtr> p = new Pledge(aSinceWhen); - nsCOMPtr cb = do_QueryObject(p); - bool ok = ipc::BackgroundChild::GetOrCreateForCurrentThread(cb); - MOZ_RELEASE_ASSERT(ok); - return p.forget(); + if (XRE_GetProcessType() == GeckoProcessType_Default) { + // Avoid opening MediaManager in this case, since this is called by + // sanitize.js when cookies are cleared, which can happen on startup. + ScopedDeletePtr> tmpParent(new Parent(true)); + tmpParent->RecvSanitizeOriginKeys(aSinceWhen); + } else { + Child::Get()->SendSanitizeOriginKeys(aSinceWhen); + } +} + +static Child* sChild; + +Child* Child::Get() +{ + MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Content); + MOZ_ASSERT(NS_IsMainThread()); + if (!sChild) { + sChild = static_cast(dom::ContentChild::GetSingleton()->SendPMediaConstructor()); + } + return sChild; } Child::Child() + : mActorDestroyed(false) { if (!gMediaChildLog) { gMediaChildLog = PR_NewLogModule("MediaChild"); @@ -113,22 +80,19 @@ Child::~Child() MOZ_COUNT_DTOR(Child); } -uint32_t -Child::AddRequestPledge(ChildPledge& aPledge) +void Child::ActorDestroy(ActorDestroyReason aWhy) { - return mRequestPledges.Append(aPledge); -} - -already_AddRefed> -Child::RemoveRequestPledge(uint32_t aRequestId) -{ - return mRequestPledges.Remove(aRequestId); + mActorDestroyed = true; } bool Child::RecvGetOriginKeyResponse(const uint32_t& aRequestId, const nsCString& aKey) { - nsRefPtr> pledge = RemoveRequestPledge(aRequestId); + nsRefPtr mgr = MediaManager::GetInstance(); + if (!mgr) { + return false; + } + nsRefPtr> pledge = mgr->mGetOriginKeyPledges.Remove(aRequestId); if (pledge) { pledge->Resolve(aKey); } @@ -138,15 +102,13 @@ Child::RecvGetOriginKeyResponse(const uint32_t& aRequestId, const nsCString& aKe PMediaChild* AllocPMediaChild() { - Child* obj = new Child(); - obj->AddRef(); - return obj; + return new Child(); } bool DeallocPMediaChild(media::PMediaChild *aActor) { - static_cast(aActor)->Release(); + delete static_cast(aActor); return true; } diff --git a/dom/media/systemservices/MediaChild.h b/dom/media/systemservices/MediaChild.h index 9ec5d9b66999..19449247c818 100644 --- a/dom/media/systemservices/MediaChild.h +++ b/dom/media/systemservices/MediaChild.h @@ -10,7 +10,6 @@ #include "mozilla/dom/ContentChild.h" #include "mozilla/media/PMediaChild.h" #include "mozilla/media/PMediaParent.h" -#include "nsIIPCBackgroundChildCreateCallback.h" #include "MediaUtils.h" namespace mozilla { @@ -25,42 +24,26 @@ namespace media { // GetOriginKey and SanitizeOriginKeys are asynchronous APIs that return pledges // (promise-like objects) with the future value. Use pledge.Then(func) to access. -class Child; - -template -class ChildPledge : public Pledge, - public nsIIPCBackgroundChildCreateCallback -{ - friend Child; - NS_DECL_NSIIPCBACKGROUNDCHILDCREATECALLBACK - NS_DECL_ISUPPORTS -public: - explicit ChildPledge() {}; -protected: - virtual ~ChildPledge() {} - virtual void Run(PMediaChild* aMedia) = 0; -}; - -already_AddRefed> +already_AddRefed> GetOriginKey(const nsCString& aOrigin, bool aPrivateBrowsing); -already_AddRefed> +void SanitizeOriginKeys(const uint64_t& aSinceWhen); class Child : public PMediaChild { - NS_INLINE_DECL_REFCOUNTING(Child) public: + static Child* Get(); + Child(); bool RecvGetOriginKeyResponse(const uint32_t& aRequestId, const nsCString& aKey); - uint32_t AddRequestPledge(ChildPledge& aPledge); - already_AddRefed> RemoveRequestPledge(uint32_t aRequestId); -private: + void ActorDestroy(ActorDestroyReason aWhy) override; virtual ~Child(); +private: - CoatCheck> mRequestPledges; + bool mActorDestroyed; }; PMediaChild* AllocPMediaChild(); diff --git a/dom/media/systemservices/MediaParent.cpp b/dom/media/systemservices/MediaParent.cpp index 9ce989f996c5..d5ae2d1f0a5e 100644 --- a/dom/media/systemservices/MediaParent.cpp +++ b/dom/media/systemservices/MediaParent.cpp @@ -32,13 +32,13 @@ PRLogModuleInfo *gMediaParentLog; namespace mozilla { namespace media { -static StaticMutex gMutex; -static ParentSingleton* sParentSingleton = nullptr; +static Parent* sIPCServingParent; -class ParentSingleton : public nsISupports +static OriginKeyStore* sOriginKeyStore = nullptr; + +class OriginKeyStore : public nsISupports { NS_DECL_THREADSAFE_ISUPPORTS - class OriginKey { public: @@ -324,166 +324,181 @@ class ParentSingleton : public nsISupports }; private: - virtual ~ParentSingleton() + virtual ~OriginKeyStore() { - sParentSingleton = nullptr; + sOriginKeyStore = nullptr; LOG((__FUNCTION__)); } public: - static ParentSingleton* Get() + static OriginKeyStore* Get() { - // Protect creation of singleton and access from multiple Background threads. - // - // Multiple Background threads happen because sanitize.js calls us from the - // chrome process and gets a thread separate from the one servicing ipc from - // the content process. - - StaticMutexAutoLock lock(gMutex); - if (!sParentSingleton) { - sParentSingleton = new ParentSingleton(); + MOZ_ASSERT(NS_IsMainThread()); + if (!sOriginKeyStore) { + sOriginKeyStore = new OriginKeyStore(); } - return sParentSingleton; + return sOriginKeyStore; } // Only accessed on StreamTS thread OriginKeysLoader mOriginKeys; OriginKeysTable mPrivateBrowsingOriginKeys; - - // Only accessed on return thread - CoatCheck> mOutstandingPledges; }; -NS_IMPL_ISUPPORTS0(ParentSingleton) +NS_IMPL_ISUPPORTS0(OriginKeyStore) -bool -Parent::RecvGetOriginKey(const uint32_t& aRequestId, +template<> /* static */ +Parent* Parent::GetSingleton() +{ + return sIPCServingParent; +} + +template<> /* static */ +Parent* Parent::GetSingleton() +{ + nsRefPtr mgr = MediaManager::GetInstance(); + if (!mgr) { + return nullptr; + } + return mgr->GetNonE10sParent(); +} + +// TODO: Remove once upgraded to GCC 4.8+ on linux. Bogus error on static func: +// error: 'this' was not captured for this lambda function + +template static +Parent* GccGetSingleton() { return Parent::GetSingleton(); }; + + +template bool +Parent::RecvGetOriginKey(const uint32_t& aRequestId, const nsCString& aOrigin, const bool& aPrivateBrowsing) { - // TODO: Replace all this when moving MediaParent to PContent soon (1037389) + MOZ_ASSERT(NS_IsMainThread()); - nsRefPtr singleton(mSingleton); - nsCOMPtr returnThread = NS_GetCurrentThread(); - nsRefPtr> p = new Pledge(); - nsresult rv; + // First, get profile dir. - // First, over to main thread to get profile dir. - - // Pledges are non-threadsafe by design, so check them and pass an id instead. - uint32_t id = singleton->mOutstandingPledges.Append(*p); - - rv = NS_DispatchToMainThread(NewRunnableFrom([id, returnThread, - singleton, aOrigin, - aPrivateBrowsing]() -> nsresult { - MOZ_ASSERT(NS_IsMainThread()); - nsCOMPtr profileDir; - nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, - getter_AddRefs(profileDir)); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - // Then from there over to stream-transport thread to do the actual file io. - - nsCOMPtr sts = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); - MOZ_ASSERT(sts); - rv = sts->Dispatch(NewRunnableFrom([profileDir, id, returnThread, singleton, - aOrigin, aPrivateBrowsing]() -> nsresult { - MOZ_ASSERT(!NS_IsMainThread()); - singleton->mOriginKeys.SetProfileDir(profileDir); - nsCString result; - if (aPrivateBrowsing) { - singleton->mPrivateBrowsingOriginKeys.GetOriginKey(aOrigin, result); - } else { - singleton->mOriginKeys.GetOriginKey(aOrigin, result); - } - - // Pass result back to original thread. - nsresult rv; - rv = returnThread->Dispatch(NewRunnableFrom([id, singleton, - result]() -> nsresult { - nsRefPtr> p = singleton->mOutstandingPledges.Remove(id); - if (!p) { - return NS_ERROR_UNEXPECTED; - } - p->Resolve(result); - return NS_OK; - }), NS_DISPATCH_NORMAL); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - return NS_OK; - }), NS_DISPATCH_NORMAL); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - return NS_OK; - })); + MOZ_ASSERT(NS_IsMainThread()); + nsCOMPtr profileDir; + nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, + getter_AddRefs(profileDir)); if (NS_WARN_IF(NS_FAILED(rv))) { return false; } - nsRefPtr keepAlive(this); - p->Then([this, keepAlive, aRequestId](const nsCString& aKey) mutable { - if (!mDestroyed) { - unused << SendGetOriginKeyResponse(aRequestId, aKey); + // Then over to stream-transport thread to do the actual file io. + // Stash a pledge to hold the answer and get an id for this request. + + nsRefPtr> p = new Pledge(); + uint32_t id = mOutstandingPledges.Append(*p); + + nsCOMPtr sts = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); + MOZ_ASSERT(sts); + nsRefPtr store(mOriginKeyStore); + bool sameProcess = mSameProcess; + + rv = sts->Dispatch(NewRunnableFrom([id, profileDir, store, sameProcess, + aOrigin, aPrivateBrowsing]() -> nsresult { + MOZ_ASSERT(!NS_IsMainThread()); + store->mOriginKeys.SetProfileDir(profileDir); + nsCString result; + if (aPrivateBrowsing) { + store->mPrivateBrowsingOriginKeys.GetOriginKey(aOrigin, result); + } else { + store->mOriginKeys.GetOriginKey(aOrigin, result); + } + + // Pass result back to main thread. + nsresult rv; + rv = NS_DispatchToMainThread(NewRunnableFrom([id, store, sameProcess, + result]() -> nsresult { + Parent* parent = GccGetSingleton(); // GetSingleton(); + if (!parent) { + return NS_OK; + } + nsRefPtr> p = parent->mOutstandingPledges.Remove(id); + if (!p) { + return NS_ERROR_UNEXPECTED; + } + p->Resolve(result); + return NS_OK; + }), NS_DISPATCH_NORMAL); + + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + return NS_OK; + }), NS_DISPATCH_NORMAL); + + if (NS_WARN_IF(NS_FAILED(rv))) { + return false; + } + + p->Then([aRequestId, sameProcess](const nsCString& aKey) mutable { + if (!sameProcess) { + if (!sIPCServingParent) { + return NS_OK; + } + unused << sIPCServingParent->SendGetOriginKeyResponse(aRequestId, aKey); + } else { + nsRefPtr mgr = MediaManager::GetInstance(); + if (!mgr) { + return NS_OK; + } + nsRefPtr> pledge = + mgr->mGetOriginKeyPledges.Remove(aRequestId); + if (pledge) { + pledge->Resolve(aKey); + } } return NS_OK; }); return true; } -bool -Parent::RecvSanitizeOriginKeys(const uint64_t& aSinceWhen) +template bool +Parent::RecvSanitizeOriginKeys(const uint64_t& aSinceWhen) { - nsRefPtr singleton(mSingleton); - - // First, over to main to get profile dir. - nsresult rv; - - rv = NS_DispatchToMainThread(NewRunnableFrom([singleton, - aSinceWhen]() -> nsresult { - MOZ_ASSERT(NS_IsMainThread()); - nsCOMPtr profileDir; - nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, + MOZ_ASSERT(NS_IsMainThread()); + nsCOMPtr profileDir; + nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(profileDir)); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - // Then from there over to stream-transport thread to do the file io. + if (NS_WARN_IF(NS_FAILED(rv))) { + return false; + } + // Over to stream-transport thread to do the file io. - nsCOMPtr sts = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); - MOZ_ASSERT(sts); - rv = sts->Dispatch(NewRunnableFrom([profileDir, singleton, aSinceWhen]() -> nsresult { - MOZ_ASSERT(!NS_IsMainThread()); - singleton->mOriginKeys.SetProfileDir(profileDir); - singleton->mPrivateBrowsingOriginKeys.Clear(aSinceWhen); - singleton->mOriginKeys.Clear(aSinceWhen); - return NS_OK; - }), NS_DISPATCH_NORMAL); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } + nsCOMPtr sts = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); + MOZ_ASSERT(sts); + nsRefPtr store(mOriginKeyStore); + + rv = sts->Dispatch(NewRunnableFrom([profileDir, store, aSinceWhen]() -> nsresult { + MOZ_ASSERT(!NS_IsMainThread()); + store->mOriginKeys.SetProfileDir(profileDir); + store->mPrivateBrowsingOriginKeys.Clear(aSinceWhen); + store->mOriginKeys.Clear(aSinceWhen); return NS_OK; - })); + }), NS_DISPATCH_NORMAL); if (NS_WARN_IF(NS_FAILED(rv))) { return false; } return true; } -void -Parent::ActorDestroy(ActorDestroyReason aWhy) +template void +Parent::ActorDestroy(ActorDestroyReason aWhy) { // No more IPC from here mDestroyed = true; LOG((__FUNCTION__)); } -Parent::Parent() - : mSingleton(ParentSingleton::Get()) +template +Parent::Parent(bool aSameProcess) + : mOriginKeyStore(OriginKeyStore::Get()) , mDestroyed(false) + , mSameProcess(aSameProcess) { if (!gMediaParentLog) gMediaParentLog = PR_NewLogModule("MediaParent"); @@ -492,7 +507,8 @@ Parent::Parent() MOZ_COUNT_CTOR(Parent); } -Parent::~Parent() +template +Parent::~Parent() { LOG(("~media::Parent: %p", this)); @@ -502,17 +518,21 @@ Parent::~Parent() PMediaParent* AllocPMediaParent() { - Parent* obj = new Parent(); - obj->AddRef(); - return obj; + MOZ_ASSERT(!sIPCServingParent); + sIPCServingParent = new Parent(); + return sIPCServingParent; } bool DeallocPMediaParent(media::PMediaParent *aActor) { - static_cast(aActor)->Release(); + MOZ_ASSERT(sIPCServingParent == static_cast*>(aActor)); + delete sIPCServingParent; return true; } } } + +// Instantiate templates to satisfy linker +template class mozilla::media::Parent; diff --git a/dom/media/systemservices/MediaParent.h b/dom/media/systemservices/MediaParent.h index b94c872f5a81..364fd2b99956 100644 --- a/dom/media/systemservices/MediaParent.h +++ b/dom/media/systemservices/MediaParent.h @@ -16,25 +16,48 @@ namespace mozilla { namespace media { // media::Parent implements the chrome-process side of ipc for media::Child APIs +// A "SameProcess" version may also be created to service non-e10s calls. -class ParentSingleton; +class OriginKeyStore; -class Parent : public PMediaParent +class NonE10s { - NS_INLINE_DECL_REFCOUNTING(Parent) + typedef mozilla::ipc::IProtocolManager::ActorDestroyReason + ActorDestroyReason; +protected: + virtual bool RecvGetOriginKey(const uint32_t& aRequestId, + const nsCString& aOrigin, + const bool& aPrivateBrowsing) = 0; + virtual bool RecvSanitizeOriginKeys(const uint64_t& aSinceWhen) = 0; + virtual void + ActorDestroy(ActorDestroyReason aWhy) = 0; +}; + +// Super = PMediaParent or NonE10s + +template +class Parent : public Super +{ + typedef mozilla::ipc::IProtocolManager::ActorDestroyReason + ActorDestroyReason; public: + static Parent* GetSingleton(); + virtual bool RecvGetOriginKey(const uint32_t& aRequestId, const nsCString& aOrigin, const bool& aPrivateBrowsing) override; virtual bool RecvSanitizeOriginKeys(const uint64_t& aSinceWhen) override; virtual void ActorDestroy(ActorDestroyReason aWhy) override; - Parent(); -private: + explicit Parent(bool aSameProcess = false); virtual ~Parent(); +private: - nsRefPtr mSingleton; + nsRefPtr mOriginKeyStore; bool mDestroyed; + bool mSameProcess; + + CoatCheck> mOutstandingPledges; }; PMediaParent* AllocPMediaParent(); diff --git a/dom/media/systemservices/MediaUtils.h b/dom/media/systemservices/MediaUtils.h index 929ef44ee93b..488644a08821 100644 --- a/dom/media/systemservices/MediaUtils.h +++ b/dom/media/systemservices/MediaUtils.h @@ -40,8 +40,16 @@ namespace media { * See media::CoatCheck below for an example of GetFooAsynchronously(). */ -template -class Pledge +class PledgeBase +{ +public: + NS_INLINE_DECL_REFCOUNTING(PledgeBase); +protected: + virtual ~PledgeBase() {}; +}; + +template +class Pledge : public PledgeBase { // TODO: Remove workaround once mozilla allows std::function from // wo/std::function support, do template + virtual trick to accept lambdas @@ -49,49 +57,50 @@ class Pledge { public: FunctorsBase() {} - virtual void Succeed(const ValueType& result) = 0; - virtual void Fail(nsresult rv) = 0; + virtual void Succeed(ValueType& result) = 0; + virtual void Fail(ErrorType& error) = 0; virtual ~FunctorsBase() {}; }; public: - NS_INLINE_DECL_REFCOUNTING(Pledge); - explicit Pledge() : mDone(false), mResult(NS_OK) {} + explicit Pledge() : mDone(false), mError(nullptr) {} + Pledge(const Pledge& aOther) = delete; + Pledge& operator = (const Pledge&) = delete; template void Then(OnSuccessType aOnSuccess) { - Then(aOnSuccess, [](nsresult){}); + Then(aOnSuccess, [](ErrorType&){}); } template void Then(OnSuccessType aOnSuccess, OnFailureType aOnFailure) { - class F : public FunctorsBase + class Functors : public FunctorsBase { public: - F(OnSuccessType& aOnSuccess, OnFailureType& aOnFailure) + Functors(OnSuccessType& aOnSuccess, OnFailureType& aOnFailure) : mOnSuccess(aOnSuccess), mOnFailure(aOnFailure) {} - void Succeed(const ValueType& result) + void Succeed(ValueType& result) { mOnSuccess(result); } - void Fail(nsresult rv) + void Fail(ErrorType& error) { - mOnFailure(rv); + mOnFailure(error); }; OnSuccessType mOnSuccess; OnFailureType mOnFailure; }; - mFunctors = new F(aOnSuccess, aOnFailure); + mFunctors = new Functors(aOnSuccess, aOnFailure); if (mDone) { - if (mResult == NS_OK) { + if (!mError) { mFunctors->Succeed(mValue); } else { - mFunctors->Fail(mResult); + mFunctors->Fail(*mError); } } } @@ -106,34 +115,127 @@ protected: { if (!mDone) { mDone = true; - MOZ_ASSERT(mResult == NS_OK); + MOZ_ASSERT(!mError); if (mFunctors) { mFunctors->Succeed(mValue); } } } - void Reject(nsresult rv) + void Reject(ErrorType rv) { if (!mDone) { mDone = true; - mResult = rv; + mError = rv; if (mFunctors) { - mFunctors->Fail(mResult); + mFunctors->Fail(mError); } } } ValueType mValue; -protected: +private: ~Pledge() {}; bool mDone; - nsresult mResult; + nsRefPtr mError; + ScopedDeletePtr mFunctors; +}; + +template +class Pledge : public PledgeBase +{ + // TODO: Remove workaround once mozilla allows std::function from + // wo/std::function support, do template + virtual trick to accept lambdas + class FunctorsBase + { + public: + FunctorsBase() {} + virtual void Succeed(ValueType& result) = 0; + virtual void Fail(nsresult error) = 0; + virtual ~FunctorsBase() {}; + }; + +public: + explicit Pledge() : mDone(false), mError(NS_OK) {} + Pledge(const Pledge& aOther) = delete; + Pledge& operator = (const Pledge&) = delete; + + template + void Then(OnSuccessType aOnSuccess) + { + Then(aOnSuccess, [](nsresult){}); + } + + template + void Then(OnSuccessType aOnSuccess, OnFailureType aOnFailure) + { + class Functors : public FunctorsBase + { + public: + Functors(OnSuccessType& aOnSuccess, OnFailureType& aOnFailure) + : mOnSuccess(aOnSuccess), mOnFailure(aOnFailure) {} + + void Succeed(ValueType& result) + { + mOnSuccess(result); + } + void Fail(nsresult rv) + { + mOnFailure(rv); + }; + + OnSuccessType mOnSuccess; + OnFailureType mOnFailure; + }; + mFunctors = new Functors(aOnSuccess, aOnFailure); + + if (mDone) { + if (mError == NS_OK) { + mFunctors->Succeed(mValue); + } else { + mFunctors->Fail(mError); + } + } + } + + void Resolve(const ValueType& aValue) + { + mValue = aValue; + Resolve(); + } +protected: + void Resolve() + { + if (!mDone) { + mDone = true; + MOZ_ASSERT(mError == NS_OK); + if (mFunctors) { + mFunctors->Succeed(mValue); + } + } + } + + void Reject(nsresult error) + { + if (!mDone) { + mDone = true; + mError = error; + if (mFunctors) { + mFunctors->Fail(mError); + } + } + } + + ValueType mValue; private: - nsAutoPtr mFunctors; + ~Pledge() {}; + bool mDone; + nsresult mError; + ScopedDeletePtr mFunctors; }; /* media::NewRunnableFrom() - Create an nsRunnable from a lambda. + * media::NewTaskFrom() - Create a Task from a lambda. * * Passing variables (closures) to an async function is clunky with nsRunnable: * @@ -192,6 +294,27 @@ NewRunnableFrom(OnRunType aOnRun) return new LambdaRunnable(aOnRun); } +template +class LambdaTask : public Task +{ +public: + explicit LambdaTask(OnRunType& aOnRun) : mOnRun(aOnRun) {} +private: + void + Run() + { + return mOnRun(); + } + OnRunType mOnRun; +}; + +template +LambdaTask* +NewTaskFrom(OnRunType aOnRun) +{ + return new LambdaTask(aOnRun); +} + /* media::CoatCheck - There and back again. Park an object in exchange for an id. * * A common problem with calling asynchronous functions that do work on other @@ -213,7 +336,7 @@ NewRunnableFrom(OnRunType aOnRun) * void DoFoo() * { * nsRefPtr foo = new Foo(); - * uint32_t requestId = mOutstandingFoos.Append(foo); + * uint32_t requestId = mOutstandingFoos.Append(*foo); * sChild->SendFoo(requestId); * } * @@ -230,13 +353,13 @@ NewRunnableFrom(OnRunType aOnRun) * * class FooGetter * { - * CoatCheck mOutstandingPledges; + * CoatCheck> mOutstandingPledges; * * public: * already_addRefed> GetFooAsynchronously() * { * nsRefPtr> p = new Pledge(); - * uint32_t requestId = mOutstandingPledges.Append(p); + * uint32_t requestId = mOutstandingPledges.Append(*p); * sChild->SendFoo(requestId); * return p.forget(); * } diff --git a/dom/media/systemservices/PMedia.ipdl b/dom/media/systemservices/PMedia.ipdl index b25423be3599..e94dcb65637b 100644 --- a/dom/media/systemservices/PMedia.ipdl +++ b/dom/media/systemservices/PMedia.ipdl @@ -3,14 +3,13 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ include protocol PContent; -include protocol PBackground; namespace mozilla { namespace media { protocol PMedia { - manager PBackground; + manager PContent; parent: /** diff --git a/dom/media/tests/mochitest/test_getUserMedia_constraints.html b/dom/media/tests/mochitest/test_getUserMedia_constraints.html index 02cd23f4caae..f01bd6d847e7 100644 --- a/dom/media/tests/mochitest/test_getUserMedia_constraints.html +++ b/dom/media/tests/mochitest/test_getUserMedia_constraints.html @@ -23,14 +23,6 @@ var tests = [ constraints: { audio: { somethingUnknown: { exact: 0 } }, fake: true }, error: null }, - { message: "video overconstrained by facingMode fails", - constraints: { video: { facingMode:{ exact: 'left' } }, - fake: true }, - error: "NotFoundError" }, - { message: "video overconstrained by facingMode array fails", - constraints: { video: { facingMode:{ exact: ['left', 'right'] } }, - fake: true }, - error: "NotFoundError" }, { message: "audio overconstrained by facingMode ignored", constraints: { audio: { facingMode: { exact: 'left' } }, fake: true }, diff --git a/dom/media/webrtc/MediaEngine.h b/dom/media/webrtc/MediaEngine.h index 6d9cc4910ae0..2f5caf694572 100644 --- a/dom/media/webrtc/MediaEngine.h +++ b/dom/media/webrtc/MediaEngine.h @@ -88,8 +88,8 @@ public: /* Populate the human readable name of this device in the nsAString */ virtual void GetName(nsAString&) = 0; - /* Populate the UUID of this device in the nsAString */ - virtual void GetUUID(nsAString&) = 0; + /* Populate the UUID of this device in the nsACString */ + virtual void GetUUID(nsACString&) = 0; /* Release the device back to the system. */ virtual nsresult Deallocate() = 0; diff --git a/dom/media/webrtc/MediaEngineCameraVideoSource.cpp b/dom/media/webrtc/MediaEngineCameraVideoSource.cpp index 8226ba727dd4..196d166f6079 100644 --- a/dom/media/webrtc/MediaEngineCameraVideoSource.cpp +++ b/dom/media/webrtc/MediaEngineCameraVideoSource.cpp @@ -9,11 +9,7 @@ namespace mozilla { using namespace mozilla::gfx; -using dom::OwningLongOrConstrainLongRange; -using dom::ConstrainLongRange; -using dom::OwningDoubleOrConstrainDoubleRange; -using dom::ConstrainDoubleRange; -using dom::MediaTrackConstraintSet; +using namespace mozilla::dom; extern PRLogModuleInfo* GetMediaManagerLog(); #define LOG(msg) MOZ_LOG(GetMediaManagerLog(), mozilla::LogLevel::Debug, msg) @@ -62,51 +58,106 @@ MediaEngineCameraVideoSource::GetCapability(size_t aIndex, template /* static */ uint32_t -MediaEngineCameraVideoSource::FitnessDistance(ValueType n, +MediaEngineCameraVideoSource::FitnessDistance(ValueType aN, const ConstrainRange& aRange) { - if ((aRange.mExact.WasPassed() && aRange.mExact.Value() != n) || - (aRange.mMin.WasPassed() && aRange.mMin.Value() > n) || - (aRange.mMax.WasPassed() && aRange.mMax.Value() < n)) { + if ((aRange.mExact.WasPassed() && aRange.mExact.Value() != aN) || + (aRange.mMin.WasPassed() && aRange.mMin.Value() > aN) || + (aRange.mMax.WasPassed() && aRange.mMax.Value() < aN)) { return UINT32_MAX; } - if (!aRange.mIdeal.WasPassed() || n == aRange.mIdeal.Value()) { + if (!aRange.mIdeal.WasPassed() || aN == aRange.mIdeal.Value()) { return 0; } - return uint32_t(ValueType((std::abs(n - aRange.mIdeal.Value()) * 1000) / - std::max(std::abs(n), std::abs(aRange.mIdeal.Value())))); + return uint32_t(ValueType((std::abs(aN - aRange.mIdeal.Value()) * 1000) / + std::max(std::abs(aN), std::abs(aRange.mIdeal.Value())))); } // Binding code doesn't templatize well... /*static*/ uint32_t -MediaEngineCameraVideoSource::FitnessDistance(int32_t n, +MediaEngineCameraVideoSource::FitnessDistance(int32_t aN, const OwningLongOrConstrainLongRange& aConstraint, bool aAdvanced) { if (aConstraint.IsLong()) { ConstrainLongRange range; (aAdvanced ? range.mExact : range.mIdeal).Construct(aConstraint.GetAsLong()); - return FitnessDistance(n, range); + return FitnessDistance(aN, range); } else { - return FitnessDistance(n, aConstraint.GetAsConstrainLongRange()); + return FitnessDistance(aN, aConstraint.GetAsConstrainLongRange()); } } /*static*/ uint32_t -MediaEngineCameraVideoSource::FitnessDistance(double n, +MediaEngineCameraVideoSource::FitnessDistance(double aN, const OwningDoubleOrConstrainDoubleRange& aConstraint, bool aAdvanced) { if (aConstraint.IsDouble()) { ConstrainDoubleRange range; (aAdvanced ? range.mExact : range.mIdeal).Construct(aConstraint.GetAsDouble()); - return FitnessDistance(n, range); + return FitnessDistance(aN, range); } else { - return FitnessDistance(n, aConstraint.GetAsConstrainDoubleRange()); + return FitnessDistance(aN, aConstraint.GetAsConstrainDoubleRange()); } } -/*static*/ uint32_t +// Fitness distance returned as integer math * 1000. Infinity = UINT32_MAX + +/* static */ uint32_t +MediaEngineCameraVideoSource::FitnessDistance(nsString aN, + const ConstrainDOMStringParameters& aParams) +{ + struct Func + { + static bool + Contains(const OwningStringOrStringSequence& aStrings, nsString aN) + { + return aStrings.IsString() ? aStrings.GetAsString() == aN + : aStrings.GetAsStringSequence().Contains(aN); + } + }; + + if (aParams.mExact.WasPassed() && !Func::Contains(aParams.mExact.Value(), aN)) { + return UINT32_MAX; + } + if (aParams.mIdeal.WasPassed() && !Func::Contains(aParams.mIdeal.Value(), aN)) { + return 1000; + } + return 0; +} + +/* static */ uint32_t +MediaEngineCameraVideoSource::FitnessDistance(nsString aN, + const OwningStringOrStringSequenceOrConstrainDOMStringParameters& aConstraint, + bool aAdvanced) +{ + if (aConstraint.IsString()) { + ConstrainDOMStringParameters params; + if (aAdvanced) { + params.mExact.Construct(); + params.mExact.Value().SetAsString() = aConstraint.GetAsString(); + } else { + params.mIdeal.Construct(); + params.mIdeal.Value().SetAsString() = aConstraint.GetAsString(); + } + return FitnessDistance(aN, params); + } else if (aConstraint.IsStringSequence()) { + ConstrainDOMStringParameters params; + if (aAdvanced) { + params.mExact.Construct(); + params.mExact.Value().SetAsStringSequence() = aConstraint.GetAsStringSequence(); + } else { + params.mIdeal.Construct(); + params.mIdeal.Value().SetAsStringSequence() = aConstraint.GetAsStringSequence(); + } + return FitnessDistance(aN, params); + } else { + return FitnessDistance(aN, aConstraint.GetAsConstrainDOMStringParameters()); + } +} + +uint32_t MediaEngineCameraVideoSource::GetFitnessDistance(const webrtc::CaptureCapability& aCandidate, const MediaTrackConstraintSet &aConstraints, bool aAdvanced) @@ -115,6 +166,7 @@ MediaEngineCameraVideoSource::GetFitnessDistance(const webrtc::CaptureCapability // This allows for orthogonal capabilities that are not in discrete steps. uint64_t distance = + uint64_t(FitnessDistance(mFacingMode, aConstraints.mFacingMode, aAdvanced)) + uint64_t(aCandidate.width? FitnessDistance(int32_t(aCandidate.width), aConstraints.mWidth, aAdvanced) : 0) + @@ -215,7 +267,7 @@ MediaEngineCameraVideoSource::LogConstraints( bool MediaEngineCameraVideoSource::ChooseCapability( - const dom::MediaTrackConstraints &aConstraints, + const MediaTrackConstraints &aConstraints, const MediaEnginePrefs &aPrefs) { if (MOZ_LOG_TEST(GetMediaManagerLog(), LogLevel::Debug)) { @@ -324,6 +376,52 @@ MediaEngineCameraVideoSource::ChooseCapability( return true; } +void +MediaEngineCameraVideoSource::SetName(nsString aName) +{ + mDeviceName = aName; + bool hasFacingMode = false; + VideoFacingModeEnum facingMode = VideoFacingModeEnum::User; + + // Set facing mode based on device name. +#if defined(MOZ_B2G_CAMERA) && defined(MOZ_WIDGET_GONK) + if (aName.EqualsLiteral("back")) { + hasFacingMode = true; + facingMode = VideoFacingModeEnum::Environment; + } else if (aName.EqualsLiteral("front")) { + hasFacingMode = true; + facingMode = VideoFacingModeEnum::User; + } +#endif // MOZ_B2G_CAMERA +#if defined(ANDROID) && !defined(MOZ_WIDGET_GONK) + // Names are generated. Example: "Camera 0, Facing back, Orientation 90" + // + // See media/webrtc/trunk/webrtc/modules/video_capture/android/java/src/org/ + // webrtc/videoengine/VideoCaptureDeviceInfoAndroid.java + + if (aName.Find(NS_LITERAL_STRING("Facing back")) != kNotFound) { + hasFacingMode = true; + facingMode = VideoFacingModeEnum::Environment; + } else if (aName.Find(NS_LITERAL_STRING("Facing front")) != kNotFound) { + hasFacingMode = true; + facingMode = VideoFacingModeEnum::User; + } +#endif // ANDROID +#ifdef XP_MACOSX + // Kludge to test user-facing cameras on OSX. + if (aName.Find(NS_LITERAL_STRING("Face")) != -1) { + hasFacingMode = true; + facingMode = VideoFacingModeEnum::User; + } +#endif + if (hasFacingMode) { + mFacingMode.Assign(NS_ConvertUTF8toUTF16( + VideoFacingModeEnumValues::strings[uint32_t(facingMode)].value)); + } else { + mFacingMode.Truncate(); + } +} + void MediaEngineCameraVideoSource::GetName(nsAString& aName) { @@ -331,11 +429,24 @@ MediaEngineCameraVideoSource::GetName(nsAString& aName) } void -MediaEngineCameraVideoSource::GetUUID(nsAString& aUUID) +MediaEngineCameraVideoSource::SetUUID(const char* aUUID) +{ + mUniqueId.Assign(aUUID); +} + +void +MediaEngineCameraVideoSource::GetUUID(nsACString& aUUID) { aUUID = mUniqueId; } +const nsCString& +MediaEngineCameraVideoSource::GetUUID() +{ + return mUniqueId; +} + + void MediaEngineCameraVideoSource::SetDirectListeners(bool aHasDirectListeners) { diff --git a/dom/media/webrtc/MediaEngineCameraVideoSource.h b/dom/media/webrtc/MediaEngineCameraVideoSource.h index 3ea9ec039f51..14ba7be9f366 100644 --- a/dom/media/webrtc/MediaEngineCameraVideoSource.h +++ b/dom/media/webrtc/MediaEngineCameraVideoSource.h @@ -34,7 +34,7 @@ public: virtual void GetName(nsAString& aName) override; - virtual void GetUUID(nsAString& aUUID) override; + virtual void GetUUID(nsACString& aUUID) override; virtual void SetDirectListeners(bool aHasListeners) override; virtual nsresult Config(bool aEchoOn, uint32_t aEcho, bool aAgcOn, uint32_t aAGC, @@ -81,15 +81,20 @@ protected: TrackID aID, StreamTime delta); template - static uint32_t FitnessDistance(ValueType n, const ConstrainRange& aRange); - static uint32_t FitnessDistance(int32_t n, + static uint32_t FitnessDistance(ValueType aN, const ConstrainRange& aRange); + static uint32_t FitnessDistance(int32_t aN, const dom::OwningLongOrConstrainLongRange& aConstraint, bool aAdvanced); - static uint32_t FitnessDistance(double n, + static uint32_t FitnessDistance(double aN, const dom::OwningDoubleOrConstrainDoubleRange& aConstraint, bool aAdvanced); + static uint32_t FitnessDistance(nsString aN, + const dom::OwningStringOrStringSequenceOrConstrainDOMStringParameters& aConstraint, + bool aAdvanced); + static uint32_t FitnessDistance(nsString aN, + const dom::ConstrainDOMStringParameters& aParams); - static uint32_t GetFitnessDistance(const webrtc::CaptureCapability& aCandidate, - const dom::MediaTrackConstraintSet &aConstraints, - bool aAdvanced); + uint32_t GetFitnessDistance(const webrtc::CaptureCapability& aCandidate, + const dom::MediaTrackConstraintSet &aConstraints, + bool aAdvanced); static void TrimLessFitCandidates(CapabilitySet& set); static void LogConstraints(const dom::MediaTrackConstraintSet& aConstraints, bool aAdvanced); @@ -97,6 +102,9 @@ protected: virtual void GetCapability(size_t aIndex, webrtc::CaptureCapability& aOut); bool ChooseCapability(const dom::MediaTrackConstraints &aConstraints, const MediaEnginePrefs &aPrefs); + void SetName(nsString aName); + void SetUUID(const char* aUUID); + const nsCString& GetUUID(); // protected access // Engine variables. @@ -124,8 +132,10 @@ protected: webrtc::CaptureCapability mCapability; // Doesn't work on OS X. nsTArray mHardcodedCapabilities; // For OSX & B2G +private: nsString mDeviceName; - nsString mUniqueId; + nsCString mUniqueId; + nsString mFacingMode; }; diff --git a/dom/media/webrtc/MediaEngineDefault.cpp b/dom/media/webrtc/MediaEngineDefault.cpp index d581a65be56a..81dbd066fc3a 100644 --- a/dom/media/webrtc/MediaEngineDefault.cpp +++ b/dom/media/webrtc/MediaEngineDefault.cpp @@ -62,9 +62,9 @@ MediaEngineDefaultVideoSource::GetName(nsAString& aName) } void -MediaEngineDefaultVideoSource::GetUUID(nsAString& aUUID) +MediaEngineDefaultVideoSource::GetUUID(nsACString& aUUID) { - aUUID.AssignLiteral(MOZ_UTF16("1041FCBD-3F12-4F7B-9E9B-1EC556DD5676")); + aUUID.AssignLiteral("1041FCBD-3F12-4F7B-9E9B-1EC556DD5676"); return; } @@ -342,9 +342,9 @@ MediaEngineDefaultAudioSource::GetName(nsAString& aName) } void -MediaEngineDefaultAudioSource::GetUUID(nsAString& aUUID) +MediaEngineDefaultAudioSource::GetUUID(nsACString& aUUID) { - aUUID.AssignLiteral(MOZ_UTF16("B7CBD7C1-53EF-42F9-8353-73F61C70C092")); + aUUID.AssignLiteral("B7CBD7C1-53EF-42F9-8353-73F61C70C092"); return; } diff --git a/dom/media/webrtc/MediaEngineDefault.h b/dom/media/webrtc/MediaEngineDefault.h index bee6c0b4e039..3e5a22edc0d0 100644 --- a/dom/media/webrtc/MediaEngineDefault.h +++ b/dom/media/webrtc/MediaEngineDefault.h @@ -39,7 +39,7 @@ public: virtual void Shutdown() override {}; virtual void GetName(nsAString&) override; - virtual void GetUUID(nsAString&) override; + virtual void GetUUID(nsACString&) override; virtual nsresult Allocate(const dom::MediaTrackConstraints &aConstraints, const MediaEnginePrefs &aPrefs) override; @@ -109,7 +109,7 @@ public: virtual void Shutdown() override {}; virtual void GetName(nsAString&) override; - virtual void GetUUID(nsAString&) override; + virtual void GetUUID(nsACString&) override; virtual nsresult Allocate(const dom::MediaTrackConstraints &aConstraints, const MediaEnginePrefs &aPrefs) override; diff --git a/dom/media/webrtc/MediaEngineGonkVideoSource.cpp b/dom/media/webrtc/MediaEngineGonkVideoSource.cpp index 29693cdbfc2c..b1db023c870b 100644 --- a/dom/media/webrtc/MediaEngineGonkVideoSource.cpp +++ b/dom/media/webrtc/MediaEngineGonkVideoSource.cpp @@ -337,8 +337,8 @@ MediaEngineGonkVideoSource::Init() { nsAutoCString deviceName; ICameraControl::GetCameraName(mCaptureIndex, deviceName); - CopyUTF8toUTF16(deviceName, mDeviceName); - CopyUTF8toUTF16(deviceName, mUniqueId); + SetName(NS_ConvertUTF8toUTF16(deviceName)); + SetUUID(deviceName.get()); mInitDone = true; } diff --git a/dom/media/webrtc/MediaEngineTabVideoSource.cpp b/dom/media/webrtc/MediaEngineTabVideoSource.cpp index ac062250e7a3..cbc443c316a7 100644 --- a/dom/media/webrtc/MediaEngineTabVideoSource.cpp +++ b/dom/media/webrtc/MediaEngineTabVideoSource.cpp @@ -109,9 +109,9 @@ MediaEngineTabVideoSource::GetName(nsAString_internal& aName) } void -MediaEngineTabVideoSource::GetUUID(nsAString_internal& aUuid) +MediaEngineTabVideoSource::GetUUID(nsACString_internal& aUuid) { - aUuid.AssignLiteral(MOZ_UTF16("uuid")); + aUuid.AssignLiteral("tab"); } #define DEFAULT_TABSHARE_VIDEO_MAX_WIDTH 4096 diff --git a/dom/media/webrtc/MediaEngineTabVideoSource.h b/dom/media/webrtc/MediaEngineTabVideoSource.h index a02c4a0fae9d..1f2eca16d36d 100644 --- a/dom/media/webrtc/MediaEngineTabVideoSource.h +++ b/dom/media/webrtc/MediaEngineTabVideoSource.h @@ -20,7 +20,7 @@ class MediaEngineTabVideoSource : public MediaEngineVideoSource, nsIDOMEventList virtual void Shutdown() override {}; virtual void GetName(nsAString_internal&) override; - virtual void GetUUID(nsAString_internal&) override; + virtual void GetUUID(nsACString_internal&) override; virtual nsresult Allocate(const dom::MediaTrackConstraints &, const mozilla::MediaEnginePrefs&) override; virtual nsresult Deallocate() override; diff --git a/dom/media/webrtc/MediaEngineWebRTC.h b/dom/media/webrtc/MediaEngineWebRTC.h index 5d6f8cbebdb2..de3894bc8a26 100644 --- a/dom/media/webrtc/MediaEngineWebRTC.h +++ b/dom/media/webrtc/MediaEngineWebRTC.h @@ -153,12 +153,12 @@ public: , mNullTransport(nullptr) { MOZ_ASSERT(aVoiceEnginePtr); mDeviceName.Assign(NS_ConvertUTF8toUTF16(name)); - mDeviceUUID.Assign(NS_ConvertUTF8toUTF16(uuid)); + mDeviceUUID.Assign(uuid); Init(); } virtual void GetName(nsAString& aName) override; - virtual void GetUUID(nsAString& aUUID) override; + virtual void GetUUID(nsACString& aUUID) override; virtual nsresult Allocate(const dom::MediaTrackConstraints& aConstraints, const MediaEnginePrefs& aPrefs) override; @@ -223,7 +223,7 @@ private: bool mStarted; nsString mDeviceName; - nsString mDeviceUUID; + nsCString mDeviceUUID; bool mEchoOn, mAgcOn, mNoiseOn; webrtc::EcModes mEchoCancel; diff --git a/dom/media/webrtc/MediaEngineWebRTCAudio.cpp b/dom/media/webrtc/MediaEngineWebRTCAudio.cpp index 2dd504375e78..c9c238c2899c 100644 --- a/dom/media/webrtc/MediaEngineWebRTCAudio.cpp +++ b/dom/media/webrtc/MediaEngineWebRTCAudio.cpp @@ -187,7 +187,7 @@ MediaEngineWebRTCAudioSource::GetName(nsAString& aName) } void -MediaEngineWebRTCAudioSource::GetUUID(nsAString& aUUID) +MediaEngineWebRTCAudioSource::GetUUID(nsACString& aUUID) { if (mInitDone) { aUUID.Assign(mDeviceUUID); diff --git a/dom/media/webrtc/MediaEngineWebRTCVideo.cpp b/dom/media/webrtc/MediaEngineWebRTCVideo.cpp index de5b00c02773..9f70402d3f4f 100644 --- a/dom/media/webrtc/MediaEngineWebRTCVideo.cpp +++ b/dom/media/webrtc/MediaEngineWebRTCVideo.cpp @@ -151,9 +151,7 @@ MediaEngineWebRTCVideoSource::NotifyPull(MediaStreamGraph* aGraph, size_t MediaEngineWebRTCVideoSource::NumCapabilities() { - NS_ConvertUTF16toUTF8 uniqueId(mUniqueId); // TODO: optimize this? - - int num = mViECapture->NumberOfCapabilities(uniqueId.get(), kMaxUniqueIdLength); + int num = mViECapture->NumberOfCapabilities(GetUUID().get(), kMaxUniqueIdLength); if (num > 0) { return num; } @@ -205,8 +203,7 @@ MediaEngineWebRTCVideoSource::GetCapability(size_t aIndex, if (!mHardcodedCapabilities.IsEmpty()) { MediaEngineCameraVideoSource::GetCapability(aIndex, aOut); } - NS_ConvertUTF16toUTF8 uniqueId(mUniqueId); // TODO: optimize this? - mViECapture->GetCaptureCapability(uniqueId.get(), kMaxUniqueIdLength, aIndex, aOut); + mViECapture->GetCaptureCapability(GetUUID().get(), kMaxUniqueIdLength, aIndex, aOut); } nsresult @@ -221,7 +218,7 @@ MediaEngineWebRTCVideoSource::Allocate(const dom::MediaTrackConstraints &aConstr if (!ChooseCapability(aConstraints, aPrefs)) { return NS_ERROR_UNEXPECTED; } - if (mViECapture->AllocateCaptureDevice(NS_ConvertUTF16toUTF8(mUniqueId).get(), + if (mViECapture->AllocateCaptureDevice(GetUUID().get(), kMaxUniqueIdLength, mCaptureIndex)) { return NS_ERROR_FAILURE; } @@ -387,9 +384,8 @@ MediaEngineWebRTCVideoSource::Init() uniqueId, kMaxUniqueIdLength)) { return; } - - CopyUTF8toUTF16(deviceName, mDeviceName); - CopyUTF8toUTF16(uniqueId, mUniqueId); + SetName(NS_ConvertUTF8toUTF16(deviceName)); + SetUUID(uniqueId); mInitDone = true; } @@ -443,11 +439,9 @@ void MediaEngineWebRTCVideoSource::Refresh(int aIndex) { return; } - CopyUTF8toUTF16(deviceName, mDeviceName); + SetName(NS_ConvertUTF8toUTF16(deviceName)); #ifdef DEBUG - nsString temp; - CopyUTF8toUTF16(uniqueId, temp); - MOZ_ASSERT(temp.Equals(mUniqueId)); + MOZ_ASSERT(GetUUID().Equals(uniqueId)); #endif } diff --git a/ipc/glue/BackgroundChildImpl.cpp b/ipc/glue/BackgroundChildImpl.cpp index a806692a27fe..884dc7c6b5f9 100644 --- a/ipc/glue/BackgroundChildImpl.cpp +++ b/ipc/glue/BackgroundChildImpl.cpp @@ -8,7 +8,6 @@ #include "BroadcastChannelChild.h" #include "ServiceWorkerManagerChild.h" #include "FileDescriptorSetChild.h" -#include "mozilla/media/MediaChild.h" #include "mozilla/Assertions.h" #include "mozilla/dom/PBlobChild.h" #include "mozilla/dom/cache/ActorUtils.h" @@ -329,18 +328,6 @@ BackgroundChildImpl::DeallocPCacheStreamControlChild(PCacheStreamControlChild* a return true; } -media::PMediaChild* -BackgroundChildImpl::AllocPMediaChild() -{ - return media::AllocPMediaChild(); -} - -bool -BackgroundChildImpl::DeallocPMediaChild(media::PMediaChild *aActor) -{ - return media::DeallocPMediaChild(aActor); -} - // ----------------------------------------------------------------------------- // MessageChannel/MessagePort API // ----------------------------------------------------------------------------- diff --git a/ipc/glue/BackgroundChildImpl.h b/ipc/glue/BackgroundChildImpl.h index c40db905a7c5..345209090595 100644 --- a/ipc/glue/BackgroundChildImpl.h +++ b/ipc/glue/BackgroundChildImpl.h @@ -71,12 +71,6 @@ protected: virtual bool DeallocPFileDescriptorSetChild(PFileDescriptorSetChild* aActor) override; - virtual PMediaChild* - AllocPMediaChild() override; - - virtual bool - DeallocPMediaChild(PMediaChild* aActor) override; - virtual PVsyncChild* AllocPVsyncChild() override; diff --git a/ipc/glue/BackgroundParentImpl.cpp b/ipc/glue/BackgroundParentImpl.cpp index e1b6849d9439..f29ed4fc6631 100644 --- a/ipc/glue/BackgroundParentImpl.cpp +++ b/ipc/glue/BackgroundParentImpl.cpp @@ -6,7 +6,6 @@ #include "BroadcastChannelParent.h" #include "FileDescriptorSetParent.h" -#include "mozilla/media/MediaParent.h" #include "mozilla/AppProcessChecker.h" #include "mozilla/Assertions.h" #include "mozilla/dom/ContentParent.h" @@ -494,18 +493,6 @@ BackgroundParentImpl::DeallocPServiceWorkerManagerParent( return true; } -media::PMediaParent* -BackgroundParentImpl::AllocPMediaParent() -{ - return media::AllocPMediaParent(); -} - -bool -BackgroundParentImpl::DeallocPMediaParent(media::PMediaParent *aActor) -{ - return media::DeallocPMediaParent(aActor); -} - bool BackgroundParentImpl::RecvShutdownServiceWorkerRegistrar() { diff --git a/ipc/glue/BackgroundParentImpl.h b/ipc/glue/BackgroundParentImpl.h index b2ad232076ae..6dd54f75f267 100644 --- a/ipc/glue/BackgroundParentImpl.h +++ b/ipc/glue/BackgroundParentImpl.h @@ -92,12 +92,6 @@ protected: virtual bool DeallocPServiceWorkerManagerParent(PServiceWorkerManagerParent* aActor) override; - virtual PMediaParent* - AllocPMediaParent() override; - - virtual bool - DeallocPMediaParent(PMediaParent* aActor) override; - virtual bool RecvShutdownServiceWorkerRegistrar() override; diff --git a/ipc/glue/PBackground.ipdl b/ipc/glue/PBackground.ipdl index cd3e8f2b2de4..6b09ed079cbd 100644 --- a/ipc/glue/PBackground.ipdl +++ b/ipc/glue/PBackground.ipdl @@ -11,7 +11,6 @@ include protocol PCacheStorage; include protocol PCacheStreamControl; include protocol PFileDescriptorSet; include protocol PMessagePort; -include protocol PMedia; include protocol PServiceWorkerManager; include protocol PUDPSocket; include protocol PVsync; @@ -37,7 +36,6 @@ sync protocol PBackground manages PCacheStreamControl; manages PFileDescriptorSet; manages PMessagePort; - manages PMedia; manages PServiceWorkerManager; manages PUDPSocket; manages PVsync; @@ -49,7 +47,6 @@ parent: PBackgroundIDBFactory(LoggingInfo loggingInfo); PVsync(); - PMedia(); PUDPSocket(OptionalPrincipalInfo pInfo, nsCString filter); PBroadcastChannel(PrincipalInfo pInfo, nsString origin, nsString channel,