Bug 1208373 - Implement MediaStreamTrack.readyState. r?smaug,jib
MozReview-Commit-ID: EoMaG0R3Dpp
--- 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]