Bug 1152401 - Use MediaDevice in MediaEngine to allow enumeration of both sinks and sources. r?jib draft
authorAlex Chronopoulos <achronop@gmail.com>
Wed, 11 Jul 2018 08:59:13 +0200
changeset 816401 ee8352e7c20bdad79aa91787679ceef75c434504
parent 816400 5270d0725d8c334ee45ce23cd78c67747a346f27
child 816402 9007e9ef76df9c1d9d017d8e005c755405af6255
child 818646 ceb39c8f5154e00896a80df9e19493daf4fe3271
push id115834
push userachronop@gmail.com
push dateWed, 11 Jul 2018 07:00:12 +0000
reviewersjib
bugs1152401
milestone63.0a1
Bug 1152401 - Use MediaDevice in MediaEngine to allow enumeration of both sinks and sources. r?jib MozReview-Commit-ID: 6ntA5YUFSnN
dom/media/MediaManager.cpp
dom/media/webrtc/MediaEngine.h
dom/media/webrtc/MediaEngineDefault.cpp
dom/media/webrtc/MediaEngineDefault.h
dom/media/webrtc/MediaEngineWebRTC.cpp
dom/media/webrtc/MediaEngineWebRTC.h
--- 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;