Bug 1208373 - Implement MediaStreamTrack.readyState. r=smaug,jib
authorAndreas Pehrson <pehrsons@gmail.com>
Tue, 10 May 2016 17:03:37 +0200
changeset 303622 48581a9670a188d4ee1cda60cffb3b08bdfafd1a
parent 303621 51f07d349d5efadf2a207759f10fcbacaad310d0
child 303623 ed5a51da1a85381a22d2c0af4078f018862c7a2e
push id79133
push userpehrsons@gmail.com
push dateTue, 05 Jul 2016 09:26:07 +0000
treeherdermozilla-inbound@750df2678990 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug, jib
bugs1208373
milestone50.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 1208373 - Implement MediaStreamTrack.readyState. r=smaug,jib MozReview-Commit-ID: EoMaG0R3Dpp
dom/media/DOMMediaStream.cpp
dom/media/MediaStreamTrack.cpp
dom/media/MediaStreamTrack.h
dom/webidl/MediaStreamTrack.webidl
--- a/dom/media/DOMMediaStream.cpp
+++ b/dom/media/DOMMediaStream.cpp
@@ -1030,16 +1030,25 @@ DOMMediaStream::CloneDOMTrack(MediaStrea
     new TrackPort(inputPort, newTrack, TrackPort::InputPortOwnership::OWNED));
 
   mTracks.AppendElement(
     new TrackPort(mPlaybackPort, newTrack, TrackPort::InputPortOwnership::EXTERNAL));
 
   NotifyTrackAdded(newTrack);
 
   newTrack->SetEnabled(aTrack.Enabled());
+  newTrack->SetReadyState(aTrack.ReadyState());
+
+  if (aTrack.Ended()) {
+    // For extra suspenders, make sure that we don't forward data by mistake
+    // to the clone when the original has already ended.
+    RefPtr<Pledge<bool, nsresult>> blockingPledge =
+      inputPort->BlockSourceTrackId(inputTrackID);
+    Unused << blockingPledge;
+  }
 
   return newTrack.forget();
 }
 
 static DOMMediaStream::TrackPort*
 FindTrackPortAmongTracks(const MediaStreamTrack& aTrack,
                          const nsTArray<RefPtr<DOMMediaStream::TrackPort>>& aTracks)
 {
--- a/dom/media/MediaStreamTrack.cpp
+++ b/dom/media/MediaStreamTrack.cpp
@@ -110,17 +110,18 @@ protected:
 };
 
 MediaStreamTrack::MediaStreamTrack(DOMMediaStream* aStream, TrackID aTrackID,
                                    TrackID aInputTrackID,
                                    MediaStreamTrackSource* aSource)
   : mOwningStream(aStream), mTrackID(aTrackID),
     mInputTrackID(aInputTrackID), mSource(aSource),
     mPrincipal(aSource->GetPrincipal()),
-    mEnded(false), mEnabled(true), mRemote(aSource->IsRemote()), mStopped(false)
+    mReadyState(MediaStreamTrackState::Live),
+    mEnabled(true), mRemote(aSource->IsRemote())
 {
 
   if (!gMediaStreamTrackLog) {
     gMediaStreamTrackLog = PR_NewLogModule("MediaStreamTrack");
   }
 
   GetSource().RegisterSink(this);
 
@@ -211,18 +212,18 @@ MediaStreamTrack::SetEnabled(bool aEnabl
   GetOwnedStream()->SetTrackEnabled(mTrackID, aEnabled);
 }
 
 void
 MediaStreamTrack::Stop()
 {
   LOG(LogLevel::Info, ("MediaStreamTrack %p Stop()", this));
 
-  if (mStopped) {
-    LOG(LogLevel::Warning, ("MediaStreamTrack %p Already stopped", this));
+  if (Ended()) {
+    LOG(LogLevel::Warning, ("MediaStreamTrack %p Already ended", this));
     return;
   }
 
   if (mRemote) {
     LOG(LogLevel::Warning, ("MediaStreamTrack %p is remote. Can't be stopped.", this));
     return;
   }
 
@@ -234,17 +235,17 @@ MediaStreamTrack::Stop()
   mSource->UnregisterSink(this);
 
   MOZ_ASSERT(mOwningStream, "Every MediaStreamTrack needs an owning DOMMediaStream");
   DOMMediaStream::TrackPort* port = mOwningStream->FindOwnedTrackPort(*this);
   MOZ_ASSERT(port, "A MediaStreamTrack must exist in its owning DOMMediaStream");
   RefPtr<Pledge<bool>> p = port->BlockSourceTrackId(mInputTrackID);
   Unused << p;
 
-  mStopped = true;
+  mReadyState = MediaStreamTrackState::Ended;
 }
 
 already_AddRefed<Promise>
 MediaStreamTrack::ApplyConstraints(const MediaTrackConstraints& aConstraints,
                                    ErrorResult &aRv)
 {
   if (MOZ_LOG_TEST(gMediaStreamTrackLog, LogLevel::Info)) {
     nsString str;
@@ -350,23 +351,23 @@ MediaStreamTrack::Clone()
   return newStream->CloneDOMTrack(*this, mTrackID);
 }
 
 void
 MediaStreamTrack::NotifyEnded()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  if (mEnded) {
+  if (Ended()) {
     return;
   }
 
   LOG(LogLevel::Info, ("MediaStreamTrack %p ended", this));
 
-  mEnded = true;
+  mReadyState = MediaStreamTrackState::Ended;
 
   DispatchTrustedEvent(NS_LITERAL_STRING("ended"));
 }
 
 DOMMediaStream*
 MediaStreamTrack::GetInputDOMStream()
 {
   MediaStreamTrack* originalTrack =
--- a/dom/media/MediaStreamTrack.h
+++ b/dom/media/MediaStreamTrack.h
@@ -261,20 +261,30 @@ public:
   void GetId(nsAString& aID) const;
   void GetLabel(nsAString& aLabel) { GetSource().GetLabel(aLabel); }
   bool Enabled() { return mEnabled; }
   void SetEnabled(bool aEnabled);
   void Stop();
   already_AddRefed<Promise>
   ApplyConstraints(const dom::MediaTrackConstraints& aConstraints, ErrorResult &aRv);
   already_AddRefed<MediaStreamTrack> Clone();
+  MediaStreamTrackState ReadyState() { return mReadyState; }
 
   IMPL_EVENT_HANDLER(ended)
 
-  bool Ended() const { return mEnded; }
+  /**
+   * Convenience (and legacy) method for when ready state is "ended".
+   */
+  bool Ended() const { return mReadyState == MediaStreamTrackState::Ended; }
+
+  /**
+   * Forces the ready state to a particular value, for instance when we're
+   * cloning an already ended track.
+   */
+  void SetReadyState(MediaStreamTrackState aState) { mReadyState = aState; }
 
   /**
    * Notified by the MediaStreamGraph, through our owning MediaStream on the
    * main thread.
    *
    * Note that this sets the track to ended and raises the "ended" event
    * synchronously.
    */
@@ -402,18 +412,17 @@ protected:
   TrackID mTrackID;
   TrackID mInputTrackID;
   RefPtr<MediaStreamTrackSource> mSource;
   RefPtr<MediaStreamTrack> mOriginalTrack;
   nsCOMPtr<nsIPrincipal> mPrincipal;
   nsCOMPtr<nsIPrincipal> mPendingPrincipal;
   RefPtr<PrincipalHandleListener> mPrincipalHandleListener;
   nsString mID;
-  bool mEnded;
+  MediaStreamTrackState mReadyState;
   bool mEnabled;
   const bool mRemote;
-  bool mStopped;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* MEDIASTREAMTRACK_H_ */
--- a/dom/webidl/MediaStreamTrack.webidl
+++ b/dom/webidl/MediaStreamTrack.webidl
@@ -58,28 +58,33 @@ dictionary MediaTrackConstraintSet {
     ConstrainBoolean mozNoiseSuppression;
     ConstrainBoolean mozAutoGainControl;
 };
 
 dictionary MediaTrackConstraints : MediaTrackConstraintSet {
     sequence<MediaTrackConstraintSet> advanced;
 };
 
+enum MediaStreamTrackState {
+    "live",
+    "ended"
+};
+
 [Exposed=Window]
 interface MediaStreamTrack : EventTarget {
     readonly    attribute DOMString             kind;
     readonly    attribute DOMString             id;
     readonly    attribute DOMString             label;
                 attribute boolean               enabled;
 //  readonly    attribute boolean               muted;
 //              attribute EventHandler          onmute;
 //              attribute EventHandler          onunmute;
 //  readonly    attribute boolean               _readonly;
 //  readonly    attribute boolean               remote;
-//  readonly    attribute MediaStreamTrackState readyState;
+    readonly    attribute MediaStreamTrackState readyState;
                 attribute EventHandler          onended;
     MediaStreamTrack       clone ();
     void                   stop ();
 //  MediaTrackCapabilities getCapabilities ();
 //  MediaTrackConstraints  getConstraints ();
 //  MediaTrackSettings     getSettings ();
 
     [Throws]