From 8ee8a34873232a80bd5a3574484ebef5d14605bc Mon Sep 17 00:00:00 2001 From: Andreas Pehrson Date: Thu, 3 Mar 2016 17:27:59 +0100 Subject: [PATCH] Bug 1208371 - Add a MediaStreamTrackListener to MediaStreamGraph. r=roc MozReview-Commit-ID: 6KHzimw9kiP --HG-- extra : rebase_source : 78e7f4b4bf18eaf390ee09c08f6f5c19d9f24d65 --- dom/media/MediaStreamGraph.cpp | 74 +++++++++++++++++++++++++++++++++- dom/media/MediaStreamGraph.h | 54 +++++++++++++++++++++++++ dom/media/MediaStreamTrack.cpp | 19 +++++++++ dom/media/MediaStreamTrack.h | 13 ++++++ dom/media/TrackUnionStream.cpp | 11 +++++ 5 files changed, 169 insertions(+), 2 deletions(-) diff --git a/dom/media/MediaStreamGraph.cpp b/dom/media/MediaStreamGraph.cpp index b525f6460307..ddc442a4ca0a 100644 --- a/dom/media/MediaStreamGraph.cpp +++ b/dom/media/MediaStreamGraph.cpp @@ -183,12 +183,21 @@ MediaStreamGraphImpl::ExtractPendingInput(SourceMediaStream* aStream, for (int32_t i = aStream->mUpdateTracks.Length() - 1; i >= 0; --i) { SourceMediaStream::TrackData* data = &aStream->mUpdateTracks[i]; aStream->ApplyTrackDisabling(data->mID, data->mData); + StreamTime offset = (data->mCommands & SourceMediaStream::TRACK_CREATE) + ? data->mStart : aStream->mBuffer.FindTrack(data->mID)->GetSegment()->GetDuration(); for (MediaStreamListener* l : aStream->mListeners) { - StreamTime offset = (data->mCommands & SourceMediaStream::TRACK_CREATE) - ? data->mStart : aStream->mBuffer.FindTrack(data->mID)->GetSegment()->GetDuration(); l->NotifyQueuedTrackChanges(this, data->mID, offset, data->mCommands, *data->mData); } + for (TrackBound& b : aStream->mTrackListeners) { + if (b.mTrackID != data->mID) { + continue; + } + b.mListener->NotifyQueuedChanges(this, offset, *data->mData); + if (data->mCommands & SourceMediaStream::TRACK_END) { + b.mListener->NotifyEnded(); + } + } if (data->mCommands & SourceMediaStream::TRACK_CREATE) { MediaSegment* segment = data->mData.forget(); STREAM_LOG(LogLevel::Debug, ("SourceMediaStream %p creating track %d, start %lld, initial end %lld", @@ -2264,6 +2273,67 @@ MediaStream::RemoveListener(MediaStreamListener* aListener) } } +void +MediaStream::AddTrackListenerImpl(already_AddRefed aListener, + TrackID aTrackID) +{ + TrackBound* l = mTrackListeners.AppendElement(); + l->mListener = aListener; + l->mTrackID = aTrackID; +} + +void +MediaStream::AddTrackListener(MediaStreamTrackListener* aListener, + TrackID aTrackID) +{ + class Message : public ControlMessage { + public: + Message(MediaStream* aStream, MediaStreamTrackListener* aListener, + TrackID aTrackID) : + ControlMessage(aStream), mListener(aListener), mTrackID(aTrackID) {} + virtual void Run() + { + mStream->AddTrackListenerImpl(mListener.forget(), mTrackID); + } + RefPtr mListener; + TrackID mTrackID; + }; + GraphImpl()->AppendMessage(MakeUnique(this, aListener, aTrackID)); +} + +void +MediaStream::RemoveTrackListenerImpl(MediaStreamTrackListener* aListener, + TrackID aTrackID) +{ + for (size_t i = 0; i < mTrackListeners.Length(); ++i) { + if (mTrackListeners[i].mListener == aListener && + mTrackListeners[i].mTrackID == aTrackID) { + mTrackListeners[i].mListener->NotifyRemoved(); + mTrackListeners.RemoveElementAt(i); + return; + } + } +} + +void +MediaStream::RemoveTrackListener(MediaStreamTrackListener* aListener, + TrackID aTrackID) +{ + class Message : public ControlMessage { + public: + Message(MediaStream* aStream, MediaStreamTrackListener* aListener, + TrackID aTrackID) : + ControlMessage(aStream), mListener(aListener), mTrackID(aTrackID) {} + virtual void Run() + { + mStream->RemoveTrackListenerImpl(mListener, mTrackID); + } + RefPtr mListener; + TrackID mTrackID; + }; + GraphImpl()->AppendMessage(MakeUnique(this, aListener, aTrackID)); +} + void MediaStream::RunAfterPendingUpdates(already_AddRefed aRunnable) { diff --git a/dom/media/MediaStreamGraph.h b/dom/media/MediaStreamGraph.h index 580dbb85b95f..83a7f1158c94 100644 --- a/dom/media/MediaStreamGraph.h +++ b/dom/media/MediaStreamGraph.h @@ -216,6 +216,41 @@ public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AudioDataListener) }; +/** + * This is a base class for media graph thread listener callbacks locked to + * specific tracks. Override methods to be notified of audio or video data or + * changes in track state. + * + * All notification methods are called from the media graph thread. Overriders + * of these methods are responsible for all synchronization. Beware! + * These methods are called without the media graph monitor held, so + * reentry into media graph methods is possible, although very much discouraged! + * You should do something non-blocking and non-reentrant (e.g. dispatch an + * event to some thread) and return. + * The listener is not allowed to add/remove any listeners from the parent + * stream. + * + * If a listener is attached to a track that has already ended, we guarantee + * to call NotifyEnded. + */ +class MediaStreamTrackListener +{ + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaStreamTrackListener) + +public: + virtual void NotifyQueuedChanges(MediaStreamGraph* aGraph, + StreamTime aTrackOffset, + const MediaSegment& aQueuedMedia) {} + + virtual void NotifyEnded() {} + + virtual void NotifyRemoved() {} + +protected: + virtual ~MediaStreamTrackListener() {} +}; + + /** * This is a base class for media graph thread listener direct callbacks * from within AppendToTrack(). Note that your regular listener will @@ -278,6 +313,16 @@ class AudioNodeExternalInputStream; class AudioNodeStream; class CameraPreviewMediaStream; +/** + * Helper struct for binding a track listener to a specific TrackID. + */ +template +struct TrackBound +{ + RefPtr mListener; + TrackID mTrackID; +}; + /** * A stream of synchronized audio and video data. All (not blocked) streams * progress at the same rate --- "real time". Streams cannot seek. The only @@ -400,6 +445,10 @@ public: // Events will be dispatched by calling methods of aListener. virtual void AddListener(MediaStreamListener* aListener); virtual void RemoveListener(MediaStreamListener* aListener); + virtual void AddTrackListener(MediaStreamTrackListener* aListener, + TrackID aTrackID); + virtual void RemoveTrackListener(MediaStreamTrackListener* aListener, + TrackID aTrackID); // A disabled track has video replaced by black, and audio replaced by // silence. void SetTrackEnabled(TrackID aTrackID, bool aEnabled); @@ -496,6 +545,10 @@ public: void AddListenerImpl(already_AddRefed aListener); void RemoveListenerImpl(MediaStreamListener* aListener); void RemoveAllListenersImpl(); + virtual void AddTrackListenerImpl(already_AddRefed aListener, + TrackID aTrackID); + virtual void RemoveTrackListenerImpl(MediaStreamTrackListener* aListener, + TrackID aTrackID); virtual void SetTrackEnabledImpl(TrackID aTrackID, bool aEnabled); void AddConsumer(MediaInputPort* aPort) @@ -649,6 +702,7 @@ protected: // with a different frame id. VideoFrame mLastPlayedVideoFrame; nsTArray > mListeners; + nsTArray> mTrackListeners; nsTArray mMainThreadListeners; nsTArray mDisabledTrackIDs; diff --git a/dom/media/MediaStreamTrack.cpp b/dom/media/MediaStreamTrack.cpp index 063909d3dbe0..f77ef999f0c2 100644 --- a/dom/media/MediaStreamTrack.cpp +++ b/dom/media/MediaStreamTrack.cpp @@ -6,6 +6,7 @@ #include "MediaStreamTrack.h" #include "DOMMediaStream.h" +#include "MediaStreamGraph.h" #include "nsIUUIDGenerator.h" #include "nsServiceManagerUtils.h" @@ -197,5 +198,23 @@ MediaStreamTrack::GetOwnedStream() return GetStream()->GetOwnedStream(); } +void +MediaStreamTrack::AddListener(MediaStreamTrackListener* aListener) +{ + LOG(LogLevel::Debug, ("MediaStreamTrack %p adding listener %p", + this, aListener)); + + GetOwnedStream()->AddTrackListener(aListener, mTrackID); +} + +void +MediaStreamTrack::RemoveListener(MediaStreamTrackListener* aListener) +{ + LOG(LogLevel::Debug, ("MediaStreamTrack %p removing listener %p", + this, aListener)); + + GetOwnedStream()->RemoveTrackListener(aListener, mTrackID); +} + } // namespace dom } // namespace mozilla diff --git a/dom/media/MediaStreamTrack.h b/dom/media/MediaStreamTrack.h index 73652d10aa30..1015073f066c 100644 --- a/dom/media/MediaStreamTrack.h +++ b/dom/media/MediaStreamTrack.h @@ -19,6 +19,7 @@ class DOMMediaStream; class MediaEnginePhotoCallback; class MediaStream; class MediaStreamGraph; +class MediaStreamTrackListener; class ProcessedMediaStream; namespace dom { @@ -254,6 +255,18 @@ public: */ bool RemovePrincipalChangeObserver(PrincipalChangeObserver* aObserver); + /** + * Adds a MediaStreamTrackListener to the MediaStreamGraph representation of + * this track. + */ + void AddListener(MediaStreamTrackListener* aListener); + + /** + * Removes a MediaStreamTrackListener from the MediaStreamGraph representation + * of this track. + */ + void RemoveListener(MediaStreamTrackListener* aListener); + protected: virtual ~MediaStreamTrack(); diff --git a/dom/media/TrackUnionStream.cpp b/dom/media/TrackUnionStream.cpp index 1c86f2d84492..e11537235327 100644 --- a/dom/media/TrackUnionStream.cpp +++ b/dom/media/TrackUnionStream.cpp @@ -239,6 +239,11 @@ TrackUnionStream::TrackUnionStream(DOMMediaStream* aWrapper) : mTrackMap[aIndex].mInputPort->GetSource(), mTrackMap[aIndex].mInputTrackID); } + for (TrackBound& b : mTrackListeners) { + if (b.mTrackID == outputTrack->GetID()) { + b.mListener->NotifyEnded(); + } + } outputTrack->SetEnded(); } @@ -300,6 +305,12 @@ TrackUnionStream::TrackUnionStream(DOMMediaStream* aWrapper) : l->NotifyQueuedTrackChanges(Graph(), outputTrack->GetID(), outputStart, 0, *segment); } + for (TrackBound& b : mTrackListeners) { + if (b.mTrackID != outputTrack->GetID()) { + continue; + } + b.mListener->NotifyQueuedChanges(Graph(), outputStart, *segment); + } outputTrack->GetSegment()->AppendFrom(segment); } }