Bug 934425 - Create a method in MediaManager to look up a given sink id. r=jib
authorAlex Chronopoulos <achronop@gmail.com>
Fri, 12 Oct 2018 08:44:23 +0000
changeset 440839 ae5bc4f62937a66d6201ea83b4dc22c5a4744fc8
parent 440838 7640652718bde21308f808970d0cc0662916bfe7
child 440840 923d8e25777eb5cfb88269eeac04addbcb88a419
push id34837
push userncsoregi@mozilla.com
push dateFri, 12 Oct 2018 16:56:54 +0000
treeherdermozilla-central@7fd59dc00149 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjib
bugs934425
milestone64.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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. Differential Revision: https://phabricator.services.mozilla.com/D5870
dom/media/MediaManager.cpp
dom/media/MediaManager.h
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -3409,16 +3409,71 @@ MediaManager::EnumerateDevices(nsPIDOMWi
     // have removed all previous active listeners. Attempt to clean it here,
     // just in case, but ignore the return value.
     windowListener->Remove(sourceListener);
     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);
+
+  bool isSecure = aWindow->IsSecureContext();
+
+  return EnumerateDevicesImpl(aWindow->WindowID(),
+                              MediaSourceEnum::Other,
+                              MediaSourceEnum::Other,
+                              MediaSinkEnum::Speaker,
+                              DeviceEnumerationType::Normal,
+                              DeviceEnumerationType::Normal)
+  ->Then(GetCurrentThreadSerialEventTarget(), __func__,
+         [aDeviceId, isSecure](RefPtr<MediaDeviceSetRefCnt>&& aDevices) {
+    for (RefPtr<MediaDevice>& device : **aDevices) {
+      if (aDeviceId.IsEmpty() && device->mSinkInfo->Preferred()) {
+        return SinkInfoPromise::CreateAndResolve(device->mSinkInfo, __func__);
+      }
+      if (device->mID.Equals(aDeviceId)) {
+        // TODO: Check if the application is authorized to play audio
+        // through this device (Bug 1493982).
+        if (isSecure || device->mSinkInfo->Preferred()) {
+          return SinkInfoPromise::CreateAndResolve(device->mSinkInfo, __func__);
+        }
+        return SinkInfoPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_NOT_ALLOWED_ERR, __func__);
+      }
+    }
+    return SinkInfoPromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE, __func__);
+  }, [](RefPtr<MediaStreamError>&& reason) {
+    return SinkInfoPromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE, __func__);
+  });
+}
+
 /*
  * 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,36 @@ public:
                                const nsAString& aCallID = nsString());
 
   nsresult EnumerateDevices(nsPIDOMWindowInner* aWindow,
                             nsIGetUserMediaDevicesSuccessCallback* aOnSuccess,
                             nsIDOMGetUserMediaErrorCallback* aOnFailure,
                             dom::CallerType aCallerType);
 
   nsresult EnumerateDevices(nsPIDOMWindowInner* aWindow, dom::Promise& aPromise);
+
+  // Get the sink that corresponds to the given device id.
+  // It is resposible to check if an application is
+  // authorized to play audio through the requested device.
+  // The returned promise will be resolved with the device
+  // information if the device id matches one and operation is
+  // allowed. The default device is always allowed. Non default
+  // devices are allowed only in secure context. It is pending to
+  // implement an user authorization model. The promise will be
+  // rejected in the following cases:
+  // NS_ERROR_NOT_AVAILABLE: Device id does not exist.
+  // NS_ERROR_DOM_MEDIA_NOT_ALLOWED_ERR:
+  //   The requested device exists but it is not allowed to be used.
+  //   Currently, this happens only on non-default default devices
+  //   and non https connections. TODO, authorization model to allow
+  //   an application to play audio through the device (Bug 1493982).
+  // NS_ERROR_ABORT: General error.
+  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;
   typedef media::Refcountable<UniquePtr<MediaDeviceSet>> MediaDeviceSetRefCnt;