Bug 1404997 - P15. Move MSG::FinishStream logic to MediaStream. r?padenot
It is good practice for the MSG to now know the implementation details of the MediaStream.
Additionally, this will allow to make a thread-safe version later.,
MozReview-Commit-ID: CTacCLSeKRP
--- a/dom/media/MediaStreamGraph.cpp
+++ b/dom/media/MediaStreamGraph.cpp
@@ -68,41 +68,16 @@ MediaStreamGraphImpl::~MediaStreamGraphI
{
MOZ_ASSERT(mStreams.IsEmpty() && mSuspendedStreams.IsEmpty(),
"All streams should have been destroyed by messages from the main thread");
LOG(LogLevel::Debug, ("MediaStreamGraph %p destroyed", this));
LOG(LogLevel::Debug, ("MediaStreamGraphImpl::~MediaStreamGraphImpl"));
}
void
-MediaStreamGraphImpl::FinishStream(MediaStream* aStream)
-{
- MOZ_ASSERT(OnGraphThreadOrNotRunning());
- if (aStream->mFinished)
- return;
- LOG(LogLevel::Debug, ("MediaStream %p will finish", aStream));
-#ifdef DEBUG
- for (StreamTracks::TrackIter track(aStream->mTracks);
- !track.IsEnded(); track.Next()) {
- if (!track->IsEnded()) {
- LOG(LogLevel::Error,
- ("MediaStream %p will finish, but track %d has not ended.",
- aStream,
- track->GetID()));
- NS_ASSERTION(false, "Finished stream cannot contain live track");
- }
- }
-#endif
- aStream->mFinished = true;
- aStream->mTracks.AdvanceKnownTracksTime(STREAM_TIME_MAX);
-
- SetStreamOrderDirty();
-}
-
-void
MediaStreamGraphImpl::AddStreamGraphThread(MediaStream* aStream)
{
MOZ_ASSERT(OnGraphThreadOrNotRunning());
aStream->mTracksStartTime = mProcessedTime;
if (aStream->AsSourceStream()) {
SourceMediaStream* source = aStream->AsSourceStream();
TimeStamp currentTimeStamp = CurrentDriver()->GetCurrentTimeStamp();
@@ -167,28 +142,16 @@ MediaStreamGraphImpl::RemoveStreamGraphT
("Removed media stream %p from graph %p, count %zu",
aStream,
this,
mStreams.Length()));
NS_RELEASE(aStream); // probably destroying it
}
-void
-MediaStreamGraphImpl::ExtractPendingInput(SourceMediaStream* aStream,
- GraphTime aDesiredUpToTime,
- bool* aEnsureNextIteration)
-{
- MOZ_ASSERT(OnGraphThread());
-
- if (aStream->ExtractPendingInput(aDesiredUpToTime, aEnsureNextIteration)) {
- FinishStream(aStream);
- }
-}
-
StreamTime
MediaStreamGraphImpl::GraphTimeToStreamTimeWithBlocking(const MediaStream* aStream,
GraphTime aTime) const
{
MOZ_ASSERT(aTime <= mStateComputedTime,
"Don't ask about times where we haven't made blocking decisions yet");
return std::max<StreamTime>(0,
std::min(aTime, aStream->mStartBlocking) - aStream->mTracksStartTime);
@@ -1183,17 +1146,17 @@ MediaStreamGraphImpl::UpdateGraph(GraphT
UpdateStreamOrder();
bool ensureNextIteration = false;
// Grab pending stream input and compute blocking time
for (MediaStream* stream : mStreams) {
if (SourceMediaStream* is = stream->AsSourceStream()) {
- ExtractPendingInput(is, aEndBlockingDecisions, &ensureNextIteration);
+ is->ExtractPendingInput(aEndBlockingDecisions, &ensureNextIteration);
}
if (stream->mFinished) {
// The stream's not suspended, and since it's finished, underruns won't
// stop it playing out. So there's no blocking other than what we impose
// here.
GraphTime endTime = stream->GetStreamTracks().GetAllTracksEnd() +
stream->mTracksStartTime;
@@ -1957,17 +1920,37 @@ StreamTime
MediaStream::GraphTimeToStreamTimeWithBlocking(GraphTime aTime) const
{
return GraphImpl()->GraphTimeToStreamTimeWithBlocking(this, aTime);
}
void
MediaStream::FinishOnGraphThread()
{
- GraphImpl()->FinishStream(this);
+ if (mFinished) {
+ return;
+ }
+ LOG(LogLevel::Debug, ("MediaStream %p will finish", this));
+#ifdef DEBUG
+ for (StreamTracks::TrackIter track(mTracks); !track.IsEnded(); track.Next()) {
+ if (!track->IsEnded()) {
+ LOG(LogLevel::Error,
+ ("MediaStream %p will finish, but track %d has not ended.",
+ this,
+ track->GetID()));
+ NS_ASSERTION(false, "Finished stream cannot contain live track");
+ }
+ }
+#endif
+ mFinished = true;
+ mTracks.AdvanceKnownTracksTime(STREAM_TIME_MAX);
+
+ // Let the MSG knows that this stream can be destroyed if necessary to avoid
+ // unnecessarily processing it in the future.
+ GraphImpl()->SetStreamOrderDirty();
}
StreamTracks::Track*
MediaStream::FindTrack(TrackID aID) const
{
return mTracks.FindTrack(aID);
}
@@ -2705,17 +2688,17 @@ SourceMediaStream::SetPullEnabled(bool a
{
MutexAutoLock lock(mMutex);
mPullEnabled = aEnabled;
if (mPullEnabled && GraphImpl()) {
GraphImpl()->EnsureNextIteration();
}
}
-bool
+void
SourceMediaStream::ExtractPendingInput(StreamTime aDesiredUpToTime,
bool* aEnsureNextIteration)
{
MutexAutoLock lock(mMutex);
if (mPullEnabled && !mFinished && !mListeners.IsEmpty()) {
// Compute how much stream time we'll need assuming we don't block
// the stream at all.
StreamTime t = GraphTimeToStreamTime(aDesiredUpToTime);
@@ -2866,17 +2849,19 @@ SourceMediaStream::ExtractPendingInput(S
if (!mFinished) {
mTracks.AdvanceKnownTracksTime(mUpdateKnownTracksTime);
}
if (mTracks.GetEnd() > 0) {
mHasCurrentData = true;
}
- return finished;
+ if (finished) {
+ FinishOnGraphThread();
+ }
}
void
SourceMediaStream::AddTrackInternal(TrackID aID, TrackRate aRate, StreamTime aStart,
MediaSegment* aSegment, uint32_t aFlags)
{
MutexAutoLock lock(mMutex);
nsTArray<TrackData> *track_data = (aFlags & ADDTRACK_QUEUED) ?
@@ -3482,17 +3467,17 @@ void
ProcessedMediaStream::QueueFinish()
{
class Message : public ControlMessage {
public:
explicit Message(ProcessedMediaStream* aStream)
: ControlMessage(aStream) {}
void Run() override
{
- mStream->GraphImpl()->FinishStream(mStream);
+ mStream->FinishOnGraphThread();
}
};
GraphImpl()->AppendMessage(MakeUnique<Message>(this));
}
void
ProcessedMediaStream::QueueSetAutofinish(bool aAutofinish)
{
--- a/dom/media/MediaStreamGraph.h
+++ b/dom/media/MediaStreamGraph.h
@@ -500,17 +500,17 @@ public:
* Convert stream time to graph time. This assumes there is no blocking time
* to take account of, which is always true except between a stream
* having its blocking time calculated in UpdateGraph and its blocking time
* taken account of in UpdateCurrentTimeForStreams.
*/
GraphTime StreamTimeToGraphTime(StreamTime aTime) const;
bool IsFinishedOnGraphThread() const { return mFinished; }
- void FinishOnGraphThread();
+ virtual void FinishOnGraphThread();
bool HasCurrentData() const { return mHasCurrentData; }
/**
* Find track by track id.
*/
StreamTracks::Track* FindTrack(TrackID aID) const;
@@ -621,16 +621,17 @@ protected:
* Number of outstanding suspend operations on this stream. Stream is
* suspended when this is > 0.
*/
int32_t mSuspendedCount;
/**
* When true, this means the stream will be finished once all
* buffered data has been consumed.
+ * Only accessed on the graph thread
*/
bool mFinished;
/**
* When true, mFinished is true and we've played all the data in this stream
* and fired NotifyFinished notifications.
*/
bool mNotifiedFinished;
/**
@@ -694,19 +695,18 @@ public:
* MediaStreamGraph control loop. Pulling is initially disabled.
* Due to unavoidable race conditions, after a call to SetPullEnabled(false)
* it is still possible for a NotifyPull to occur.
*/
void SetPullEnabled(bool aEnabled);
/**
* Extract any state updates pending in the stream, and apply them.
- * Returns true if the stream is now finished.
*/
- bool ExtractPendingInput(StreamTime aDesiredUpToTime,
+ void ExtractPendingInput(StreamTime aDesiredUpToTime,
bool* aEnsureNextIteration);
/**
* These add/remove DirectListeners, which allow bypassing the graph and any
* synchronization delays for e.g. PeerConnection, which wants the data ASAP
* and lets the far-end handle sync and playout timing.
*/
void NotifyListenersEventImpl(MediaStreamGraphEvent aEvent);
@@ -759,16 +759,17 @@ public:
* Ignored if the track does not exist.
*/
void EndTrack(TrackID aID);
/**
* Indicate that no tracks will be added starting before time aKnownTime.
* aKnownTime must be >= its value at the last call to AdvanceKnownTracksTime.
*/
void AdvanceKnownTracksTime(StreamTime aKnownTime);
+ void AdvanceKnownTracksTimeWithLockHeld(StreamTime aKnownTime);
/**
* Indicate that this stream should enter the "finished" state. All tracks
* must have been ended via EndTrack. The finish time of the stream is
* when all tracks have ended.
*/
void FinishPendingWithLockHeld();
void FinishPending()
{
--- a/dom/media/MediaStreamGraphImpl.h
+++ b/dom/media/MediaStreamGraphImpl.h
@@ -274,22 +274,16 @@ public:
mMonitor.AssertCurrentThreadOwns();
mFrontMessageQueue.SwapElements(mBackMessageQueue);
}
/**
* Do all the processing and play the audio and video, from
* mProcessedTime to mStateComputedTime.
*/
void Process();
- /**
- * Extract any state updates pending in aStream, and apply them.
- */
- void ExtractPendingInput(SourceMediaStream* aStream,
- GraphTime aDesiredUpToTime,
- bool* aEnsureNextIteration);
/**
* For use during ProcessedMediaStream::ProcessInput() or
* MediaStreamListener callbacks, when graph state cannot be changed.
* Schedules |aMessage| to run after processing, at a time when graph state
* can be changed. Graph thread.
*/
void RunMessageAfterProcessing(UniquePtr<ControlMessage> aMessage);
@@ -389,17 +383,16 @@ public:
*/
void OpenAudioInputImpl(int aID,
AudioDataListener *aListener);
virtual nsresult OpenAudioInput(int aID,
AudioDataListener *aListener) override;
void CloseAudioInputImpl(AudioDataListener *aListener);
virtual void CloseAudioInput(AudioDataListener *aListener) override;
- void FinishStream(MediaStream* aStream);
/**
* Compute how much stream data we would like to buffer for aStream.
*/
StreamTime GetDesiredBufferEnd(MediaStream* aStream);
/**
* Returns true when there are no active streams.
*/
bool IsEmpty() const