Bug 1299515 - Plumb MediaStreamTrack enabled state to sources. r=jib
authorAndreas Pehrson <pehrsons@mozilla.com>
Fri, 10 Nov 2017 15:55:42 +0100
changeset 454191 87a5b07fa4c9c258e11b1c77058afe135b9a6533
parent 454190 c7bd57a9d7ef2010fe408ffab503077bc15f3e01
child 454192 871480d5c37d3ff8e2d011ca4700f550148d490d
push id8799
push usermtabara@mozilla.com
push dateThu, 01 Mar 2018 16:46:23 +0000
treeherdermozilla-beta@15334014dc67 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjib
bugs1299515
milestone60.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 1299515 - Plumb MediaStreamTrack enabled state to sources. r=jib MozReview-Commit-ID: Eg1g9JtLmOz
dom/html/HTMLCanvasElement.cpp
dom/html/HTMLMediaElement.cpp
dom/media/MediaManager.cpp
dom/media/MediaStreamTrack.cpp
dom/media/MediaStreamTrack.h
dom/media/webaudio/MediaStreamAudioDestinationNode.cpp
media/webrtc/signaling/gtest/mediapipeline_unittest.cpp
media/webrtc/signaling/src/peerconnection/RemoteTrackSource.h
--- a/dom/html/HTMLCanvasElement.cpp
+++ b/dom/html/HTMLCanvasElement.cpp
@@ -715,16 +715,24 @@ public:
     if (!mCaptureStream) {
       NS_ERROR("No stream");
       return;
     }
 
     mCaptureStream->StopCapture();
   }
 
+  void Disable() override
+  {
+  }
+
+  void Enable() override
+  {
+  }
+
 private:
   virtual ~CanvasCaptureTrackSource() {}
 
   RefPtr<CanvasCaptureMediaStream> mCaptureStream;
 };
 
 NS_IMPL_ADDREF_INHERITED(CanvasCaptureTrackSource,
                          MediaStreamTrackSource)
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -3243,16 +3243,32 @@ public:
    * Do not keep the track source alive. The source lifetime is controlled by
    * its associated tracks.
    */
   bool KeepsSourceAlive() const override
   {
     return false;
   }
 
+  /**
+   * Do not keep the track source on. It is controlled by its associated tracks.
+   */
+  bool Enabled() const override
+  {
+    return false;
+  }
+
+  void Disable() override
+  {
+  }
+
+  void Enable() override
+  {
+  }
+
   void PrincipalChanged() override
   {
     if (!mCapturedTrackSource) {
       // This could happen during shutdown.
       return;
     }
 
     mPrincipal = mCapturedTrackSource->GetPrincipal();
@@ -3336,16 +3352,24 @@ public:
   void Stop() override
   {
     // We don't notify the source that a track was stopped since it will keep
     // producing tracks until the element ends. The decoder also needs the
     // tracks it created to be live at the source since the decoder's clock is
     // based on MediaStreams during capture.
   }
 
+  void Disable() override
+  {
+  }
+
+  void Enable() override
+  {
+  }
+
   void NotifyDecoderPrincipalChanged() override
   {
     nsCOMPtr<nsIPrincipal> newPrincipal = mElement->GetCurrentPrincipal();
     if (nsContentUtils::CombineResourcePrincipals(&mPrincipal, newPrincipal)) {
       PrincipalChanged();
     }
   }
 
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -183,16 +183,29 @@ public:
   /**
    * Posts a task to stop the device associated with aTrackID and notifies the
    * associated window listener that a track was stopped.
    * Should this track be the last live one to be stopped, we'll also clean up.
    */
   void StopTrack(TrackID aTrackID);
 
   /**
+   * Posts a task to disable the device associated with aTrackID and notifies
+   * the associated window listener that a track has been disabled.
+   */
+  void DisableTrack(TrackID aTrackID);
+
+
+  /**
+   * Posts a task to enable the device associated with aTrackID and notifies
+   * the associated window listener that a track has been enabled.
+   */
+  void EnableTrack(TrackID aTrackID);
+
+  /**
    * Stops all screen/app/window/audioCapture sharing, but not camera or
    * microphone.
    */
   void StopSharing();
 
   MediaStream* Stream() const
   {
     return mStream;
@@ -1114,16 +1127,30 @@ public:
         void Stop() override
         {
           if (mListener) {
             mListener->StopTrack(mTrackID);
             mListener = nullptr;
           }
         }
 
+        void Disable() override
+        {
+          if (mListener) {
+            mListener->DisableTrack(mTrackID);
+          }
+        }
+
+        void Enable() override
+        {
+          if (mListener) {
+            mListener->EnableTrack(mTrackID);
+          }
+        }
+
       protected:
         ~LocalTrackSource() {}
 
         RefPtr<SourceListener> mListener;
         const MediaSourceEnum mSource;
         const TrackID mTrackID;
         const RefPtr<const PeerIdentity> mPeerIdentity;
       };
@@ -3806,16 +3833,112 @@ SourceListener::StopTrack(TrackID aTrack
   if (!mWindowListener) {
     MOZ_ASSERT(false, "Should still have window listener");
     return;
   }
   mWindowListener->NotifySourceTrackStopped();
 }
 
 void
+SourceListener::DisableTrack(TrackID aTrackID)
+{
+  MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread");
+
+  if (!Activated()) {
+    MOZ_ASSERT(false, "No device to disable");
+    return;
+  }
+
+  RefPtr<MediaDevice> device;
+
+  switch (aTrackID) {
+    case kAudioTrack: {
+      LOG(("SourceListener %p disabling audio track %d", this, aTrackID));
+      if (!mAudioDevice) {
+        NS_ASSERTION(false, "Can't disable audio. No device.");
+        return;
+      }
+      if (mAudioStopped) {
+        // Audio stopped. Disabling is pointless.
+        return;
+      }
+      device = mAudioDevice;
+      break;
+    }
+    case kVideoTrack: {
+      LOG(("SourceListener %p disabling video track %d", this, aTrackID));
+      if (!mVideoDevice) {
+        NS_ASSERTION(false, "Can't disable video. No device.");
+        return;
+      }
+      if (mVideoStopped) {
+        // Video stopped. Disabling is pointless.
+        return;
+      }
+      device = mVideoDevice;
+      break;
+    }
+    default: {
+      MOZ_ASSERT(false, "Unknown track id");
+      return;
+    }
+  }
+
+  // XXX Later patch
+}
+
+void
+SourceListener::EnableTrack(TrackID aTrackID)
+{
+  MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread");
+
+  if (!Activated()) {
+    MOZ_ASSERT(false, "No device to enable");
+    return;
+  }
+
+  RefPtr<MediaDevice> device;
+
+  switch (aTrackID) {
+    case kAudioTrack: {
+      LOG(("SourceListener %p enabling audio track %d", this, aTrackID));
+      if (!mAudioDevice) {
+        NS_ASSERTION(false, "Can't enable audio. No device.");
+        return;
+      }
+      if (mAudioStopped) {
+        // Audio stopped. Enabling is pointless.
+        return;
+      }
+      device = mAudioDevice;
+      break;
+    }
+    case kVideoTrack: {
+      LOG(("SourceListener %p enabling video track %d", this, aTrackID));
+      if (!mVideoDevice) {
+        NS_ASSERTION(false, "Can't enable video. No device.");
+        return;
+      }
+      if (mVideoStopped) {
+        // Video stopped. Enabling is pointless.
+        return;
+      }
+      device = mVideoDevice;
+      break;
+    }
+    default: {
+      MOZ_ASSERT(false, "Unknown track id");
+      return;
+    }
+  }
+
+  // XXX Later patch
+}
+
+void
 SourceListener::StopSharing()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_RELEASE_ASSERT(mWindowListener);
 
   if (mStopped) {
     return;
   }
--- a/dom/media/MediaStreamTrack.cpp
+++ b/dom/media/MediaStreamTrack.cpp
@@ -217,16 +217,17 @@ void
 MediaStreamTrack::SetEnabled(bool aEnabled)
 {
   LOG(LogLevel::Info, ("MediaStreamTrack %p %s",
                        this, aEnabled ? "Enabled" : "Disabled"));
 
   mEnabled = aEnabled;
   GetOwnedStream()->SetTrackEnabled(mTrackID, mEnabled ? DisabledTrackMode::ENABLED
                                                        : DisabledTrackMode::SILENCE_BLACK);
+  GetSource().SinkEnabledStateChanged();
 }
 
 void
 MediaStreamTrack::Stop()
 {
   LOG(LogLevel::Info, ("MediaStreamTrack %p Stop()", this));
 
   if (Ended()) {
--- a/dom/media/MediaStreamTrack.h
+++ b/dom/media/MediaStreamTrack.h
@@ -69,16 +69,31 @@ public:
      * registered alive.
      * Return false to allow the source to stop.
      *
      * Typically MediaStreamTrack::Sink returns true and other Sinks
      * (like HTMLMediaElement::StreamCaptureTrackSource) return false.
      */
     virtual bool KeepsSourceAlive() const = 0;
 
+    /**
+     * Return true to ensure that the MediaStreamTrackSource where this Sink is
+     * registered is kept turned on and active.
+     * Return false to allow the source to pause, and any underlying devices to
+     * temporarily stop.
+     *
+     * When the underlying enabled state of the sink changes,
+     * call MediaStreamTrackSource::SinkEnabledStateChanged().
+     *
+     * Typically MediaStreamTrack returns the track's enabled state and other
+     * Sinks (like HTMLMediaElement::StreamCaptureTrackSource) return false so
+     * control over device state remains with tracks and their enabled state.
+     */
+    virtual bool Enabled() const = 0;
+
     virtual void PrincipalChanged() = 0;
     virtual void MutedChanged(bool aNewState) = 0;
   };
 
   MediaStreamTrackSource(nsIPrincipal* aPrincipal,
                          const nsString& aLabel)
     : mPrincipal(aPrincipal),
       mLabel(aLabel),
@@ -152,16 +167,43 @@ public:
 
   /**
    * Called by the source interface when all registered sinks with
    * KeepsSourceAlive() == true have unregistered.
    */
   virtual void Stop() = 0;
 
   /**
+   * Called by the source interface when all registered sinks with
+   * KeepsSourceAlive() == true become disabled.
+   */
+  virtual void Disable() = 0;
+
+  /**
+   * Called by the source interface when at least one registered sink with
+   * KeepsSourceAlive() == true become enabled.
+   */
+  virtual void Enable() = 0;
+
+  /**
+   * Called when a Sink's Enabled() state changed. Will iterate through all
+   * sinks and notify the source of the aggregated enabled state.
+   *
+   * Note that a Sink with KeepsSourceAlive() == false counts as disabled.
+   */
+  void SinkEnabledStateChanged()
+  {
+    if (IsEnabled()) {
+      Enable();
+    } else {
+      Disable();
+    }
+  }
+
+  /**
    * Called by each MediaStreamTrack clone on initialization.
    */
   void RegisterSink(Sink* aSink)
   {
     MOZ_ASSERT(NS_IsMainThread());
     if (mStopped) {
       return;
     }
@@ -200,16 +242,26 @@ protected:
     for (const WeakPtr<Sink>& sink : mSinks) {
       if (sink && sink->KeepsSourceAlive()) {
         return true;
       }
     }
     return false;
   }
 
+  bool IsEnabled()
+  {
+    for (const WeakPtr<Sink>& sink : mSinks) {
+      if (sink && sink->KeepsSourceAlive() && sink->Enabled()) {
+        return true;
+      }
+    }
+    return false;
+  }
+
   /**
    * Called by a sub class when the principal has changed.
    * Notifies all sinks.
    */
   void PrincipalChanged()
   {
     MOZ_ASSERT(NS_IsMainThread());
     nsTArray<WeakPtr<Sink>> sinks(mSinks);
@@ -267,16 +319,18 @@ public:
                             MediaSourceEnum::Other)
     : MediaStreamTrackSource(aPrincipal, nsString())
     , mMediaSource(aMediaSource)
   {}
 
   MediaSourceEnum GetMediaSource() const override { return mMediaSource; }
 
   void Stop() override {}
+  void Disable() override {}
+  void Enable() override {}
 
 protected:
   ~BasicTrackSource() {}
 
   const MediaSourceEnum mMediaSource;
 };
 
 /**
@@ -337,17 +391,17 @@ public:
 
   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;
   virtual void GetLabel(nsAString& aLabel, CallerType /* aCallerType */) { GetSource().GetLabel(aLabel); }
-  bool Enabled() { return mEnabled; }
+  bool Enabled() const override { return mEnabled; }
   void SetEnabled(bool aEnabled);
   bool Muted() { return mMuted; }
   void Stop();
   void GetConstraints(dom::MediaTrackConstraints& aResult);
   void GetSettings(dom::MediaTrackSettings& aResult, CallerType aCallerType);
 
   already_AddRefed<Promise>
   ApplyConstraints(const dom::MediaTrackConstraints& aConstraints,
--- a/dom/media/webaudio/MediaStreamAudioDestinationNode.cpp
+++ b/dom/media/webaudio/MediaStreamAudioDestinationNode.cpp
@@ -44,16 +44,24 @@ public:
     return MediaSourceEnum::AudioCapture;
   }
 
   void Stop() override
   {
     Destroy();
   }
 
+  void Disable() override
+  {
+  }
+
+  void Enable() override
+  {
+  }
+
 private:
   ~AudioDestinationTrackSource() = default;
 
   RefPtr<MediaStreamAudioDestinationNode> mNode;
 };
 
 NS_IMPL_ADDREF_INHERITED(AudioDestinationTrackSource,
                          MediaStreamTrackSource)
--- a/media/webrtc/signaling/gtest/mediapipeline_unittest.cpp
+++ b/media/webrtc/signaling/gtest/mediapipeline_unittest.cpp
@@ -67,16 +67,25 @@ public:
   {
   }
 
   virtual mozilla::dom::MediaSourceEnum GetMediaSource() const override
   {
     return mozilla::dom::MediaSourceEnum::Microphone;
   }
 
+
+  virtual void Disable() override
+  {
+  }
+
+  virtual void Enable() override
+  {
+  }
+
   virtual void Stop() override
   {
   }
 
 };
 
 class FakeAudioStreamTrack : public mozilla::dom::AudioStreamTrack {
 
--- a/media/webrtc/signaling/src/peerconnection/RemoteTrackSource.h
+++ b/media/webrtc/signaling/src/peerconnection/RemoteTrackSource.h
@@ -35,16 +35,24 @@ public:
   }
 
   void Stop() override
   {
     // XXX (Bug 1314270): Implement rejection logic if necessary when we have
     //                    clarity in the spec.
   }
 
+  void Disable() override
+  {
+  }
+
+  void Enable() override
+  {
+  }
+
   void SetPrincipal(nsIPrincipal* aPrincipal)
   {
     mPrincipal = aPrincipal;
     PrincipalChanged();
   }
 
 protected:
   virtual ~RemoteTrackSource() {}