--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -1548,17 +1548,17 @@ GetMediaDevices(MediaEngine *aEngine,
const char* aMediaDeviceName = nullptr)
{
MOZ_ASSERT(MediaManager::IsInMediaThread());
LOG(("%s: aEngine=%p, aWindowId=%" PRIu64 ", aSrcType=%" PRIu8 ", aMediaDeviceName=%s",
__func__, aEngine, aWindowId, static_cast<uint8_t>(aSrcType),
aMediaDeviceName ? aMediaDeviceName : "null"));
nsTArray<RefPtr<MediaDevice>> devices;
- aEngine->EnumerateDevices(aWindowId, aSrcType, &devices);
+ aEngine->EnumerateDevices(aWindowId, aSrcType, MediaSinkEnum::Other, &devices);
/*
* We're allowing multiple tabs to access the same camera for parity
* with Chrome. See bug 811757 for some of the issues surrounding
* this decision. To disallow, we'd filter by IsAvailable() as we used
* to.
*/
if (aMediaDeviceName && *aMediaDeviceName) {
@@ -1916,102 +1916,117 @@ private:
/**
* EnumerateRawDevices - Enumerate a list of audio & video devices that
* satisfy passed-in constraints. List contains raw id's.
*/
already_AddRefed<MediaManager::PledgeSourceSet>
MediaManager::EnumerateRawDevices(uint64_t aWindowId,
- MediaSourceEnum aVideoType,
- MediaSourceEnum aAudioType,
- DeviceEnumerationType aVideoEnumType /* = DeviceEnumerationType::Normal */,
- DeviceEnumerationType aAudioEnumType /* = DeviceEnumerationType::Normal */)
+ MediaSourceEnum aVideoInputType,
+ MediaSourceEnum aAudioInputType,
+ MediaSinkEnum aAudioOutputType,
+ DeviceEnumerationType aVideoInputEnumType /* = DeviceEnumerationType::Normal */,
+ DeviceEnumerationType aAudioInputEnumType /* = DeviceEnumerationType::Normal */)
{
MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(aVideoType != MediaSourceEnum::Other ||
- aAudioType != MediaSourceEnum::Other);
+ MOZ_ASSERT(aVideoInputType != MediaSourceEnum::Other ||
+ aAudioInputType != MediaSourceEnum::Other ||
+ aAudioOutputType != MediaSinkEnum::Other);
// Since the enums can take one of several values, the following asserts rely
- // on short circuting behavior. E.g. aVideoEnumType != Fake will be true if
+ // on short circuting behavior. E.g. aVideoInputEnumType != Fake will be true if
// the requested device is not fake and thus the assert will pass. However,
- // if the device is fake, aVideoType == MediaSourceEnum::Camera will be
+ // if the device is fake, aVideoInputType == MediaSourceEnum::Camera will be
// checked as well, ensuring that fake devices are of the camera type.
- MOZ_ASSERT(aVideoEnumType != DeviceEnumerationType::Fake ||
- aVideoType == MediaSourceEnum::Camera,
+ MOZ_ASSERT(aVideoInputEnumType != DeviceEnumerationType::Fake ||
+ aVideoInputType == MediaSourceEnum::Camera,
"If fake cams are requested video type should be camera!");
- MOZ_ASSERT(aVideoEnumType != DeviceEnumerationType::Loopback ||
- aVideoType == MediaSourceEnum::Camera,
+ MOZ_ASSERT(aVideoInputEnumType != DeviceEnumerationType::Loopback ||
+ aVideoInputType == MediaSourceEnum::Camera,
"If loopback video is requested video type should be camera!");
- MOZ_ASSERT(aAudioEnumType != DeviceEnumerationType::Fake ||
- aAudioType == MediaSourceEnum::Microphone,
+ MOZ_ASSERT(aAudioInputEnumType != DeviceEnumerationType::Fake ||
+ aAudioInputType == MediaSourceEnum::Microphone,
"If fake mics are requested audio type should be microphone!");
- MOZ_ASSERT(aAudioEnumType != DeviceEnumerationType::Loopback ||
- aAudioType == MediaSourceEnum::Microphone,
+ MOZ_ASSERT(aAudioInputEnumType != DeviceEnumerationType::Loopback ||
+ aAudioInputType == MediaSourceEnum::Microphone,
"If loopback audio is requested audio type should be microphone!");
- LOG(("%s: aWindowId=%" PRIu64 ", aVideoType=%" PRIu8 ", aAudioType=%" PRIu8
- ", aVideoEnumType=%" PRIu8 ", aAudioEnumType=%" PRIu8,
+ LOG(("%s: aWindowId=%" PRIu64 ", aVideoInputType=%" PRIu8 ", aAudioInputType=%" PRIu8
+ ", aVideoInputEnumType=%" PRIu8 ", aAudioInputEnumType=%" PRIu8,
__func__, aWindowId,
- static_cast<uint8_t>(aVideoType), static_cast<uint8_t>(aAudioType),
- static_cast<uint8_t>(aVideoEnumType), static_cast<uint8_t>(aAudioEnumType)));
+ static_cast<uint8_t>(aVideoInputType), static_cast<uint8_t>(aAudioInputType),
+ static_cast<uint8_t>(aVideoInputEnumType), static_cast<uint8_t>(aAudioInputEnumType)));
RefPtr<PledgeSourceSet> p = new PledgeSourceSet();
uint32_t id = mOutstandingPledges.Append(*p);
- bool hasVideo = aVideoType != MediaSourceEnum::Other;
- bool hasAudio = aAudioType != MediaSourceEnum::Other;
-
- // True of at least one of video or audio is a fake device
- bool fakeDeviceRequested = (aVideoEnumType == DeviceEnumerationType::Fake && hasVideo) ||
- (aAudioEnumType == DeviceEnumerationType::Fake && hasAudio);
- // True if at least one of video or audio is a real device
- bool realDeviceRequested = (aVideoEnumType != DeviceEnumerationType::Fake && hasVideo) ||
- (aAudioEnumType != DeviceEnumerationType::Fake && hasAudio);
+ bool hasVideo = aVideoInputType != MediaSourceEnum::Other;
+ bool hasAudio = aAudioInputType != MediaSourceEnum::Other;
+ bool hasAudioOutput = aAudioOutputType == MediaSinkEnum::Speaker;
+
+ // True of at least one of video input or audio input is a fake device
+ bool fakeDeviceRequested = (aVideoInputEnumType == DeviceEnumerationType::Fake && hasVideo) ||
+ (aAudioInputEnumType == DeviceEnumerationType::Fake && hasAudio);
+ // True if at least one of video input or audio input is a real device
+ // or there is audio output.
+ bool realDeviceRequested = (aVideoInputEnumType != DeviceEnumerationType::Fake && hasVideo) ||
+ (aAudioInputEnumType != DeviceEnumerationType::Fake && hasAudio) ||
+ hasAudioOutput;
nsAutoCString videoLoopDev, audioLoopDev;
- if (hasVideo && aVideoEnumType == DeviceEnumerationType::Loopback) {
+ if (hasVideo && aVideoInputEnumType == DeviceEnumerationType::Loopback) {
Preferences::GetCString("media.video_loopback_dev", videoLoopDev);
}
- if (hasAudio && aAudioEnumType == DeviceEnumerationType::Loopback) {
+ if (hasAudio && aAudioInputEnumType == DeviceEnumerationType::Loopback) {
Preferences::GetCString("media.audio_loopback_dev", audioLoopDev);
}
- RefPtr<Runnable> task = NewTaskFrom([id, aWindowId, aVideoType, aAudioType,
- aVideoEnumType, aAudioEnumType,
+ RefPtr<Runnable> task = NewTaskFrom([id, aWindowId, aVideoInputType, aAudioInputType,
+ aVideoInputEnumType, aAudioInputEnumType,
videoLoopDev, audioLoopDev,
- hasVideo, hasAudio, fakeDeviceRequested,
- realDeviceRequested]() {
+ hasVideo, hasAudio, hasAudioOutput,
+ fakeDeviceRequested, realDeviceRequested]() {
// Only enumerate what's asked for, and only fake cams and mics.
RefPtr<MediaEngine> fakeBackend, realBackend;
if (fakeDeviceRequested) {
fakeBackend = new MediaEngineDefault();
}
if (realDeviceRequested) {
MediaManager* manager = MediaManager::GetIfExists();
MOZ_RELEASE_ASSERT(manager); // Must exist while media thread is alive
realBackend = manager->GetBackend(aWindowId);
}
auto result = MakeUnique<SourceSet>();
if (hasVideo) {
SourceSet videos;
LOG(("EnumerateRawDevices Task: Getting video sources with %s backend",
- aVideoEnumType == DeviceEnumerationType::Fake ? "fake" : "real"));
- GetMediaDevices(aVideoEnumType == DeviceEnumerationType::Fake ? fakeBackend : realBackend,
- aWindowId, aVideoType, videos, videoLoopDev.get());
+ aVideoInputEnumType == DeviceEnumerationType::Fake ? "fake" : "real"));
+ GetMediaDevices(aVideoInputEnumType == DeviceEnumerationType::Fake ? fakeBackend : realBackend,
+ aWindowId, aVideoInputType, videos, videoLoopDev.get());
result->AppendElements(videos);
}
if (hasAudio) {
SourceSet audios;
LOG(("EnumerateRawDevices Task: Getting audio sources with %s backend",
- aVideoEnumType == DeviceEnumerationType::Fake ? "fake" : "real"));
- GetMediaDevices(aAudioEnumType == DeviceEnumerationType::Fake ? fakeBackend : realBackend,
- aWindowId, aAudioType, audios, audioLoopDev.get());
+ aAudioInputEnumType == DeviceEnumerationType::Fake ? "fake" : "real"));
+ GetMediaDevices(aAudioInputEnumType == DeviceEnumerationType::Fake ? fakeBackend : realBackend,
+ aWindowId, aAudioInputType, audios, audioLoopDev.get());
result->AppendElements(audios);
}
+ if (hasAudioOutput) {
+ SourceSet outputs;
+ MOZ_ASSERT(realBackend);
+ realBackend->EnumerateDevices(aWindowId,
+ MediaSourceEnum::Other,
+ MediaSinkEnum::Speaker,
+ &outputs);
+ result->AppendElements(outputs);
+ }
+
NS_DispatchToMainThread(NewRunnableFrom([id, result = std::move(result)]() mutable {
MediaManager* mgr = MediaManager::GetIfExists();
if (!mgr) {
return NS_OK;
}
RefPtr<PledgeSourceSet> p = mgr->mOutstandingPledges.Remove(id);
if (p) {
p->Resolve(result.release());
@@ -2020,19 +2035,19 @@ MediaManager::EnumerateRawDevices(uint64
}));
});
if (realDeviceRequested &&
Preferences::GetBool("media.navigator.permission.device", false)) {
// Need to ask permission to retrieve list of all devices;
// notify frontend observer and wait for callback notification to post task.
const char16_t* const type =
- (aVideoType != MediaSourceEnum::Camera) ? u"audio" :
- (aAudioType != MediaSourceEnum::Microphone) ? u"video" :
- u"all";
+ (aVideoInputType != MediaSourceEnum::Camera) ? u"audio" :
+ (aAudioInputType != MediaSourceEnum::Microphone) ? u"video" :
+ u"all";
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
obs->NotifyObservers(static_cast<nsIRunnable*>(task),
"getUserMedia:ask-device-permission",
type);
} else {
// Don't need to ask permission to retrieve list of all devices;
// post the retrieval task immediately.
MediaManager::PostTask(task.forget());
@@ -2341,22 +2356,23 @@ void MediaManager::OnDeviceChange() {
RefPtr<MediaManager> self(this);
NS_DispatchToMainThread(media::NewRunnableFrom([self]() mutable {
MOZ_ASSERT(NS_IsMainThread());
if (sHasShutdown) {
return NS_OK;
}
self->DeviceChangeCallback::OnDeviceChange();
- // On some Windows machine, if we call EnumertaeRawDevices immediately after receiving
+ // On some Windows machine, if we call EnumerateRawDevices immediately after receiving
// devicechange event, sometimes we would get outdated devices list.
PR_Sleep(PR_MillisecondsToInterval(100));
RefPtr<PledgeSourceSet> p = self->EnumerateRawDevices(0,
MediaSourceEnum::Camera,
- MediaSourceEnum::Microphone);
+ MediaSourceEnum::Microphone,
+ MediaSinkEnum::Speaker);
p->Then([self](SourceSet*& aDevices) mutable {
UniquePtr<SourceSet> devices(aDevices);
nsTArray<nsString> deviceIDs;
for (auto& device : *devices) {
nsString id;
device->GetId(id);
id.ReplaceSubstring(NS_LITERAL_STRING("default: "), NS_LITERAL_STRING(""));
@@ -2854,18 +2870,20 @@ MediaManager::GetUserMedia(nsPIDOMWindow
", videoType=%" PRIu8 ", audioType=%" PRIu8
", videoEnumerationType=%" PRIu8 ", audioEnumerationType=%" PRIu8
", askPermission=%s",
__func__, windowID,
static_cast<uint8_t>(videoType), static_cast<uint8_t>(audioType),
static_cast<uint8_t>(videoEnumerationType), static_cast<uint8_t>(audioEnumerationType),
askPermission ? "true" : "false"));
- RefPtr<PledgeSourceSet> p = EnumerateDevicesImpl(windowID, videoType,
+ RefPtr<PledgeSourceSet> p = EnumerateDevicesImpl(windowID,
+ videoType,
audioType,
+ MediaSinkEnum::Other,
videoEnumerationType,
audioEnumerationType);
RefPtr<MediaManager> self = this;
p->Then([self, onSuccess, onFailure, windowID, c, windowListener,
sourceListener, askPermission, prefs, isHTTPS, isHandlingUserInput,
callID, principalInfo, isChrome, resistFingerprinting](SourceSet*& aDevices) mutable {
LOG(("GetUserMedia: post enumeration pledge success callback starting"));
// grab result
@@ -3073,28 +3091,29 @@ MediaManager::ToJSArray(SourceSet& aDevi
} else {
var->SetAsEmptyArray(); // because SetAsArray() fails on zero length arrays.
}
return var.forget();
}
already_AddRefed<MediaManager::PledgeSourceSet>
MediaManager::EnumerateDevicesImpl(uint64_t aWindowId,
- MediaSourceEnum aVideoType,
- MediaSourceEnum aAudioType,
- DeviceEnumerationType aVideoEnumType /* = DeviceEnumerationType::Normal */,
- DeviceEnumerationType aAudioEnumType /* = DeviceEnumerationType::Normal */)
+ MediaSourceEnum aVideoInputType,
+ MediaSourceEnum aAudioInputType,
+ MediaSinkEnum aAudioOutputType,
+ DeviceEnumerationType aVideoInputEnumType,
+ DeviceEnumerationType aAudioInputEnumType)
{
MOZ_ASSERT(NS_IsMainThread());
- LOG(("%s: aWindowId=%" PRIu64 ", aVideoType=%" PRIu8 ", aAudioType=%" PRIu8
- ", aVideoEnumType=%" PRIu8 ", aAudioEnumType=%" PRIu8,
+ LOG(("%s: aWindowId=%" PRIu64 ", aVideoInputType=%" PRIu8 ", aAudioInputType=%" PRIu8
+ ", aVideoInputEnumType=%" PRIu8 ", aAudioInputEnumType=%" PRIu8,
__func__, aWindowId,
- static_cast<uint8_t>(aVideoType), static_cast<uint8_t>(aAudioType),
- static_cast<uint8_t>(aVideoEnumType), static_cast<uint8_t>(aAudioEnumType)));
+ static_cast<uint8_t>(aVideoInputType), static_cast<uint8_t>(aAudioInputType),
+ static_cast<uint8_t>(aVideoInputEnumType), static_cast<uint8_t>(aAudioInputEnumType)));
nsPIDOMWindowInner* window =
nsGlobalWindowInner::GetInnerWindowWithId(aWindowId)->AsInner();
// This function returns a pledge, a promise-like object with the future result
RefPtr<PledgeSourceSet> pledge = new PledgeSourceSet();
uint32_t id = mOutstandingPledges.Append(*pledge);
// To get a device list anonymized for a particular origin, we must:
@@ -3119,50 +3138,51 @@ MediaManager::EnumerateDevicesImpl(uint6
bool persist = IsActivelyCapturingOrHasAPermission(aWindowId);
// GetPrincipalKey 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 GetPrincipalKey resolves. Needed variables are "captured"
// (passed by value) safely into the lambda.
RefPtr<Pledge<nsCString>> p = media::GetPrincipalKey(principalInfo, persist);
- p->Then([id, aWindowId, aVideoType, aAudioType,
- aVideoEnumType, aAudioEnumType](const nsCString& aOriginKey) mutable {
+ p->Then([id, aWindowId, aVideoInputType, aAudioInputType,
+ aVideoInputEnumType, aAudioInputEnumType, aAudioOutputType](const nsCString& aOriginKey) mutable {
MOZ_ASSERT(NS_IsMainThread());
MediaManager* mgr = MediaManager::GetIfExists();
if (!mgr) {
return;
}
RefPtr<PledgeSourceSet> p = mgr->EnumerateRawDevices(aWindowId,
- aVideoType,
- aAudioType,
- aVideoEnumType,
- aAudioEnumType);
+ aVideoInputType,
+ aAudioInputType,
+ aAudioOutputType,
+ aVideoInputEnumType,
+ aAudioInputEnumType);
p->Then([id,
aWindowId,
aOriginKey,
- aVideoEnumType,
- aAudioEnumType,
- aVideoType,
- aAudioType](SourceSet*& aDevices) mutable {
+ aVideoInputEnumType,
+ aAudioInputEnumType,
+ aVideoInputType,
+ aAudioInputType](SourceSet*& aDevices) mutable {
UniquePtr<SourceSet> devices(aDevices); // secondary result
// Only run if window is still on our active list.
MediaManager* mgr = MediaManager::GetIfExists();
if (!mgr) {
return NS_OK;
}
// If we fetched any real cameras or mics, remove the "default" part of
// their IDs.
- if (aVideoType == MediaSourceEnum::Camera &&
- aAudioType == MediaSourceEnum::Microphone &&
- (aVideoEnumType != DeviceEnumerationType::Fake ||
- aAudioEnumType != DeviceEnumerationType::Fake)) {
+ if (aVideoInputType == MediaSourceEnum::Camera &&
+ aAudioInputType == MediaSourceEnum::Microphone &&
+ (aVideoInputEnumType != DeviceEnumerationType::Fake ||
+ aAudioInputEnumType != DeviceEnumerationType::Fake)) {
mgr->mDeviceIDs.Clear();
for (auto& device : *devices) {
nsString id;
device->GetId(id);
id.ReplaceSubstring(NS_LITERAL_STRING("default: "), NS_LITERAL_STRING(""));
if (!mgr->mDeviceIDs.Contains(id)) {
mgr->mDeviceIDs.AppendElement(id);
}
@@ -3240,16 +3260,17 @@ MediaManager::EnumerateDevices(nsPIDOMWi
} else if (wantFakes) {
audioEnumerationType = DeviceEnumerationType::Fake;
}
}
RefPtr<PledgeSourceSet> p = EnumerateDevicesImpl(windowId,
MediaSourceEnum::Camera,
MediaSourceEnum::Microphone,
+ MediaSinkEnum::Speaker,
videoEnumerationType,
audioEnumerationType);
p->Then([onSuccess, windowListener, sourceListener](SourceSet*& aDevices) mutable {
UniquePtr<SourceSet> devices(aDevices); // grab result
DebugOnly<bool> rv = windowListener->Remove(sourceListener);
MOZ_ASSERT(rv);
nsCOMPtr<nsIWritableVariant> array = MediaManager_ToJSArray(*devices);
onSuccess->OnSuccess(array);