Bug 1152401 - Add MediaDeviceKind member in MediaDevice to differentiate sink devices. r?jib
MozReview-Commit-ID: E6SGabjpqIA
--- a/browser/modules/ContentWebRTC.jsm
+++ b/browser/modules/ContentWebRTC.jsm
@@ -166,27 +166,27 @@ function prompt(aContentWindow, aWindowI
let audio = aConstraints.audio;
let sharingScreen = video && typeof(video) != "boolean" &&
video.mediaSource != "camera";
let sharingAudio = audio && typeof(audio) != "boolean" &&
audio.mediaSource != "microphone";
for (let device of aDevices) {
device = device.QueryInterface(Ci.nsIMediaDevice);
switch (device.type) {
- case "audio":
+ case "audioinput":
// Check that if we got a microphone, we have not requested an audio
// capture, and if we have requested an audio capture, we are not
// getting a microphone instead.
if (audio && (device.mediaSource == "microphone") != sharingAudio) {
audioDevices.push({name: device.name, deviceIndex: devices.length,
id: device.rawId, mediaSource: device.mediaSource});
devices.push(device);
}
break;
- case "video":
+ case "videoinput":
// Verify that if we got a camera, we haven't requested a screen share,
// or that if we requested a screen share we aren't getting a camera.
if (video && (device.mediaSource == "camera") != sharingScreen) {
let deviceObject = {name: device.name, deviceIndex: devices.length,
id: device.rawId, mediaSource: device.mediaSource};
if (device.scary)
deviceObject.scary = true;
videoDevices.push(deviceObject);
--- a/dom/media/MediaDevices.cpp
+++ b/dom/media/MediaDevices.cpp
@@ -108,20 +108,19 @@ public:
devices.AppendElement(device);
NS_IF_RELEASE(supportsArray[i]); // explicitly decrease refcount for rawptr
}
free(rawArray); // explicitly free memory from nsIVariant::GetAsArray
}
}
nsTArray<RefPtr<MediaDeviceInfo>> infos;
for (auto& device : devices) {
- nsString type;
- device->GetType(type);
- bool isVideo = type.EqualsLiteral("video");
- bool isAudio = type.EqualsLiteral("audio");
+ MediaDevice* dev = static_cast<MediaDevice*>(device.get());
+ bool isVideo = dev->mKind == dom::MediaDeviceKind::Videoinput;
+ bool isAudio = dev->mKind == dom::MediaDeviceKind::Audioinput;
if (isVideo || isAudio) {
MediaDeviceKind kind = isVideo ?
MediaDeviceKind::Videoinput : MediaDeviceKind::Audioinput;
nsString id;
nsString name;
device->GetId(id);
// Include name only if page currently has a gUM stream active or
// persistent permissions (audio or video) have been granted
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -5,16 +5,17 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "MediaManager.h"
#include "AllocationHandle.h"
#include "MediaStreamGraph.h"
#include "MediaTimer.h"
#include "mozilla/dom/MediaStreamTrack.h"
+#include "mozilla/dom/MediaDeviceInfo.h"
#include "MediaStreamListener.h"
#include "nsArray.h"
#include "nsContentUtils.h"
#include "nsGlobalWindow.h"
#include "nsHashPropertyBag.h"
#include "nsIEventTarget.h"
#include "nsIUUIDGenerator.h"
#include "nsIScriptGlobalObject.h"
@@ -818,23 +819,58 @@ private:
*/
NS_IMPL_ISUPPORTS(MediaDevice, nsIMediaDevice)
MediaDevice::MediaDevice(MediaEngineSource* aSource,
const nsString& aName,
const nsString& aID,
const nsString& aRawID)
: mSource(aSource)
- , mIsVideo(MediaEngineSource::IsVideo(mSource->GetMediaSource()))
+ , mKind((mSource && MediaEngineSource::IsVideo(mSource->GetMediaSource())) ?
+ dom::MediaDeviceKind::Videoinput : dom::MediaDeviceKind::Audioinput)
, mScary(mSource->GetScary())
- , mType(mIsVideo ? NS_LITERAL_STRING("video") : NS_LITERAL_STRING("audio"))
+ , mType(NS_ConvertUTF8toUTF16(dom::MediaDeviceKindValues::strings[uint32_t(mKind)].value))
, mName(aName)
, mID(aID)
, mRawID(aRawID)
{
+ MOZ_ASSERT(mSource);
+}
+
+MediaDevice::MediaDevice(const nsString& aName,
+ const dom::MediaDeviceKind aKind,
+ const nsString& aID,
+ const nsString& aRawID)
+ : mSource(nullptr)
+ , mKind(aKind)
+ , mScary(false)
+ , mType(NS_ConvertUTF8toUTF16(dom::MediaDeviceKindValues::strings[uint32_t(mKind)].value))
+ , mName(aName)
+ , mID(aID)
+ , mRawID(aRawID)
+{
+ // For now this ctor is used only for Audiooutput.
+ // It could be used for Audioinput and Videoinput
+ // when we do not instantiate a MediaEngineSource
+ // during EnumerateDevices.
+ MOZ_ASSERT(mKind == dom::MediaDeviceKind::Audiooutput);
+}
+
+MediaDevice::MediaDevice(const MediaDevice* aOther,
+ const nsString& aID,
+ const nsString& aRawID)
+ : mSource(aOther->mSource)
+ , mKind(aOther->mKind)
+ , mScary(aOther->mScary)
+ , mType(aOther->mType)
+ , mName(aOther->mName)
+ , mID(aID)
+ , mRawID(aRawID)
+{
+ MOZ_ASSERT(aOther);
}
/**
* Helper functions that implement the constraints algorithm from
* http://dev.w3.org/2011/webrtc/editor/getusermedia.html#methods-5
*/
/* static */ bool
@@ -880,16 +916,17 @@ MediaDevice::FitnessDistance(nsString aN
}
uint32_t
MediaDevice::GetBestFitnessDistance(
const nsTArray<const NormalizedConstraintSet*>& aConstraintSets,
bool aIsChrome)
{
MOZ_ASSERT(MediaManager::IsInMediaThread());
+ MOZ_ASSERT(mSource);
nsString mediaSource;
GetMediaSource(mediaSource);
// This code is reused for audio, where the mediaSource constraint does
// not currently have a function, but because it defaults to "camera" in
// webidl, we ignore it for audio here.
if (!mediaSource.EqualsASCII("microphone")) {
@@ -944,16 +981,17 @@ MediaDevice::GetScary(bool* aScary)
*aScary = mScary;
return NS_OK;
}
void
MediaDevice::GetSettings(dom::MediaTrackSettings& aOutSettings) const
{
MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(mSource);
mSource->GetSettings(aOutSettings);
}
// Threadsafe since mSource is const.
NS_IMETHODIMP
MediaDevice::GetMediaSource(nsAString& aMediaSource)
{
aMediaSource.Assign(NS_ConvertUTF8toUTF16(
@@ -963,91 +1001,100 @@ MediaDevice::GetMediaSource(nsAString& a
nsresult
MediaDevice::Allocate(const dom::MediaTrackConstraints &aConstraints,
const MediaEnginePrefs &aPrefs,
const ipc::PrincipalInfo& aPrincipalInfo,
const char** aOutBadConstraint)
{
MOZ_ASSERT(MediaManager::IsInMediaThread());
+ MOZ_ASSERT(mSource);
return mSource->Allocate(aConstraints,
aPrefs,
mID,
aPrincipalInfo,
getter_AddRefs(mAllocationHandle),
aOutBadConstraint);
}
nsresult
MediaDevice::SetTrack(const RefPtr<SourceMediaStream>& aStream,
TrackID aTrackID,
const PrincipalHandle& aPrincipalHandle)
{
MOZ_ASSERT(MediaManager::IsInMediaThread());
+ MOZ_ASSERT(mSource);
return mSource->SetTrack(mAllocationHandle, aStream, aTrackID, aPrincipalHandle);
}
nsresult
MediaDevice::Start()
{
MOZ_ASSERT(MediaManager::IsInMediaThread());
+ MOZ_ASSERT(mSource);
return mSource->Start(mAllocationHandle);
}
nsresult
MediaDevice::Reconfigure(const dom::MediaTrackConstraints &aConstraints,
const MediaEnginePrefs &aPrefs,
const char** aOutBadConstraint)
{
MOZ_ASSERT(MediaManager::IsInMediaThread());
+ MOZ_ASSERT(mSource);
return mSource->Reconfigure(mAllocationHandle,
aConstraints,
aPrefs,
mID,
aOutBadConstraint);
}
nsresult
MediaDevice::FocusOnSelectedSource()
{
MOZ_ASSERT(MediaManager::IsInMediaThread());
+ MOZ_ASSERT(mSource);
return mSource->FocusOnSelectedSource(mAllocationHandle);
}
nsresult
MediaDevice::Stop()
{
MOZ_ASSERT(MediaManager::IsInMediaThread());
+ MOZ_ASSERT(mSource);
return mSource->Stop(mAllocationHandle);
}
nsresult
MediaDevice::Deallocate()
{
MOZ_ASSERT(MediaManager::IsInMediaThread());
+ MOZ_ASSERT(mSource);
return mSource->Deallocate(mAllocationHandle);
}
void
MediaDevice::Pull(const RefPtr<SourceMediaStream>& aStream,
TrackID aTrackID,
StreamTime aDesiredTime,
const PrincipalHandle& aPrincipal)
{
// This is on the graph thread, but mAllocationHandle is safe since we never
// change it after it's been set, which is guaranteed to happen before
// registering the listener for pulls.
+ MOZ_ASSERT(mSource);
mSource->Pull(mAllocationHandle, aStream, aTrackID, aDesiredTime, aPrincipal);
}
dom::MediaSourceEnum
MediaDevice::GetMediaSource() const
{
// Threadsafe because mSource is const. GetMediaSource() might have other
// requirements.
+ MOZ_ASSERT(mSource);
return mSource->GetMediaSource();
}
static bool
IsOn(const OwningBooleanOrMediaTrackConstraints &aUnion) {
return !aUnion.IsBoolean() || aUnion.GetAsBoolean();
}
@@ -1559,19 +1606,21 @@ MediaManager::SelectSettings(
// Since the advanced part of the constraints algorithm needs to know when
// a candidate set is overconstrained (zero members), we must split up the
// list into videos and audios, and put it back together again at the end.
nsTArray<RefPtr<MediaDevice>> videos;
nsTArray<RefPtr<MediaDevice>> audios;
for (auto& source : sources) {
- if (source->mIsVideo) {
+ MOZ_ASSERT(source->mKind == dom::MediaDeviceKind::Videoinput ||
+ source->mKind == dom::MediaDeviceKind::Audioinput);
+ if (source->mKind == dom::MediaDeviceKind::Videoinput) {
videos.AppendElement(source);
- } else {
+ } else if (source->mKind == dom::MediaDeviceKind::Audioinput) {
audios.AppendElement(source);
}
}
sources.Clear();
const char* badConstraint = nullptr;
bool needVideo = IsOn(aConstraints.mVideo);
bool needAudio = IsOn(aConstraints.mAudio);
@@ -2946,20 +2995,17 @@ MediaManager::GetUserMedia(nsPIDOMWindow
MediaManager::AnonymizeDevices(SourceSet& aDevices, const nsACString& aOriginKey)
{
if (!aOriginKey.IsEmpty()) {
for (RefPtr<MediaDevice>& device : aDevices) {
nsString id;
device->GetId(id);
nsString rawId(id);
AnonymizeId(id, aOriginKey);
- device = new MediaDevice(device->mSource,
- device->mName,
- id,
- rawId);
+ device = new MediaDevice(device, id, rawId);
}
}
}
/* static */ nsresult
MediaManager::AnonymizeId(nsAString& aId, const nsACString& aOriginKey)
{
MOZ_ASSERT(NS_IsMainThread());
@@ -3640,26 +3686,27 @@ MediaManager::Observe(nsISupports* aSubj
nsCOMPtr<nsIMediaDevice> device;
array->QueryElementAt(i, NS_GET_IID(nsIMediaDevice),
getter_AddRefs(device));
MOZ_ASSERT(device); // shouldn't be returning anything else...
if (!device) {
continue;
}
- nsString type;
- device->GetType(type);
- if (type.EqualsLiteral("video")) {
+ // Casting here is safe because a MediaDevice is created
+ // only in Gecko side, JS can only query for an instance.
+ MediaDevice* dev = static_cast<MediaDevice*>(device.get());
+ if (dev->mKind == dom::MediaDeviceKind::Videoinput) {
if (!videoFound) {
- task->SetVideoDevice(static_cast<MediaDevice*>(device.get()));
+ task->SetVideoDevice(dev);
videoFound = true;
}
- } else if (type.EqualsLiteral("audio")) {
+ } else if (dev->mKind == dom::MediaDeviceKind::Audioinput) {
if (!audioFound) {
- task->SetAudioDevice(static_cast<MediaDevice*>(device.get()));
+ task->SetAudioDevice(dev);
audioFound = true;
}
} else {
NS_WARNING("Unknown device type in getUserMedia");
}
}
bool needVideo = IsOn(task->GetConstraints().mVideo);
bool needAudio = IsOn(task->GetConstraints().mAudio);
--- a/dom/media/MediaManager.h
+++ b/dom/media/MediaManager.h
@@ -44,16 +44,17 @@
#include "base/task.h"
namespace mozilla {
namespace dom {
struct MediaStreamConstraints;
struct MediaTrackConstraints;
struct MediaTrackConstraintSet;
enum class CallerType : uint32_t;
+enum class MediaDeviceKind : uint8_t;
} // namespace dom
namespace ipc {
class PrincipalInfo;
}
class AllocationHandle;
class GetUserMediaTask;
@@ -69,16 +70,25 @@ public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIMEDIADEVICE
explicit MediaDevice(MediaEngineSource* aSource,
const nsString& aName,
const nsString& aID,
const nsString& aRawID = NS_LITERAL_STRING(""));
+ explicit MediaDevice(const nsString& aName,
+ const dom::MediaDeviceKind aKind,
+ const nsString& aID,
+ const nsString& aRawID = NS_LITERAL_STRING(""));
+
+ explicit MediaDevice(const MediaDevice* aOther,
+ const nsString& aID,
+ const nsString& aRawID);
+
uint32_t GetBestFitnessDistance(
const nsTArray<const NormalizedConstraintSet*>& aConstraintSets,
bool aIsChrome);
nsresult Allocate(const dom::MediaTrackConstraints& aConstraints,
const MediaEnginePrefs& aPrefs,
const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
const char** aOutBadConstraint);
@@ -113,17 +123,17 @@ private:
const dom::ConstrainDOMStringParameters& aParams);
// Assigned on allocation on media thread, then read on the media thread and
// graph thread
RefPtr<AllocationHandle> mAllocationHandle;
public:
const RefPtr<MediaEngineSource> mSource;
- const bool mIsVideo;
+ const dom::MediaDeviceKind mKind;
const bool mScary;
const nsString mType;
const nsString mName;
const nsString mID;
const nsString mRawID;
};
typedef nsRefPtrHashtable<nsUint64HashKey, GetUserMediaWindowListener> WindowTable;
--- a/mobile/android/components/geckoview/GeckoViewPermission.js
+++ b/mobile/android/components/geckoview/GeckoViewPermission.js
@@ -112,29 +112,29 @@ GeckoViewPermission.prototype = {
type: device.type,
id: device.id,
rawId: device.rawId,
name: device.name,
mediaSource: device.mediaSource,
};
});
- if (constraints.video && !sources.some(source => source.type === "video")) {
+ if (constraints.video && !sources.some(source => source.type === "videoinput")) {
throw "no video source";
- } else if (constraints.audio && !sources.some(source => source.type === "audio")) {
+ } else if (constraints.audio && !sources.some(source => source.type === "audioinput")) {
throw "no audio source";
}
let dispatcher = GeckoViewUtils.getDispatcherForWindow(win);
let uri = win.document.documentURIObject;
return dispatcher.sendRequestForResult({
type: "GeckoView:MediaPermission",
uri: uri.displaySpec,
- video: constraints.video ? sources.filter(source => source.type === "video") : null,
- audio: constraints.audio ? sources.filter(source => source.type === "audio") : null,
+ video: constraints.video ? sources.filter(source => source.type === "videoinput") : null,
+ audio: constraints.audio ? sources.filter(source => source.type === "audioinput") : null,
}).then(response => {
if (!response) {
// Rejected.
denyRequest();
return;
}
let allowedDevices = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
if (constraints.video) {
--- a/mobile/android/modules/WebrtcUI.jsm
+++ b/mobile/android/modules/WebrtcUI.jsm
@@ -258,19 +258,19 @@ var WebrtcUI = {
},
showBlockMessage: function(aWindow, aDevices) {
let microphone = false;
let camera = false;
for (let device of aDevices) {
device = device.QueryInterface(Ci.nsIMediaDevice);
- if (device.type == "audio") {
+ if (device.type == "audioinput") {
microphone = true;
- } else if (device.type == "video") {
+ } else if (device.type == "videoinput") {
camera = true;
}
}
let message;
if (microphone && !camera) {
message = Strings.browser.GetStringFromName("getUserMedia.blockedMicrophoneAccess");
} else if (camera && !microphone) {
@@ -295,21 +295,21 @@ var WebrtcUI = {
prompt: function prompt(aContentWindow, aCallID, aAudioRequested,
aVideoRequested, aDevices) {
let audioDevices = [];
let videoDevices = [];
for (let device of aDevices) {
device = device.QueryInterface(Ci.nsIMediaDevice);
switch (device.type) {
- case "audio":
+ case "audioinput":
if (aAudioRequested)
audioDevices.push(device);
break;
- case "video":
+ case "videoinput":
if (aVideoRequested)
videoDevices.push(device);
break;
}
}
let requestType;
if (audioDevices.length && videoDevices.length)