Bug 1152401 - Use MediaDevice in MediaEngine to allow enumeration of both sinks and sources. r?jib
MozReview-Commit-ID: 6ntA5YUFSnN
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -1489,56 +1489,51 @@ private:
ipc::PrincipalInfo mPrincipalInfo;
RefPtr<PeerIdentity> mPeerIdentity;
RefPtr<MediaManager> mManager; // get ref to this when creating the runnable
};
// Source getter returning full list
static void
-GetSources(MediaEngine *aEngine,
- uint64_t aWindowId,
- MediaSourceEnum aSrcType,
- nsTArray<RefPtr<MediaDevice>>& aResult,
- const char* aMediaDeviceName = nullptr)
+GetMediaDevices(MediaEngine *aEngine,
+ uint64_t aWindowId,
+ MediaSourceEnum aSrcType,
+ nsTArray<RefPtr<MediaDevice>>& aResult,
+ 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<MediaEngineSource>> sources;
- aEngine->EnumerateDevices(aWindowId, aSrcType, &sources);
+ nsTArray<RefPtr<MediaDevice>> devices;
+ aEngine->EnumerateDevices(aWindowId, aSrcType, &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) {
- for (auto& source : sources) {
- nsString deviceName = source->GetName();
- if (deviceName.EqualsASCII(aMediaDeviceName)) {
- aResult.AppendElement(MakeRefPtr<MediaDevice>(
- source,
- source->GetName(),
- NS_ConvertUTF8toUTF16(source->GetUUID())));
+ for (auto& device : devices) {
+ if (device->mName.EqualsASCII(aMediaDeviceName)) {
+ aResult.AppendElement(device);
LOG(("%s: found aMediaDeviceName=%s", __func__, aMediaDeviceName));
break;
}
}
} else {
- for (auto& source : sources) {
- aResult.AppendElement(MakeRefPtr<MediaDevice>(
- source,
- source->GetName(),
- NS_ConvertUTF8toUTF16(source->GetUUID())));
- LOG(("%s: appending device=%s", __func__,
- NS_ConvertUTF16toUTF8(source->GetName()).get()));
+ aResult = devices;
+ if (MOZ_LOG_TEST(GetMediaManagerLog(), mozilla::LogLevel::Debug)) {
+ for (auto& device : devices) {
+ LOG(("%s: appending device=%s", __func__,
+ NS_ConvertUTF16toUTF8(device->mName).get()));
+ }
}
}
}
// TODO: Remove once upgraded to GCC 4.8+ on linux. Bogus error on static func:
// error: 'this' was not captured for this lambda function
static auto& MediaManager_ToJSArray = MediaManager::ToJSArray;
@@ -1946,31 +1941,27 @@ MediaManager::EnumerateRawDevices(uint64
}
auto result = MakeUnique<SourceSet>();
if (hasVideo) {
SourceSet videos;
LOG(("EnumerateRawDevices Task: Getting video sources with %s backend",
aVideoEnumType == DeviceEnumerationType::Fake ? "fake" : "real"));
- GetSources(aVideoEnumType == DeviceEnumerationType::Fake ? fakeBackend : realBackend,
- aWindowId, aVideoType, videos, videoLoopDev.get());
- for (auto& source : videos) {
- result->AppendElement(source);
- }
+ GetMediaDevices(aVideoEnumType == DeviceEnumerationType::Fake ? fakeBackend : realBackend,
+ aWindowId, aVideoType, videos, videoLoopDev.get());
+ result->AppendElements(videos);
}
if (hasAudio) {
SourceSet audios;
LOG(("EnumerateRawDevices Task: Getting audio sources with %s backend",
aVideoEnumType == DeviceEnumerationType::Fake ? "fake" : "real"));
- GetSources(aAudioEnumType == DeviceEnumerationType::Fake ? fakeBackend : realBackend,
- aWindowId, aAudioType, audios, audioLoopDev.get());
- for (auto& source : audios) {
- result->AppendElement(source);
- }
+ GetMediaDevices(aAudioEnumType == DeviceEnumerationType::Fake ? fakeBackend : realBackend,
+ aWindowId, aAudioType, audios, audioLoopDev.get());
+ result->AppendElements(audios);
}
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) {
--- a/dom/media/webrtc/MediaEngine.h
+++ b/dom/media/webrtc/MediaEngine.h
@@ -46,17 +46,17 @@ public:
}
/**
* Populate an array of sources of the requested type in the nsTArray.
* Also include devices that are currently unavailable.
*/
virtual void EnumerateDevices(uint64_t aWindowId,
dom::MediaSourceEnum,
- nsTArray<RefPtr<MediaEngineSource>>*) = 0;
+ nsTArray<RefPtr<MediaDevice>>*) = 0;
virtual void ReleaseResourcesForWindow(uint64_t aWindowId) = 0;
virtual void Shutdown() = 0;
virtual void SetFakeDeviceChangeEvents() {}
protected:
virtual ~MediaEngine() {}
--- a/dom/media/webrtc/MediaEngineDefault.cpp
+++ b/dom/media/webrtc/MediaEngineDefault.cpp
@@ -549,49 +549,58 @@ MediaEngineDefaultAudioSource::Pull(cons
mLastNotify += delta;
AppendToSegment(segment, delta, aPrincipalHandle);
aStream->AppendToTrack(aTrackID, &segment);
}
void
MediaEngineDefault::EnumerateDevices(uint64_t aWindowId,
dom::MediaSourceEnum aMediaSource,
- nsTArray<RefPtr<MediaEngineSource>>* aSources)
+ nsTArray<RefPtr<MediaDevice>>* aDevices)
{
AssertIsOnOwningThread();
switch (aMediaSource) {
case dom::MediaSourceEnum::Camera: {
// Only supports camera video sources. See Bug 1038241.
// We once had code here to find a VideoSource with the same settings and
// re-use that. This is no longer possible since the resolution gets set
// in Allocate().
nsTArray<RefPtr<MediaEngineSource>>*
devicesForThisWindow = mVSources.LookupOrAdd(aWindowId);
auto newSource = MakeRefPtr<MediaEngineDefaultVideoSource>();
devicesForThisWindow->AppendElement(newSource);
- aSources->AppendElement(newSource);
+ aDevices->AppendElement(MakeRefPtr<MediaDevice>(
+ newSource,
+ newSource->GetName(),
+ NS_ConvertUTF8toUTF16(newSource->GetUUID())));
return;
}
case dom::MediaSourceEnum::Microphone: {
nsTArray<RefPtr<MediaEngineDefaultAudioSource>>*
devicesForThisWindow = mASources.LookupOrAdd(aWindowId);
for (const RefPtr<MediaEngineDefaultAudioSource>& source : *devicesForThisWindow) {
if (source->IsAvailable()) {
- aSources->AppendElement(source);
+ aDevices->AppendElement(MakeRefPtr<MediaDevice>(
+ source,
+ source->GetName(),
+ NS_ConvertUTF8toUTF16(source->GetUUID())));
}
}
- if (aSources->IsEmpty()) {
+ if (aDevices->IsEmpty()) {
// All streams are currently busy, just make a new one.
auto newSource = MakeRefPtr<MediaEngineDefaultAudioSource>();
devicesForThisWindow->AppendElement(newSource);
- aSources->AppendElement(newSource);
+ aDevices->AppendElement(MakeRefPtr<MediaDevice>(
+ newSource,
+ newSource->GetName(),
+ NS_ConvertUTF8toUTF16(newSource->GetUUID())));
}
return;
}
default:
MOZ_ASSERT_UNREACHABLE("Unsupported source type");
return;
}
}
--- a/dom/media/webrtc/MediaEngineDefault.h
+++ b/dom/media/webrtc/MediaEngineDefault.h
@@ -184,17 +184,17 @@ protected:
class MediaEngineDefault : public MediaEngine
{
public:
MediaEngineDefault() = default;
void EnumerateDevices(uint64_t aWindowId,
dom::MediaSourceEnum,
- nsTArray<RefPtr<MediaEngineSource>>*) override;
+ nsTArray<RefPtr<MediaDevice>>*) override;
void Shutdown() override;
void ReleaseResourcesForWindow(uint64_t aWindowId) override;
private:
~MediaEngineDefault() = default;
// WindowID -> Array of devices.
nsClassHashtable<nsUint64HashKey,
--- a/dom/media/webrtc/MediaEngineWebRTC.cpp
+++ b/dom/media/webrtc/MediaEngineWebRTC.cpp
@@ -120,17 +120,17 @@ MediaEngineWebRTC::SetFakeDeviceChangeEv
{
camera::GetChildAndCall(
&camera::CamerasChild::SetFakeDeviceChangeEvents);
}
void
MediaEngineWebRTC::EnumerateVideoDevices(uint64_t aWindowId,
dom::MediaSourceEnum aMediaSource,
- nsTArray<RefPtr<MediaEngineSource> >* aSources)
+ nsTArray<RefPtr<MediaDevice> >* aDevices)
{
mMutex.AssertCurrentThreadOwns();
mozilla::camera::CaptureEngine capEngine = mozilla::camera::InvalidEngine;
bool scaryKind = false; // flag sources with cross-origin exploit potential
switch (aMediaSource) {
@@ -223,33 +223,39 @@ MediaEngineWebRTC::EnumerateVideoDevices
nsRefPtrHashtable<nsStringHashKey, MediaEngineSource>*
devicesForThisWindow = mVideoSources.LookupOrAdd(aWindowId);
if (devicesForThisWindow->Get(uuid, getter_AddRefs(vSource)) &&
vSource->RequiresSharing()) {
// We've already seen this shared device, just refresh and append.
static_cast<MediaEngineRemoteVideoSource*>(vSource.get())->Refresh(i);
- aSources->AppendElement(vSource.get());
} else {
vSource = new MediaEngineRemoteVideoSource(i, capEngine, aMediaSource,
scaryKind || scarySource);
devicesForThisWindow->Put(uuid, vSource);
- aSources->AppendElement(vSource);
}
+ aDevices->AppendElement(MakeRefPtr<MediaDevice>(
+ vSource,
+ vSource->GetName(),
+ NS_ConvertUTF8toUTF16(vSource->GetUUID())));
}
if (mHasTabVideoSource || dom::MediaSourceEnum::Browser == aMediaSource) {
- aSources->AppendElement(new MediaEngineTabVideoSource());
+ RefPtr<MediaEngineSource> tabVideoSource = new MediaEngineTabVideoSource();
+ aDevices->AppendElement(MakeRefPtr<MediaDevice>(
+ tabVideoSource,
+ tabVideoSource->GetName(),
+ NS_ConvertUTF8toUTF16(tabVideoSource->GetUUID())));
}
}
void
MediaEngineWebRTC::EnumerateMicrophoneDevices(uint64_t aWindowId,
- nsTArray<RefPtr<MediaEngineSource> >* aSources)
+ nsTArray<RefPtr<MediaDevice> >* aDevices)
{
mMutex.AssertCurrentThreadOwns();
if (!mAudioInput) {
if (!SupportsDuplex()) {
return;
}
mAudioInput = new mozilla::AudioInputCubeb();
@@ -279,53 +285,57 @@ MediaEngineWebRTC::EnumerateMicrophoneDe
}
if (uniqueId[0] == '\0') {
// Mac and Linux don't set uniqueId!
strcpy(uniqueId, deviceName); // safe given assert and initialization/error-check
}
- RefPtr<MediaEngineSource> aSource;
+ RefPtr<MediaEngineSource> micSource;
NS_ConvertUTF8toUTF16 uuid(uniqueId);
nsRefPtrHashtable<nsStringHashKey, MediaEngineSource>*
devicesForThisWindow = mAudioSources.LookupOrAdd(aWindowId);
- if (devicesForThisWindow->Get(uuid, getter_AddRefs(aSource)) &&
- aSource->RequiresSharing()) {
- // We've already seen this device, just append.
- aSources->AppendElement(aSource.get());
- } else {
- aSource = new MediaEngineWebRTCMicrophoneSource(
+ bool alreadySeenThisDeviceBefore = devicesForThisWindow->Get(uuid, getter_AddRefs(micSource)) &&
+ micSource->RequiresSharing();
+ if (!alreadySeenThisDeviceBefore) {
+ micSource = new MediaEngineWebRTCMicrophoneSource(
new mozilla::AudioInputCubeb(i),
i, deviceName, uniqueId,
mDelayAgnostic, mExtendedFilter);
- devicesForThisWindow->Put(uuid, aSource);
- aSources->AppendElement(aSource);
+ devicesForThisWindow->Put(uuid, micSource);
}
+ aDevices->AppendElement(MakeRefPtr<MediaDevice>(
+ micSource,
+ micSource->GetName(),
+ NS_ConvertUTF8toUTF16(micSource->GetUUID())));
}
}
void
MediaEngineWebRTC::EnumerateDevices(uint64_t aWindowId,
dom::MediaSourceEnum aMediaSource,
- nsTArray<RefPtr<MediaEngineSource> >* aSources)
+ nsTArray<RefPtr<MediaDevice> >* aDevices)
{
// We spawn threads to handle gUM runnables, so we must protect the member vars
MutexAutoLock lock(mMutex);
if (MediaEngineSource::IsVideo(aMediaSource)) {
- EnumerateVideoDevices(aWindowId, aMediaSource, aSources);
+ EnumerateVideoDevices(aWindowId, aMediaSource, aDevices);
} else if (aMediaSource == dom::MediaSourceEnum::AudioCapture) {
RefPtr<MediaEngineWebRTCAudioCaptureSource> audioCaptureSource =
new MediaEngineWebRTCAudioCaptureSource(nullptr);
- aSources->AppendElement(audioCaptureSource);
+ aDevices->AppendElement(MakeRefPtr<MediaDevice>(
+ audioCaptureSource,
+ audioCaptureSource->GetName(),
+ NS_ConvertUTF8toUTF16(audioCaptureSource->GetUUID())));
} else {
MOZ_ASSERT(aMediaSource == dom::MediaSourceEnum::Microphone);
- EnumerateMicrophoneDevices(aWindowId, aSources);
+ EnumerateMicrophoneDevices(aWindowId, aDevices);
}
}
bool
MediaEngineWebRTC::SupportsDuplex()
{
return mFullDuplex;
}
--- a/dom/media/webrtc/MediaEngineWebRTC.h
+++ b/dom/media/webrtc/MediaEngineWebRTC.h
@@ -630,25 +630,25 @@ public:
// before invoking Shutdown on this class.
void Shutdown() override;
// Returns whether the host supports duplex audio stream.
bool SupportsDuplex();
void EnumerateDevices(uint64_t aWindowId,
dom::MediaSourceEnum,
- nsTArray<RefPtr<MediaEngineSource>>*) override;
+ nsTArray<RefPtr<MediaDevice>>*) override;
void ReleaseResourcesForWindow(uint64_t aWindowId) override;
private:
~MediaEngineWebRTC() = default;
void EnumerateVideoDevices(uint64_t aWindowId,
dom::MediaSourceEnum,
- nsTArray<RefPtr<MediaEngineSource>>*);
+ nsTArray<RefPtr<MediaDevice>>*);
void EnumerateMicrophoneDevices(uint64_t aWindowId,
- nsTArray<RefPtr<MediaEngineSource>>*);
+ nsTArray<RefPtr<MediaDevice>>*);
nsCOMPtr<nsIThread> mThread;
// gUM runnables can e.g. Enumerate from multiple threads
Mutex mMutex;
RefPtr<mozilla::AudioInput> mAudioInput;
bool mFullDuplex;
bool mDelayAgnostic;