Bug 934425 - Create a method in MediaManager to look up a given sink id. r?jib draft
authorAlex Chronopoulos <achronop@gmail.com>
Thu, 09 Aug 2018 14:59:09 +0300
changeset 827852 3baecc0d865d89533828c35291a91f6973c00211
parent 827851 53f5415c710a956abfeca0fcdd9c67dee3127d32
child 827853 44bfb340b80b9e45b9232ae68d731b8a189ce1a4
push id118601
push userachronop@gmail.com
push dateThu, 09 Aug 2018 14:17:09 +0000
reviewersjib
bugs934425
milestone63.0a1
Bug 934425 - Create a method in MediaManager to look up a given sink id. r?jib Implement a new method in MediaManager that enumerates audio output devices and looks up for a given sink id asynchronously. MozReview-Commit-ID: 9mhaH1Kxfbl
dom/media/MediaManager.cpp
dom/media/MediaManager.h
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -3366,30 +3366,81 @@ MediaManager::EnumerateDevices(nsPIDOMWi
     audioOutputType = MediaSinkEnum::Speaker;
   }
   RefPtr<PledgeMediaDeviceSet> p = EnumerateDevicesImpl(windowId,
                                                         MediaSourceEnum::Camera,
                                                         MediaSourceEnum::Microphone,
                                                         audioOutputType,
                                                         videoEnumerationType,
                                                         audioEnumerationType);
-  p->Then([onSuccess, windowListener, sourceListener](MediaDeviceSet*& aDevices) mutable {
+  p->Then([onSuccess, windowListener, sourceListener,
+           windowId = aWindow->WindowID()](MediaDeviceSet*& aDevices) mutable {
     UniquePtr<MediaDeviceSet> devices(aDevices); // grab result
     DebugOnly<bool> rv = windowListener->Remove(sourceListener);
     MOZ_ASSERT(rv);
     nsCOMPtr<nsIWritableVariant> array = MediaManager_ToJSArray(*devices);
     onSuccess->OnSuccess(array);
   }, [onFailure, windowListener, sourceListener](MediaStreamError*& reason) mutable {
     DebugOnly<bool> rv = windowListener->Remove(sourceListener);
     MOZ_ASSERT(rv);
     onFailure->OnError(reason);
   });
   return NS_OK;
 }
 
+RefPtr<SinkInfoPromise>
+MediaManager::GetSinkDevice(nsPIDOMWindowInner* aWindow,
+                            const nsString& aDeviceId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aWindow);
+
+  // We have to add the window id here because enumerate methods
+  // check for that and abort silently if it does not exist.
+  uint64_t windowId = aWindow->WindowID();
+  nsIPrincipal* principal = aWindow->GetExtantDoc()->NodePrincipal();
+  RefPtr<GetUserMediaWindowListener> windowListener = GetWindowListener(windowId);
+  if (windowListener) {
+    PrincipalHandle existingPrincipalHandle =
+      windowListener->GetPrincipalHandle();
+    MOZ_ASSERT(PrincipalHandleMatches(existingPrincipalHandle, principal));
+  } else {
+    windowListener = new GetUserMediaWindowListener(mMediaThread, windowId,
+                                                    MakePrincipalHandle(principal));
+    AddWindowID(windowId, windowListener);
+  }
+  // Create an inactive SourceListener to act as a placeholder, so the
+  // window listener doesn't clean itself up until we're done.
+  RefPtr<SourceListener> sourceListener = new SourceListener();
+  windowListener->Register(sourceListener);
+
+  RefPtr<SinkInfoPromise::Private> promise = new SinkInfoPromise::Private(__func__);
+  RefPtr<PledgeMediaDeviceSet> p =
+    EnumerateDevicesImpl(aWindow->WindowID(),
+                         MediaSourceEnum::Other,
+                         MediaSourceEnum::Other,
+                         MediaSinkEnum::Speaker,
+                         DeviceEnumerationType::Normal,
+                         DeviceEnumerationType::Normal);
+  p->Then([aDeviceId, promise](MediaDeviceSet*& aDevices) mutable {
+    UniquePtr<MediaDeviceSet> devices(aDevices);
+    for (RefPtr<MediaDevice>& device : *devices) {
+      if (device->mID.Equals(aDeviceId)) {
+        promise->Resolve(device->mSinkInfo, __func__);
+        return;
+      }
+    }
+    promise->Resolve(nullptr, __func__);
+  }, [promise](MediaStreamError*& reason) mutable {
+    promise->Reject(NS_ERROR_DOM_NOT_FOUND_ERR, __func__);
+  });
+
+  return promise.forget();
+}
+
 /*
  * GetUserMediaDevices - called by the UI-part of getUserMedia from chrome JS.
  */
 
 nsresult
 MediaManager::GetUserMediaDevices(nsPIDOMWindowInner* aWindow,
                                   const MediaStreamConstraints& aConstraints,
                                   dom::MozGetUserMediaDevicesSuccessCallback& aOnSuccess,
--- a/dom/media/MediaManager.h
+++ b/dom/media/MediaManager.h
@@ -133,16 +133,17 @@ public:
   const bool mScary;
   const nsString mType;
   const nsString mName;
   const nsString mID;
   const nsString mRawID;
 };
 
 typedef nsRefPtrHashtable<nsUint64HashKey, GetUserMediaWindowListener> WindowTable;
+typedef MozPromise<RefPtr<AudioDeviceInfo>, nsresult, true> SinkInfoPromise;
 
 class MediaManager final : public nsIMediaManagerService,
                            public nsIObserver
                           ,public DeviceChangeCallback
 {
   friend SourceListener;
 public:
   static already_AddRefed<MediaManager> GetInstance();
@@ -222,16 +223,20 @@ public:
                                const nsAString& aCallID = nsString());
 
   nsresult EnumerateDevices(nsPIDOMWindowInner* aWindow,
                             nsIGetUserMediaDevicesSuccessCallback* aOnSuccess,
                             nsIDOMGetUserMediaErrorCallback* aOnFailure,
                             dom::CallerType aCallerType);
 
   nsresult EnumerateDevices(nsPIDOMWindowInner* aWindow, dom::Promise& aPromise);
+
+  RefPtr<SinkInfoPromise> GetSinkDevice(nsPIDOMWindowInner* aWindow,
+                                        const nsString& aDeviceId);
+
   void OnNavigation(uint64_t aWindowID);
   bool IsActivelyCapturingOrHasAPermission(uint64_t aWindowId);
 
   MediaEnginePrefs mPrefs;
 
   typedef nsTArray<RefPtr<MediaDevice>> MediaDeviceSet;
 
   virtual int AddDeviceChangeCallback(DeviceChangeCallback* aCallback) override;