Bug 1208371 - Route ApplyConstraints through MediaStreamTrackSource. r=jib
authorAndreas Pehrson <pehrsons@gmail.com>
Mon, 01 Feb 2016 22:43:38 +0800
changeset 348436 67aec27a919c5251528d55904747747fd6312327
parent 348435 9b9a6dbb6eeaa61763d80c6211aefa390916dcfe
child 348437 e11ca9dbdfc31d3682a31543b5226e1c553e2e4b
push id14828
push userpehrsons@gmail.com
push dateThu, 07 Apr 2016 12:57:27 +0000
reviewersjib
bugs1208371
milestone48.0a1
Bug 1208371 - Route ApplyConstraints through MediaStreamTrackSource. r=jib MozReview-Commit-ID: CnJnxszKU4o
dom/html/HTMLMediaElement.cpp
dom/media/AudioStreamTrack.h
dom/media/DOMMediaStream.cpp
dom/media/DOMMediaStream.h
dom/media/MediaManager.cpp
dom/media/MediaManager.h
dom/media/MediaStreamTrack.cpp
dom/media/MediaStreamTrack.h
dom/media/VideoStreamTrack.h
media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -1881,16 +1881,25 @@ public:
     mElement->AddDecoderPrincipalChangeObserver(this);
   }
 
   MediaSourceEnum GetMediaSource() const override
   {
     return MediaSourceEnum::Other;
   }
 
+  already_AddRefed<Promise>
+  ApplyConstraints(nsPIDOMWindowInner* aWindow,
+                   const dom::MediaTrackConstraints& aConstraints,
+                   ErrorResult &aRv) override
+  {
+    NS_ERROR("ApplyConstraints not implemented for media element capture");
+    return nullptr;
+  }
+
   void Stop() override
   {
     NS_ERROR("We're reporting remote=true to not be stoppable. "
              "Stop() should not be called.");
   }
 
   void NotifyDecoderPrincipalChanged() override
   {
--- a/dom/media/AudioStreamTrack.h
+++ b/dom/media/AudioStreamTrack.h
@@ -18,16 +18,18 @@ public:
                    TrackID aInputTrackID, const nsString& aLabel,
                    MediaStreamTrackSource* aSource)
     : MediaStreamTrack(aStream, aTrackID, aInputTrackID, aLabel, aSource) {}
 
   JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   AudioStreamTrack* AsAudioStreamTrack() override { return this; }
 
+  const AudioStreamTrack* AsAudioStreamTrack() const override { return this; }
+
   // WebIDL
   void GetKind(nsAString& aKind) override { aKind.AssignLiteral("audio"); }
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* AUDIOSTREAMTRACK_H_ */
--- a/dom/media/DOMMediaStream.cpp
+++ b/dom/media/DOMMediaStream.cpp
@@ -13,18 +13,16 @@
 #include "mozilla/dom/LocalMediaStreamBinding.h"
 #include "mozilla/dom/AudioNode.h"
 #include "AudioChannelAgent.h"
 #include "mozilla/dom/AudioTrack.h"
 #include "mozilla/dom/AudioTrackList.h"
 #include "mozilla/dom/VideoTrack.h"
 #include "mozilla/dom/VideoTrackList.h"
 #include "mozilla/dom/HTMLCanvasElement.h"
-#include "mozilla/dom/MediaStreamError.h"
-#include "mozilla/dom/Promise.h"
 #include "MediaStreamGraph.h"
 #include "AudioStreamTrack.h"
 #include "VideoStreamTrack.h"
 #include "Layers.h"
 
 // GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
 // GetTickCount() and conflicts with NS_DECL_NSIDOMMEDIASTREAM, containing
 // currentTime getter.
@@ -745,35 +743,16 @@ DOMMediaStream::CreateAudioCaptureStream
 {
   // Audio capture doesn't create tracks dynamically
   MediaStreamTrackSourceGetter* getter = nullptr;
   RefPtr<DOMMediaStream> stream = new DOMMediaStream(aWindow, getter);
   stream->InitAudioCaptureStream(aPrincipal, aGraph);
   return stream.forget();
 }
 
-already_AddRefed<Promise>
-DOMMediaStream::ApplyConstraintsToTrack(TrackID aTrackID,
-                                        const MediaTrackConstraints& aConstraints,
-                                        ErrorResult &aRv)
-{
-  nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(mWindow);
-  RefPtr<Promise> promise = Promise::Create(go, aRv);
-  MOZ_RELEASE_ASSERT(!aRv.Failed());
-
-  promise->MaybeReject(new MediaStreamError(
-      mWindow,
-      NS_LITERAL_STRING("OverconstrainedError"),
-      NS_LITERAL_STRING(""),
-      NS_LITERAL_STRING("")));
-  return promise.forget();
-}
-
-
-
 void
 DOMMediaStream::PrincipalChanged(MediaStreamTrack* aTrack)
 {
   MOZ_ASSERT(aTrack);
   NS_ASSERTION(HasTrack(*aTrack), "Principal changed for an unknown track");
   LOG(LogLevel::Info, ("DOMMediaStream %p Principal changed for track %p",
                        this, aTrack));
   RecomputePrincipal();
--- a/dom/media/DOMMediaStream.h
+++ b/dom/media/DOMMediaStream.h
@@ -416,21 +416,16 @@ public:
   /**
    * Overridden in DOMLocalMediaStreams to allow getUserMedia to pass
    * data directly to RTCPeerConnection without going through graph queuing.
    * Returns a bool to let us know if direct data will be delivered.
    */
   virtual bool AddDirectListener(MediaStreamDirectListener *aListener) { return false; }
   virtual void RemoveDirectListener(MediaStreamDirectListener *aListener) {}
 
-  virtual already_AddRefed<dom::Promise>
-  ApplyConstraintsToTrack(TrackID aTrackID,
-                          const MediaTrackConstraints& aConstraints,
-                          ErrorResult &aRv);
-
   virtual DOMLocalMediaStream* AsDOMLocalMediaStream() { return nullptr; }
   virtual DOMHwMediaStream* AsDOMHwMediaStream() { return nullptr; }
 
   bool IsFinished();
   /**
    * Returns a principal indicating who may access this stream. The stream contents
    * can only be accessed by principals subsuming this principal.
    */
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -687,61 +687,16 @@ public:
   {
     StopImpl();
 
     if (GetSourceStream()) {
       GetSourceStream()->Destroy();
     }
   }
 
-  already_AddRefed<Promise>
-  ApplyConstraintsToTrack(TrackID aTrackID,
-                          const MediaTrackConstraints& aConstraints,
-                          ErrorResult &aRv) override
-  {
-    nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(mWindow);
-    RefPtr<Promise> promise = Promise::Create(go, aRv);
-
-    if (sInShutdown) {
-      RefPtr<MediaStreamError> error = new MediaStreamError(mWindow,
-          NS_LITERAL_STRING("AbortError"),
-          NS_LITERAL_STRING("In shutdown"));
-      promise->MaybeReject(error);
-      return promise.forget();
-    }
-    if (!GetSourceStream()) {
-      RefPtr<MediaStreamError> error = new MediaStreamError(mWindow,
-          NS_LITERAL_STRING("InternalError"),
-          NS_LITERAL_STRING("No stream."));
-      promise->MaybeReject(error);
-      return promise.forget();
-    }
-
-    RefPtr<dom::MediaStreamTrack> track = FindOwnedDOMTrack(mOwnedStream, aTrackID);
-    if (!track) {
-      LOG(("ApplyConstraintsToTrack(%d) on non-existent track", aTrackID));
-      RefPtr<MediaStreamError> error = new MediaStreamError(mWindow,
-          NS_LITERAL_STRING("InternalError"),
-          NS_LITERAL_STRING("No track."));
-      promise->MaybeReject(error);
-      return promise.forget();
-    }
-
-    typedef media::Pledge<bool, MediaStreamError*> PledgeVoid;
-
-    RefPtr<PledgeVoid> p = mListener->ApplyConstraintsToTrack(mWindow,
-        aTrackID, !!track->AsAudioStreamTrack(), aConstraints);
-    p->Then([promise](bool& aDummy) mutable {
-      promise->MaybeResolve(false);
-    }, [promise](MediaStreamError*& reason) mutable {
-      promise->MaybeReject(reason);
-    });
-    return promise.forget();
-  }
-
   // Allow getUserMedia to pass input data directly to PeerConnection/MediaPipeline
   bool AddDirectListener(MediaStreamDirectListener *aListener) override
   {
     if (GetSourceStream()) {
       GetSourceStream()->AddDirectListener(aListener);
       return true; // application should ignore NotifyQueuedTrackData
     }
     return false;
@@ -920,16 +875,45 @@ public:
           : MediaStreamTrackSource(aPrincipal, false), mListener(aListener),
             mSource(aSource), mTrackID(aTrackID) {}
 
         MediaSourceEnum GetMediaSource() const override
         {
           return mSource;
         }
 
+        already_AddRefed<Promise>
+        ApplyConstraints(nsPIDOMWindowInner* aWindow,
+                         const MediaTrackConstraints& aConstraints,
+                         ErrorResult &aRv) override
+        {
+          nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(aWindow);
+          RefPtr<Promise> promise = Promise::Create(go, aRv);
+
+          if (sInShutdown) {
+            RefPtr<MediaStreamError> error = new MediaStreamError(aWindow,
+                NS_LITERAL_STRING("AbortError"),
+                NS_LITERAL_STRING("In shutdown"));
+            promise->MaybeReject(error);
+            return promise.forget();
+          }
+
+          typedef media::Pledge<bool, MediaStreamError*> PledgeVoid;
+
+          RefPtr<PledgeVoid> p =
+            mListener->ApplyConstraintsToTrack(aWindow, mTrackID, aConstraints);
+          p->Then([promise](bool& aDummy) mutable {
+            promise->MaybeResolve(false);
+          }, [promise](MediaStreamError*& reason) mutable {
+            promise->MaybeReject(reason);
+          });
+          return promise.forget();
+        }
+
+
         void Stop() override
         {
           if (mListener) {
             mListener->StopTrack(mTrackID);
             mListener = nullptr;
           }
         }
 
@@ -3142,36 +3126,36 @@ GetUserMediaCallbackMediaStreamListener:
 }
 
 // ApplyConstraints for track
 
 already_AddRefed<GetUserMediaCallbackMediaStreamListener::PledgeVoid>
 GetUserMediaCallbackMediaStreamListener::ApplyConstraintsToTrack(
     nsPIDOMWindowInner* aWindow,
     TrackID aTrackID,
-    bool aIsAudio,
     const MediaTrackConstraints& aConstraints)
 {
   MOZ_ASSERT(NS_IsMainThread());
   RefPtr<PledgeVoid> p = new PledgeVoid();
 
-  if (!(((aIsAudio && mAudioDevice) ||
-         (!aIsAudio && mVideoDevice)) && !mStopped))
+  // XXX to support multiple tracks of a type in a stream, this should key off
+  // the TrackID and not just the type
+  RefPtr<AudioDevice> audioDevice =
+    aTrackID == kAudioTrack ? mAudioDevice.get() : nullptr;
+  RefPtr<VideoDevice> videoDevice =
+    aTrackID == kVideoTrack ? mVideoDevice.get() : nullptr;
+
+  if (mStopped || (!audioDevice && !videoDevice))
   {
     LOG(("gUM track %d applyConstraints, but we don't have type %s",
-         aTrackID, aIsAudio ? "audio" : "video"));
+         aTrackID, aTrackID == kAudioTrack ? "audio" : "video"));
     p->Resolve(false);
     return p.forget();
   }
 
-  // XXX to support multiple tracks of a type in a stream, this should key off
-  // the TrackID and not just the type
-  RefPtr<AudioDevice> audioDevice = aIsAudio ? mAudioDevice.get() : nullptr;
-  RefPtr<VideoDevice> videoDevice = !aIsAudio ? mVideoDevice.get() : nullptr;
-
   RefPtr<MediaManager> mgr = MediaManager::GetInstance();
   uint32_t id = mgr->mOutstandingVoidPledges.Append(*p);
   uint64_t windowId = aWindow->WindowID();
 
   MediaManager::PostTask(FROM_HERE, NewTaskFrom([id, windowId,
                                                  audioDevice, videoDevice,
                                                  aConstraints]() mutable {
     MOZ_ASSERT(MediaManager::IsInMediaThread());
--- a/dom/media/MediaManager.h
+++ b/dom/media/MediaManager.h
@@ -170,17 +170,17 @@ public:
   void StopSharing();
 
   void StopTrack(TrackID aID);
 
   typedef media::Pledge<bool, dom::MediaStreamError*> PledgeVoid;
 
   already_AddRefed<PledgeVoid>
   ApplyConstraintsToTrack(nsPIDOMWindowInner* aWindow,
-                          TrackID aID, bool aIsAudio,
+                          TrackID aID,
                           const dom::MediaTrackConstraints& aConstraints);
 
   // mVideo/AudioDevice are set by Activate(), so we assume they're capturing
   // if set and represent a real capture device.
   bool CapturingVideo()
   {
     MOZ_ASSERT(NS_IsMainThread());
     return mVideoDevice && !mStopped &&
--- a/dom/media/MediaStreamTrack.cpp
+++ b/dom/media/MediaStreamTrack.cpp
@@ -22,16 +22,33 @@ namespace dom {
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaStreamTrackSource)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaStreamTrackSource)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaStreamTrackSource)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 NS_IMPL_CYCLE_COLLECTION(MediaStreamTrackSource, mPrincipal)
 
+already_AddRefed<Promise>
+MediaStreamTrackSource::ApplyConstraints(nsPIDOMWindowInner* aWindow,
+                                         const dom::MediaTrackConstraints& aConstraints,
+                                         ErrorResult &aRv)
+{
+  nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(aWindow);
+  RefPtr<Promise> promise = Promise::Create(go, aRv);
+  MOZ_RELEASE_ASSERT(!aRv.Failed());
+
+  promise->MaybeReject(new MediaStreamError(
+    aWindow,
+    NS_LITERAL_STRING("OverconstrainedError"),
+    NS_LITERAL_STRING(""),
+    NS_LITERAL_STRING("")));
+  return promise.forget();
+}
+
 MediaStreamTrack::MediaStreamTrack(DOMMediaStream* aStream, TrackID aTrackID,
                                    TrackID aInputTrackID, const nsString& aLabel,
                                    MediaStreamTrackSource* aSource)
   : mOwningStream(aStream), mTrackID(aTrackID),
     mInputTrackID(aInputTrackID), mSource(aSource), mLabel(aLabel),
     mEnded(false), mEnabled(true), mRemote(aSource->IsRemote()), mStopped(false)
 {
 
@@ -139,17 +156,18 @@ MediaStreamTrack::ApplyConstraints(const
   if (MOZ_LOG_TEST(gMediaStreamTrackLog, LogLevel::Info)) {
     nsString str;
     aConstraints.ToJSON(str);
 
     LOG(LogLevel::Info, ("MediaStreamTrack %p ApplyConstraints() with "
                          "constraints %s", this, NS_ConvertUTF16toUTF8(str).get()));
   }
 
-  return mOwningStream->ApplyConstraintsToTrack(mTrackID, aConstraints, aRv);
+  nsPIDOMWindowInner* window = mOwningStream->GetParentObject();
+  return GetSource().ApplyConstraints(window, aConstraints, aRv);
 }
 
 MediaStreamGraph*
 MediaStreamTrack::Graph()
 {
   return GetOwnedStream()->Graph();
 }
 
--- a/dom/media/MediaStreamTrack.h
+++ b/dom/media/MediaStreamTrack.h
@@ -75,16 +75,25 @@ public:
   /**
    * Forwards a photo request to backends that support it. Other backends return
    * NS_ERROR_NOT_IMPLEMENTED to indicate that a MediaStreamGraph-based fallback
    * should be used.
    */
   virtual nsresult TakePhoto(MediaEnginePhotoCallback*) const { return NS_ERROR_NOT_IMPLEMENTED; }
 
   /**
+   * We provide a fallback solution to ApplyConstraints() here.
+   * Sources that support ApplyConstraints() will have to override it.
+   */
+  virtual already_AddRefed<Promise>
+  ApplyConstraints(nsPIDOMWindowInner* aWindow,
+                   const dom::MediaTrackConstraints& aConstraints,
+                   ErrorResult &aRv);
+
+  /**
    * Called by the source interface when all registered sinks have unregistered.
    */
   virtual void Stop() = 0;
 
   /**
    * Called by each MediaStreamTrack clone on initialization.
    */
   void RegisterSink(Sink* aSink)
@@ -189,16 +198,19 @@ public:
                                            DOMEventTargetHelper)
 
   nsPIDOMWindowInner* GetParentObject() const;
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override = 0;
 
   virtual AudioStreamTrack* AsAudioStreamTrack() { return nullptr; }
   virtual VideoStreamTrack* AsVideoStreamTrack() { return nullptr; }
 
+  virtual const AudioStreamTrack* AsAudioStreamTrack() const { return nullptr; }
+  virtual const VideoStreamTrack* AsVideoStreamTrack() const { return nullptr; }
+
   // WebIDL
   virtual void GetKind(nsAString& aKind) = 0;
   void GetId(nsAString& aID) const;
   void GetLabel(nsAString& aLabel) { aLabel.Assign(mLabel); }
   bool Enabled() { return mEnabled; }
   void SetEnabled(bool aEnabled);
   void Stop();
   already_AddRefed<Promise>
--- a/dom/media/VideoStreamTrack.h
+++ b/dom/media/VideoStreamTrack.h
@@ -18,16 +18,18 @@ public:
                    TrackID aInputTrackID, const nsString& aLabel,
                    MediaStreamTrackSource* aSource)
     : MediaStreamTrack(aStream, aTrackID, aInputTrackID, aLabel, aSource) {}
 
   JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   VideoStreamTrack* AsVideoStreamTrack() override { return this; }
 
+  const VideoStreamTrack* AsVideoStreamTrack() const override { return this; }
+
   // WebIDL
   void GetKind(nsAString& aKind) override { aKind.AssignLiteral("video"); }
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* VIDEOSTREAMTRACK_H_ */
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
@@ -153,16 +153,25 @@ public:
   explicit RemoteTrackSource(nsIPrincipal* aPrincipal)
     : dom::MediaStreamTrackSource(aPrincipal, true) {}
 
   dom::MediaSourceEnum GetMediaSource() const override
   {
     return dom::MediaSourceEnum::Other;
   }
 
+  already_AddRefed<dom::Promise>
+  ApplyConstraints(nsPIDOMWindowInner* aWindow,
+                   const dom::MediaTrackConstraints& aConstraints,
+                   ErrorResult &aRv) override
+  {
+    NS_ERROR("Can't ApplyConstraints() a remote source!");
+    return nullptr;
+  }
+
   void Stop() override { NS_ERROR("Can't stop a remote source!"); }
 
   void SetPrincipal(nsIPrincipal* aPrincipal)
   {
     mPrincipal = aPrincipal;
     PrincipalChanged();
   }