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
This commit is contained in:
Jan-Ivar Bruaroey 2015-06-18 11:46:36 -04:00
parent d9a401584e
commit d4bc9fa237
32 changed files with 877 additions and 765 deletions

View File

@ -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()
{

View File

@ -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;

View File

@ -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()
{

View File

@ -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;

View File

@ -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();

View File

@ -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<bool> sInShutdown;
@ -267,150 +270,6 @@ private:
nsRefPtr<MediaManager> 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<nsIGetUserMediaDevicesSuccessCallback>& aOnSuccess,
nsCOMPtr<nsIDOMGetUserMediaErrorCallback>& aOnFailure,
nsTArray<nsRefPtr<MediaDevice>>* 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<nsIThread> mainThread = do_GetMainThread();
NS_ProxyRelease(mainThread, mOnSuccess);
NS_ProxyRelease(mainThread, mOnFailure);
}
}
nsresult
AnonymizeId(nsAString& aId, const nsACString& aOriginKey)
{
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;
}
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<nsIWritableVariant> 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<MediaStreamError> error = new MediaStreamError(window,
NS_LITERAL_STRING("NotFoundError"));
mOnFailure->OnError(error);
}
return NS_OK;
}
devices->SetAsEmptyArray(); // SetAsArray() fails on zero length arrays.
} else {
nsTArray<nsIMediaDevice*> 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<void*>(
static_cast<const void*>(tmp.Elements())
));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
mOnSuccess->OnSuccess(devices);
return NS_OK;
}
nsCString mOriginKey;
private:
nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> mOnSuccess;
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mOnFailure;
nsAutoPtr<nsTArray<nsRefPtr<MediaDevice>>> mDevices;
uint64_t mWindowID;
bool mIsGum;
nsRefPtr<MediaManager> 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<const MediaTrackConstraintSet*>& 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<media::ChildPledge<bool>> 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::PledgeSourceSet>
MediaManager::EnumerateRawDevices(uint64_t aWindowId,
const MediaStreamConstraints& aConstraints)
{
public:
GetUserMediaDevicesTask(
const MediaStreamConstraints& aConstraints,
already_AddRefed<nsIGetUserMediaDevicesSuccessCallback> aOnSuccess,
already_AddRefed<nsIDOMGetUserMediaErrorCallback> 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<PledgeSourceSet> 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<MediaEngine> backend;
if (mConstraints.mFake || mUseFakeDevices)
backend = new MediaEngineDefault(mConstraints.mFakeTracks);
else
backend = mManager->GetBackend(mWindowId);
typedef nsTArray<nsRefPtr<MediaDevice>> SourceSet;
if (aConstraints.mFake || fake) {
backend = new MediaEngineDefault(aConstraints.mFakeTracks);
} else {
nsRefPtr<MediaManager> manager = MediaManager_GetInstance();
backend = manager->GetBackend(aWindowId);
}
ScopedDeletePtr<SourceSet> result(new SourceSet);
if (IsOn(mConstraints.mVideo)) {
if (IsOn(aConstraints.mVideo)) {
nsTArray<nsRefPtr<VideoDevice>> 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<nsRefPtr<AudioDevice>> 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<DeviceSuccessCallbackRunnable> 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<media::ChildPledge<nsCString>> 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<nsIGetUserMediaDevicesSuccessCallback> mOnSuccess;
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mOnFailure;
nsRefPtr<MediaManager> 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<SourceSet> result(handoff);
nsRefPtr<MediaManager> mgr = MediaManager_GetInstance();
if (!mgr) {
return NS_OK;
}
nsRefPtr<PledgeSourceSet> 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<nsIPrefService> prefs = do_GetService("@mozilla.org/preferences-service;1", &rv);
if (NS_SUCCEEDED(rv)) {
@ -1654,6 +1375,15 @@ MediaManager::GetInstance()
return service.forget();
}
media::Parent<media::NonE10s>*
MediaManager::GetNonE10sParent()
{
if (!mNonE10sParent) {
mNonE10sParent = new media::Parent<media::NonE10s>(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<nsIDOMGetUserMediaSuccessCallback> onSuccess(aOnSuccess);
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> 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<nsIGetUserMediaDevicesSuccessCallback> onSuccess(aOnSuccess);
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onFailure(aOnFailure);
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;
}
// 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<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>
MediaManager::ToJSArray(SourceSet& aDevices)
{
nsCOMPtr<nsIWritableVariant> var = do_CreateInstance("@mozilla.org/variant;1");
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();
}
already_AddRefed<MediaManager::PledgeSourceSet>
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<PledgeSourceSet> 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<nsIDocument> doc = aWindow->GetDoc();
nsCOMPtr<nsILoadContext> 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<nsPIDOMWindow*>
(nsGlobalWindow::GetInnerWindowWithId(aWindowId));
nsPrincipal::GetOriginForURI(window->GetDocumentURI(), origin);
return NS_OK;
nsCOMPtr<nsIDocument> doc = window->GetDoc();
nsCOMPtr<nsILoadContext> 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<Pledge<nsCString>> p = media::GetOriginKey(origin, privateBrowsing);
p->Then([id, aWindowId, aConstraints](const nsCString& aOriginKey) mutable {
MOZ_ASSERT(NS_IsMainThread());
nsRefPtr<MediaManager> mgr = MediaManager_GetInstance();
nsRefPtr<PledgeSourceSet> p = mgr->EnumerateRawDevices(aWindowId, aConstraints);
p->Then([id, aWindowId, aOriginKey](SourceSet*& aDevices) mutable {
ScopedDeletePtr<SourceSet> devices(aDevices); // secondary result
// Only run if window is still on our active list.
nsRefPtr<MediaManager> mgr = MediaManager_GetInstance();
if (!mgr) {
return NS_OK;
}
nsRefPtr<PledgeSourceSet> 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<nsIGetUserMediaDevicesSuccessCallback> onSuccess(aOnSuccess);
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> 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<PledgeSourceSet> p = EnumerateDevicesImpl(windowId, c);
p->Then([onSuccess](SourceSet*& aDevices) mutable {
ScopedDeletePtr<SourceSet> devices(aDevices); // grab result
nsCOMPtr<nsIWritableVariant> 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<nsIGetUserMediaDevicesSuccessCallback> onSuccess(aOnSuccess);
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onFailure(aOnFailure);
if (!aWindowId) {
aWindowId = aWindow->WindowID();
}
nsRefPtr<PledgeSourceSet> p = EnumerateDevicesImpl(aWindowId, aConstraints);
p->Then([aWindowId, onSuccess, onFailure](SourceSet*& aDevices) mutable {
ScopedDeletePtr<SourceSet> devices(aDevices); // grab result
if (devices->Length()) {
nsCOMPtr<nsIWritableVariant> array = MediaManager_ToJSArray(*devices);
onSuccess->OnSuccess(array);
} else {
nsRefPtr<nsGlobalWindow> window = nsGlobalWindow::GetInnerWindowWithId(aWindowId);
if (!window) {
return NS_ERROR_UNEXPECTED;
}
nsRefPtr<MediaStreamError> 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;
}

View File

@ -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<MediaEngineSource> mSource;
};
@ -534,6 +534,7 @@ public:
NS_DECL_NSIOBSERVER
NS_DECL_NSIMEDIAMANAGERSERVICE
media::Parent<media::NonE10s>* 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<nsRefPtr<MediaDevice>> SourceSet;
typedef media::Pledge<SourceSet*, dom::MediaStreamError> 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<nsIWritableVariant> ToJSArray(SourceSet& aDevices);
private:
already_AddRefed<PledgeSourceSet>
EnumerateRawDevices(uint64_t aWindowId,
const dom::MediaStreamConstraints& aConstraints);
already_AddRefed<PledgeSourceSet>
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<MediaManager> sSingleton;
media::CoatCheck<PledgeSourceSet> mOutstandingPledges;
#if defined(MOZ_B2G_CAMERA) && defined(MOZ_WIDGET_GONK)
nsRefPtr<nsDOMCameraManager> mCameraManager;
#endif
public:
media::CoatCheck<media::Pledge<nsCString>> mGetOriginKeyPledges;
ScopedDeletePtr<media::Parent<media::NonE10s>> mNonE10sParent;
};
} // namespace mozilla

View File

@ -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);

View File

@ -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;
};

View File

@ -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<typename ValueType> void
ChildPledge<ValueType>::ActorCreated(PBackgroundChild* aActor)
{
if (!sChild) {
// Create PMedia by sending a message to the parent
sChild = static_cast<Child*>(aActor->SendPMediaConstructor());
}
Run(sChild);
}
template<typename ValueType> void
ChildPledge<ValueType>::ActorFailed()
{
Pledge<ValueType>::Reject(NS_ERROR_UNEXPECTED);
}
template<typename ValueType> NS_IMPL_ADDREF(ChildPledge<ValueType>)
template<typename ValueType> NS_IMPL_RELEASE(ChildPledge<ValueType>)
template<typename ValueType> NS_INTERFACE_MAP_BEGIN(ChildPledge<ValueType>)
NS_INTERFACE_MAP_ENTRY(nsIIPCBackgroundChildCreateCallback)
NS_INTERFACE_MAP_END
already_AddRefed<ChildPledge<nsCString>>
already_AddRefed<Pledge<nsCString>>
GetOriginKey(const nsCString& aOrigin, bool aPrivateBrowsing)
{
class Pledge : public ChildPledge<nsCString>
{
public:
explicit Pledge(const nsCString& aOrigin, bool aPrivateBrowsing)
: mOrigin(aOrigin), mPrivateBrowsing(aPrivateBrowsing) {}
private:
~Pledge() {}
void Run(PMediaChild* aChild)
{
Child* child = static_cast<Child*>(aChild);
nsRefPtr<MediaManager> mgr = MediaManager::GetInstance();
MOZ_ASSERT(mgr);
uint32_t id = child->AddRequestPledge(*this);
child->SendGetOriginKey(id, mOrigin, mPrivateBrowsing);
}
const nsCString mOrigin;
const bool mPrivateBrowsing;
};
nsRefPtr<Pledge<nsCString>> p = new Pledge<nsCString>();
uint32_t id = mgr->mGetOriginKeyPledges.Append(*p);
nsRefPtr<ChildPledge<nsCString>> p = new Pledge(aOrigin, aPrivateBrowsing);
nsCOMPtr<nsIIPCBackgroundChildCreateCallback> 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<ChildPledge<bool>>
void
SanitizeOriginKeys(const uint64_t& aSinceWhen)
{
class Pledge : public ChildPledge<bool>
{
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<ChildPledge<bool>> p = new Pledge(aSinceWhen);
nsCOMPtr<nsIIPCBackgroundChildCreateCallback> 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<Parent<NonE10s>> tmpParent(new Parent<NonE10s>(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<Child*>(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<nsCString>& aPledge)
void Child::ActorDestroy(ActorDestroyReason aWhy)
{
return mRequestPledges.Append(aPledge);
}
already_AddRefed<ChildPledge<nsCString>>
Child::RemoveRequestPledge(uint32_t aRequestId)
{
return mRequestPledges.Remove(aRequestId);
mActorDestroyed = true;
}
bool
Child::RecvGetOriginKeyResponse(const uint32_t& aRequestId, const nsCString& aKey)
{
nsRefPtr<ChildPledge<nsCString>> pledge = RemoveRequestPledge(aRequestId);
nsRefPtr<MediaManager> mgr = MediaManager::GetInstance();
if (!mgr) {
return false;
}
nsRefPtr<Pledge<nsCString>> 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<Child*>(aActor)->Release();
delete static_cast<Child*>(aActor);
return true;
}

View File

@ -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<typename ValueType>
class ChildPledge : public Pledge<ValueType>,
public nsIIPCBackgroundChildCreateCallback
{
friend Child;
NS_DECL_NSIIPCBACKGROUNDCHILDCREATECALLBACK
NS_DECL_ISUPPORTS
public:
explicit ChildPledge() {};
protected:
virtual ~ChildPledge() {}
virtual void Run(PMediaChild* aMedia) = 0;
};
already_AddRefed<ChildPledge<nsCString>>
already_AddRefed<Pledge<nsCString>>
GetOriginKey(const nsCString& aOrigin, bool aPrivateBrowsing);
already_AddRefed<ChildPledge<bool>>
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<nsCString>& aPledge);
already_AddRefed<ChildPledge<nsCString>> RemoveRequestPledge(uint32_t aRequestId);
private:
void ActorDestroy(ActorDestroyReason aWhy) override;
virtual ~Child();
private:
CoatCheck<ChildPledge<nsCString>> mRequestPledges;
bool mActorDestroyed;
};
PMediaChild* AllocPMediaChild();

View File

@ -32,13 +32,13 @@ PRLogModuleInfo *gMediaParentLog;
namespace mozilla {
namespace media {
static StaticMutex gMutex;
static ParentSingleton* sParentSingleton = nullptr;
static Parent<PMediaParent>* 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<Pledge<nsCString>> mOutstandingPledges;
};
NS_IMPL_ISUPPORTS0(ParentSingleton)
NS_IMPL_ISUPPORTS0(OriginKeyStore)
bool
Parent::RecvGetOriginKey(const uint32_t& aRequestId,
template<> /* static */
Parent<PMediaParent>* Parent<PMediaParent>::GetSingleton()
{
return sIPCServingParent;
}
template<> /* static */
Parent<NonE10s>* Parent<NonE10s>::GetSingleton()
{
nsRefPtr<MediaManager> 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<class Super> static
Parent<Super>* GccGetSingleton() { return Parent<Super>::GetSingleton(); };
template<class Super> bool
Parent<Super>::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<ParentSingleton> singleton(mSingleton);
nsCOMPtr<nsIThread> returnThread = NS_GetCurrentThread();
nsRefPtr<Pledge<nsCString>> p = new Pledge<nsCString>();
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<nsIFile> 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<nsIEventTarget> 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<Pledge<nsCString>> 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<nsIFile> profileDir;
nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
getter_AddRefs(profileDir));
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
nsRefPtr<media::Parent> 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<Pledge<nsCString>> p = new Pledge<nsCString>();
uint32_t id = mOutstandingPledges.Append(*p);
nsCOMPtr<nsIEventTarget> sts = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
MOZ_ASSERT(sts);
nsRefPtr<OriginKeyStore> 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<Super>(); // GetSingleton();
if (!parent) {
return NS_OK;
}
nsRefPtr<Pledge<nsCString>> 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<MediaManager> mgr = MediaManager::GetInstance();
if (!mgr) {
return NS_OK;
}
nsRefPtr<Pledge<nsCString>> pledge =
mgr->mGetOriginKeyPledges.Remove(aRequestId);
if (pledge) {
pledge->Resolve(aKey);
}
}
return NS_OK;
});
return true;
}
bool
Parent::RecvSanitizeOriginKeys(const uint64_t& aSinceWhen)
template<class Super> bool
Parent<Super>::RecvSanitizeOriginKeys(const uint64_t& aSinceWhen)
{
nsRefPtr<ParentSingleton> singleton(mSingleton);
// First, over to main to get profile dir.
nsresult rv;
rv = NS_DispatchToMainThread(NewRunnableFrom([singleton,
aSinceWhen]() -> nsresult {
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIFile> profileDir;
nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIFile> 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<nsIEventTarget> 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<nsIEventTarget> sts = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
MOZ_ASSERT(sts);
nsRefPtr<OriginKeyStore> 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<class Super> void
Parent<Super>::ActorDestroy(ActorDestroyReason aWhy)
{
// No more IPC from here
mDestroyed = true;
LOG((__FUNCTION__));
}
Parent::Parent()
: mSingleton(ParentSingleton::Get())
template<class Super>
Parent<Super>::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<class Super>
Parent<Super>::~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<PMediaParent>();
return sIPCServingParent;
}
bool
DeallocPMediaParent(media::PMediaParent *aActor)
{
static_cast<Parent*>(aActor)->Release();
MOZ_ASSERT(sIPCServingParent == static_cast<Parent<PMediaParent>*>(aActor));
delete sIPCServingParent;
return true;
}
}
}
// Instantiate templates to satisfy linker
template class mozilla::media::Parent<mozilla::media::NonE10s>;

View File

@ -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<mozilla::ipc::IProtocol>::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 Super>
class Parent : public Super
{
typedef mozilla::ipc::IProtocolManager<mozilla::ipc::IProtocol>::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<ParentSingleton> mSingleton;
nsRefPtr<OriginKeyStore> mOriginKeyStore;
bool mDestroyed;
bool mSameProcess;
CoatCheck<Pledge<nsCString>> mOutstandingPledges;
};
PMediaParent* AllocPMediaParent();

View File

@ -40,8 +40,16 @@ namespace media {
* See media::CoatCheck below for an example of GetFooAsynchronously().
*/
template<typename ValueType>
class Pledge
class PledgeBase
{
public:
NS_INLINE_DECL_REFCOUNTING(PledgeBase);
protected:
virtual ~PledgeBase() {};
};
template<typename ValueType, typename ErrorType = nsresult>
class Pledge : public PledgeBase
{
// TODO: Remove workaround once mozilla allows std::function from <functional>
// 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<typename OnSuccessType>
void Then(OnSuccessType aOnSuccess)
{
Then(aOnSuccess, [](nsresult){});
Then(aOnSuccess, [](ErrorType&){});
}
template<typename OnSuccessType, typename OnFailureType>
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<ErrorType> mError;
ScopedDeletePtr<FunctorsBase> mFunctors;
};
template<typename ValueType>
class Pledge<ValueType, nsresult> : public PledgeBase
{
// TODO: Remove workaround once mozilla allows std::function from <functional>
// 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<typename OnSuccessType>
void Then(OnSuccessType aOnSuccess)
{
Then(aOnSuccess, [](nsresult){});
}
template<typename OnSuccessType, typename OnFailureType>
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<FunctorsBase> mFunctors;
~Pledge() {};
bool mDone;
nsresult mError;
ScopedDeletePtr<FunctorsBase> 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<OnRunType>(aOnRun);
}
template<typename OnRunType>
class LambdaTask : public Task
{
public:
explicit LambdaTask(OnRunType& aOnRun) : mOnRun(aOnRun) {}
private:
void
Run()
{
return mOnRun();
}
OnRunType mOnRun;
};
template<typename OnRunType>
LambdaTask<OnRunType>*
NewTaskFrom(OnRunType aOnRun)
{
return new LambdaTask<OnRunType>(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> 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<Foo> mOutstandingPledges;
* CoatCheck<Pledge<Foo>> mOutstandingPledges;
*
* public:
* already_addRefed<Pledge<Foo>> GetFooAsynchronously()
* {
* nsRefPtr<Pledge<Foo>> p = new Pledge<Foo>();
* uint32_t requestId = mOutstandingPledges.Append(p);
* uint32_t requestId = mOutstandingPledges.Append(*p);
* sChild->SendFoo(requestId);
* return p.forget();
* }

View File

@ -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:
/**

View File

@ -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 },

View File

@ -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;

View File

@ -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<class ValueType, class ConstrainRange>
/* 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)
{

View File

@ -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<class ValueType, class ConstrainRange>
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<webrtc::CaptureCapability> mHardcodedCapabilities; // For OSX & B2G
private:
nsString mDeviceName;
nsString mUniqueId;
nsCString mUniqueId;
nsString mFacingMode;
};

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -187,7 +187,7 @@ MediaEngineWebRTCAudioSource::GetName(nsAString& aName)
}
void
MediaEngineWebRTCAudioSource::GetUUID(nsAString& aUUID)
MediaEngineWebRTCAudioSource::GetUUID(nsACString& aUUID)
{
if (mInitDone) {
aUUID.Assign(mDeviceUUID);

View File

@ -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
}

View File

@ -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
// -----------------------------------------------------------------------------

View File

@ -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;

View File

@ -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()
{

View File

@ -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;

View File

@ -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,