author | Andrea Marchesini <amarchesini@mozilla.com> |
Mon, 11 May 2015 15:07:38 +0100 | |
changeset 243365 | 4c5f304c7451b8e9e14baba2677ce54f95bdfd87 |
parent 243364 | bad7af6079e93cdac37461f8e55ca0a7a528230b |
child 243366 | f282df3f34b757fb71920396b0c9c2094bc24a1b |
push id | 28738 |
push user | cbook@mozilla.com |
push date | Tue, 12 May 2015 14:11:31 +0000 |
treeherder | mozilla-central@bedce1b405a3 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | padenot |
bugs | 1161946 |
milestone | 40.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
dom/media/MediaStreamGraph.cpp | file | annotate | diff | comparison | revisions | |
dom/media/MediaStreamGraph.h | file | annotate | diff | comparison | revisions |
--- a/dom/media/MediaStreamGraph.cpp +++ b/dom/media/MediaStreamGraph.cpp @@ -1543,19 +1543,17 @@ MediaStreamGraphImpl::ApplyStreamUpdate( stream->mMainThreadCurrentTime = aUpdate->mNextMainThreadCurrentTime; stream->mMainThreadFinished = aUpdate->mNextMainThreadFinished; if (stream->ShouldNotifyStreamFinished()) { if (stream->mWrapper) { stream->mWrapper->NotifyStreamFinished(); } - for (int32_t i = stream->mMainThreadListeners.Length() - 1; i >= 0; --i) { - stream->mMainThreadListeners[i]->NotifyMainThreadStreamFinished(); - } + stream->NotifyMainThreadListeners(); } } void MediaStreamGraphImpl::ForceShutDown() { NS_ASSERTION(NS_IsMainThread(), "Must be called on main thread"); STREAM_LOG(PR_LOG_DEBUG, ("MediaStreamGraph %p ForceShutdown", this)); @@ -2404,16 +2402,60 @@ MediaStream::ApplyTrackDisabling(TrackID } aSegment->ReplaceWithDisabled(); if (aRawSegment) { aRawSegment->ReplaceWithDisabled(); } } void +MediaStream::AddMainThreadListener(MainThreadMediaStreamListener* aListener) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aListener); + MOZ_ASSERT(!mMainThreadListeners.Contains(aListener)); + + mMainThreadListeners.AppendElement(aListener); + + // If we have to send the notification or we have a runnable that will do it, + // let finish here. + if (!mFinishedNotificationSent || mNotificationMainThreadRunnable) { + return; + } + + class NotifyRunnable final : public nsRunnable + { + public: + NotifyRunnable(MediaStream* aStream) + : mStream(aStream) + {} + + NS_IMETHOD Run() override + { + MOZ_ASSERT(NS_IsMainThread()); + mStream->mNotificationMainThreadRunnable = nullptr; + mStream->NotifyMainThreadListeners(); + return NS_OK; + } + + private: + ~NotifyRunnable() {} + + nsRefPtr<MediaStream> mStream; + }; + + nsRefPtr<nsRunnable> runnable = new NotifyRunnable(this); + if (NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(runnable)))) { + return; + } + + mNotificationMainThreadRunnable = runnable; +} + +void SourceMediaStream::DestroyImpl() { // Hold mMutex while mGraph is reset so that other threads holding mMutex // can null-check know that the graph will not destroyed. MutexAutoLock lock(mMutex); MediaStream::DestroyImpl(); }
--- a/dom/media/MediaStreamGraph.h +++ b/dom/media/MediaStreamGraph.h @@ -368,30 +368,29 @@ public: void BlockStreamIfNeeded(); void UnblockStreamIfNeeded(); // Events will be dispatched by calling methods of aListener. virtual void AddListener(MediaStreamListener* aListener); virtual void RemoveListener(MediaStreamListener* aListener); // A disabled track has video replaced by black, and audio replaced by // silence. void SetTrackEnabled(TrackID aTrackID, bool aEnabled); - // Events will be dispatched by calling methods of aListener. It is the + + // Finish event will be notified by calling methods of aListener. It is the // responsibility of the caller to remove aListener before it is destroyed. - void AddMainThreadListener(MainThreadMediaStreamListener* aListener) - { - NS_ASSERTION(NS_IsMainThread(), "Call only on main thread"); - mMainThreadListeners.AppendElement(aListener); - } + void AddMainThreadListener(MainThreadMediaStreamListener* aListener); // It's safe to call this even if aListener is not currently a listener; // the call will be ignored. void RemoveMainThreadListener(MainThreadMediaStreamListener* aListener) { - NS_ASSERTION(NS_IsMainThread(), "Call only on main thread"); + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aListener); mMainThreadListeners.RemoveElement(aListener); } + /** * Ensure a runnable will run on the main thread after running all pending * updates that were sent from the graph thread or will be sent before the * graph thread receives the next graph update. * * If the graph has been shut down or destroyed, then the runnable will be * dispatched to the event queue immediately. If the graph is non-realtime * and has not started, then the runnable will be run @@ -592,16 +591,26 @@ protected: mBufferStartTime += aBlockedTime; mGraphUpdateIndices.InsertTimeAtStart(aBlockedTime); mGraphUpdateIndices.AdvanceCurrentTime(aCurrentTime); mExplicitBlockerCount.AdvanceCurrentTime(aCurrentTime); mBuffer.ForgetUpTo(aCurrentTime - mBufferStartTime); } + void NotifyMainThreadListeners() + { + NS_ASSERTION(NS_IsMainThread(), "Call only on main thread"); + + for (int32_t i = mMainThreadListeners.Length() - 1; i >= 0; --i) { + mMainThreadListeners[i]->NotifyMainThreadStreamFinished(); + } + mMainThreadListeners.Clear(); + } + bool ShouldNotifyStreamFinished() { NS_ASSERTION(NS_IsMainThread(), "Call only on main thread"); if (!mMainThreadFinished || mFinishedNotificationSent) { return false; } mFinishedNotificationSent = true; @@ -631,16 +640,17 @@ protected: // We record the last played video frame to avoid redundant setting // of the current video frame. VideoFrame mLastPlayedVideoFrame; // The number of times this stream has been explicitly blocked by the control // API, minus the number of times it has been explicitly unblocked. TimeVarying<GraphTime,uint32_t,0> mExplicitBlockerCount; nsTArray<nsRefPtr<MediaStreamListener> > mListeners; nsTArray<MainThreadMediaStreamListener*> mMainThreadListeners; + nsRefPtr<nsRunnable> mNotificationMainThreadRunnable; nsTArray<TrackID> mDisabledTrackIDs; // Precomputed blocking status (over GraphTime). // This is only valid between the graph's mCurrentTime and // mStateComputedTime. The stream is considered to have // not been blocked before mCurrentTime (its mBufferStartTime is increased // as necessary to account for that time instead) --- this avoids us having to // record the entire history of the stream's blocking-ness in mBlocked.