Bug 1208316 - Route notifications of ending tracks through MediaStreamTrack instead of DOMMediaStream. r=jib

MozReview-Commit-ID: KMFE5HXEOtJ

--HG--
extra : rebase_source : 279dffcdd325a5ac78f115803269a724887b6ac0
This commit is contained in:
Andreas Pehrson 2016-09-23 17:03:13 +02:00
Родитель d88a8a02fa
Коммит da3ba8634d
4 изменённых файлов: 148 добавлений и 48 удалений

Просмотреть файл

@ -236,40 +236,6 @@ public:
mStream = nullptr;
}
void DoNotifyTrackEnded(MediaStream* aInputStream,
TrackID aInputTrackID)
{
MOZ_ASSERT(NS_IsMainThread());
if (!mStream) {
return;
}
LOG(LogLevel::Debug, ("DOMMediaStream %p Track %u of stream %p ended",
mStream, aInputTrackID, aInputStream));
RefPtr<MediaStreamTrack> track =
mStream->FindPlaybackDOMTrack(aInputStream, aInputTrackID);
if (!track) {
LOG(LogLevel::Debug, ("DOMMediaStream %p Not a playback track.", mStream));
return;
}
LOG(LogLevel::Debug, ("DOMMediaStream %p Playback track; notifying stream listeners.",
mStream));
mStream->NotifyTrackRemoved(track);
RefPtr<TrackPort> endedPort = mStream->FindPlaybackTrackPort(*track);
NS_ASSERTION(endedPort, "Playback track should have a TrackPort");
if (endedPort && IsTrackIDExplicit(endedPort->GetSourceTrackId())) {
// If a track connected to a locked-track input port ends, we destroy the
// port to allow our playback stream to finish.
// XXX (bug 1208316) This should not be necessary when MediaStreams don't
// finish but instead become inactive.
endedPort->DestroyInputPort();
}
}
void DoNotifyFinishedTrackCreation()
{
MOZ_ASSERT(NS_IsMainThread());
@ -285,22 +251,19 @@ public:
NewRunnableMethod(mStream, &DOMMediaStream::NotifyTracksCreated));
}
// The methods below are called on the MediaStreamGraph thread.
void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID,
StreamTime aTrackOffset, TrackEventCommand aTrackEvents,
const MediaSegment& aQueuedMedia,
MediaStream* aInputStream,
TrackID aInputTrackID) override
void DoNotifyFinished()
{
if (aTrackEvents & TrackEventCommand::TRACK_EVENT_ENDED) {
nsCOMPtr<nsIRunnable> runnable =
NewRunnableMethod<RefPtr<MediaStream>, TrackID>(
this, &PlaybackStreamListener::DoNotifyTrackEnded, aInputStream, aInputTrackID);
aGraph->DispatchToMainThreadAfterStreamStateUpdate(runnable.forget());
MOZ_ASSERT(NS_IsMainThread());
if (!mStream) {
return;
}
mStream->NotifyFinished();
}
// The methods below are called on the MediaStreamGraph thread.
void NotifyFinishedTrackCreation(MediaStreamGraph* aGraph) override
{
nsCOMPtr<nsIRunnable> runnable =
@ -313,6 +276,48 @@ private:
DOMMediaStream* mStream;
};
class DOMMediaStream::PlaybackTrackListener : public MediaStreamTrackConsumer
{
public:
explicit PlaybackTrackListener(DOMMediaStream* aStream) :
mStream(aStream) {}
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(PlaybackTrackListener,
MediaStreamTrackConsumer)
void NotifyEnded(MediaStreamTrack* aTrack) override
{
if (!mStream) {
MOZ_ASSERT(false);
return;
}
if (!aTrack) {
MOZ_ASSERT(false);
return;
}
MOZ_ASSERT(mStream->HasTrack(*aTrack));
mStream->NotifyTrackRemoved(aTrack);
}
protected:
virtual ~PlaybackTrackListener() {}
RefPtr<DOMMediaStream> mStream;
};
NS_IMPL_ADDREF_INHERITED(DOMMediaStream::PlaybackTrackListener,
MediaStreamTrackConsumer)
NS_IMPL_RELEASE_INHERITED(DOMMediaStream::PlaybackTrackListener,
MediaStreamTrackConsumer)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DOMMediaStream::PlaybackTrackListener)
NS_INTERFACE_MAP_END_INHERITING(MediaStreamTrackConsumer)
NS_IMPL_CYCLE_COLLECTION_INHERITED(DOMMediaStream::PlaybackTrackListener,
MediaStreamTrackConsumer,
mStream)
NS_IMPL_CYCLE_COLLECTION_CLASS(DOMMediaStream)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(DOMMediaStream,
@ -323,6 +328,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(DOMMediaStream,
NS_IMPL_CYCLE_COLLECTION_UNLINK(mTracks)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsumersToKeepAlive)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mTrackSourceGetter)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPlaybackTrackListener)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPrincipal)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mVideoPrincipal)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
@ -334,6 +340,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(DOMMediaStream,
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTracks)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsumersToKeepAlive)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTrackSourceGetter)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPlaybackTrackListener)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrincipal)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVideoPrincipal)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
@ -366,6 +373,7 @@ DOMMediaStream::DOMMediaStream(nsPIDOMWindowInner* aWindow,
: mLogicalStreamStartTime(0), mWindow(aWindow),
mInputStream(nullptr), mOwnedStream(nullptr), mPlaybackStream(nullptr),
mTracksPendingRemoval(0), mTrackSourceGetter(aTrackSourceGetter),
mPlaybackTrackListener(MakeAndAddRef<PlaybackTrackListener>(this)),
mTracksCreated(false), mNotifiedOfMediaStreamGraphShutdown(false),
mActive(false)
{
@ -405,8 +413,12 @@ DOMMediaStream::Destroy()
for (const RefPtr<TrackPort>& info : mTracks) {
// We must remove ourselves from each track's principal change observer list
// before we die. CC may have cleared info->mTrack so guard against it.
if (info->GetTrack()) {
info->GetTrack()->RemovePrincipalChangeObserver(this);
MediaStreamTrack* track = info->GetTrack();
if (track) {
track->RemovePrincipalChangeObserver(this);
if (!track->Ended()) {
track->RemoveConsumer(mPlaybackTrackListener);
}
}
}
if (mPlaybackPort) {
@ -1268,6 +1280,7 @@ DOMMediaStream::NotifyTrackAdded(const RefPtr<MediaStreamTrack>& aTrack)
}
aTrack->AddPrincipalChangeObserver(this);
aTrack->AddConsumer(mPlaybackTrackListener);
for (int32_t i = mTrackListeners.Length() - 1; i >= 0; --i) {
mTrackListeners[i]->NotifyTrackAdded(aTrack);
@ -1297,6 +1310,7 @@ DOMMediaStream::NotifyTrackRemoved(const RefPtr<MediaStreamTrack>& aTrack)
{
MOZ_ASSERT(NS_IsMainThread());
aTrack->RemoveConsumer(mPlaybackTrackListener);
aTrack->RemovePrincipalChangeObserver(this);
for (int32_t i = mTrackListeners.Length() - 1; i >= 0; --i) {

Просмотреть файл

@ -635,6 +635,9 @@ protected:
class PlaybackStreamListener;
friend class PlaybackStreamListener;
class PlaybackTrackListener;
friend class PlaybackTrackListener;
/**
* Block a track in our playback stream. Calls NotifyPlaybackTrackBlocked()
* after the MediaStreamGraph has applied the block and the track is no longer
@ -704,6 +707,9 @@ protected:
// in this DOMMediaStream and notifications to mTrackListeners.
RefPtr<PlaybackStreamListener> mPlaybackListener;
// Listener tracking when live MediaStreamTracks in mTracks end.
RefPtr<PlaybackTrackListener> mPlaybackTrackListener;
nsTArray<nsAutoPtr<OnTracksAvailableCallback> > mRunOnTracksAvailable;
// Set to true after MediaStreamGraph has created tracks for mPlaybackStream.

Просмотреть файл

@ -53,6 +53,14 @@ MediaStreamTrackSource::ApplyConstraints(
return p.forget();
}
NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaStreamTrackConsumer)
NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaStreamTrackConsumer)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaStreamTrackConsumer)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTION_0(MediaStreamTrackConsumer)
/**
* PrincipalHandleListener monitors changes in PrincipalHandle of the media flowing
* through the MediaStreamGraph.
@ -171,6 +179,7 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(MediaStreamTrack)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MediaStreamTrack,
DOMEventTargetHelper)
tmp->Destroy();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsumers)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwningStream)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSource)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOriginalTrack)
@ -180,6 +189,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MediaStreamTrack,
DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsumers)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwningStream)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSource)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOriginalTrack)
@ -245,6 +255,8 @@ MediaStreamTrack::Stop()
Unused << p;
mReadyState = MediaStreamTrackState::Ended;
NotifyEnded();
}
void
@ -357,6 +369,18 @@ MediaStreamTrack::NotifyPrincipalHandleChanged(const PrincipalHandle& aNewPrinci
}
}
void
MediaStreamTrack::NotifyEnded()
{
MOZ_ASSERT(mReadyState == MediaStreamTrackState::Ended);
for (int32_t i = mConsumers.Length() - 1; i >= 0; --i) {
// Loop backwards by index in case the consumer removes itself in the
// callback.
mConsumers[i]->NotifyEnded(this);
}
}
bool
MediaStreamTrack::AddPrincipalChangeObserver(
PrincipalChangeObserver<MediaStreamTrack>* aObserver)
@ -371,6 +395,19 @@ MediaStreamTrack::RemovePrincipalChangeObserver(
return mPrincipalChangeObservers.RemoveElement(aObserver);
}
void
MediaStreamTrack::AddConsumer(MediaStreamTrackConsumer* aConsumer)
{
MOZ_ASSERT(!mConsumers.Contains(aConsumer));
mConsumers.AppendElement(aConsumer);
}
void
MediaStreamTrack::RemoveConsumer(MediaStreamTrackConsumer* aConsumer)
{
mConsumers.RemoveElement(aConsumer);
}
already_AddRefed<MediaStreamTrack>
MediaStreamTrack::Clone()
{
@ -423,6 +460,8 @@ MediaStreamTrack::OverrideEnded()
mReadyState = MediaStreamTrackState::Ended;
NotifyEnded();
DispatchTrustedEvent(NS_LITERAL_STRING("ended"));
}

Просмотреть файл

@ -230,6 +230,27 @@ protected:
const MediaSourceEnum mMediaSource;
};
/**
* Base class that consumers of a MediaStreamTrack can use to get notifications
* about state changes in the track.
*/
class MediaStreamTrackConsumer : public nsISupports
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(MediaStreamTrackConsumer)
/**
* Called when the track's readyState transitions to "ended".
* Unlike the "ended" event exposed to script this is called for any reason,
* including MediaStreamTrack::Stop().
*/
virtual void NotifyEnded(MediaStreamTrack* aTrack) {};
protected:
virtual ~MediaStreamTrackConsumer() {}
};
/**
* Class representing a track in a DOMMediaStream.
*/
@ -320,6 +341,12 @@ public:
*/
void NotifyPrincipalHandleChanged(const PrincipalHandle& aPrincipalHandle);
/**
* Called when this track's readyState transitions to "ended".
* Notifies all MediaStreamTrackConsumers that this track ended.
*/
void NotifyEnded();
/**
* Get this track's CORS mode.
*/
@ -363,6 +390,18 @@ public:
*/
bool RemovePrincipalChangeObserver(PrincipalChangeObserver<MediaStreamTrack>* aObserver);
/**
* Add a MediaStreamTrackConsumer to this track.
*
* Adding the same consumer multiple times is prohibited.
*/
void AddConsumer(MediaStreamTrackConsumer* aConsumer);
/**
* Remove an added MediaStreamTrackConsumer from this track.
*/
void RemoveConsumer(MediaStreamTrackConsumer* aConsumer);
/**
* Adds a MediaStreamTrackListener to the MediaStreamGraph representation of
* this track.
@ -429,6 +468,8 @@ protected:
nsTArray<PrincipalChangeObserver<MediaStreamTrack>*> mPrincipalChangeObservers;
nsTArray<RefPtr<MediaStreamTrackConsumer>> mConsumers;
RefPtr<DOMMediaStream> mOwningStream;
TrackID mTrackID;
TrackID mInputTrackID;