Bug 1208373 - Implement MediaStreamTrack.readyState. r?smaug,jib draft
authorAndreas Pehrson <pehrsons@gmail.com>
Tue, 10 May 2016 17:03:37 +0200
changeset 376730 25406fd0160084b7430ad8b7c65fd3b434e183d3
parent 376729 c30697044c1e6a98c19295b417c0b925f323f069
child 376731 29a71129127d3059fd3d6f32f091a63ef69bb00b
push id20652
push userpehrsons@gmail.com
push dateWed, 08 Jun 2016 15:10:47 +0000
reviewerssmaug, jib
bugs1208373
milestone50.0a1
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]