From a4fbb9b8783643c3d76448c24b548e385a1d3b6d Mon Sep 17 00:00:00 2001 From: Andreas Pehrson Date: Wed, 18 Dec 2019 22:52:24 +0000 Subject: [PATCH] Bug 1586370 - Pass IterationEnd up to the graph rather than back-querying the driver. r=padenot This makes it simpler to maintain state in the GraphDriver in more complex cases, such as when an AudioCallbackDriver is backed by a fallback driver. Differential Revision: https://phabricator.services.mozilla.com/D57553 --HG-- extra : moz-landing-system : lando --- dom/media/GraphDriver.cpp | 12 +++++++----- dom/media/GraphDriver.h | 11 ++++------- dom/media/GraphRunner.cpp | 7 ++++--- dom/media/GraphRunner.h | 13 +++++++++---- dom/media/MediaTrackGraph.cpp | 14 +++++++++----- dom/media/MediaTrackGraphImpl.h | 9 +++++++-- dom/media/gtest/TestAudioCallbackDriver.cpp | 2 +- 7 files changed, 41 insertions(+), 27 deletions(-) diff --git a/dom/media/GraphDriver.cpp b/dom/media/GraphDriver.cpp index 0efc804de2c6..3a99c72a8b66 100644 --- a/dom/media/GraphDriver.cpp +++ b/dom/media/GraphDriver.cpp @@ -167,7 +167,7 @@ bool SystemClockDriver::IsFallback() { return mIsFallback; } void ThreadedDriver::RunThread() { mThreadRunning = true; while (true) { - mIterationStart = IterationEnd(); + mIterationStart = mIterationEnd; mIterationEnd += GetIntervalForIteration(); if (mStateComputedTime < mIterationEnd) { @@ -202,7 +202,8 @@ void ThreadedDriver::RunThread() { (long)nextStateComputedTime)); mStateComputedTime = nextStateComputedTime; - IterationResult result = Graph()->OneIteration(mStateComputedTime, nullptr); + IterationResult result = + Graph()->OneIteration(mStateComputedTime, mIterationEnd, nullptr); if (result.IsStop()) { // Signal that we're done stopping. @@ -231,7 +232,7 @@ MediaTime SystemClockDriver::GetIntervalForIteration() { MOZ_LOG(gMediaTrackGraphLog, LogLevel::Verbose, ("%p: Updating current time to %f (real %f, StateComputedTime() %f)", - Graph(), MediaTimeToSeconds(IterationEnd() + interval), + Graph(), MediaTimeToSeconds(mIterationEnd + interval), (now - mInitialTimeStamp).ToSeconds(), MediaTimeToSeconds(mStateComputedTime))); @@ -726,8 +727,9 @@ long AudioCallbackDriver::DataCallback(const AudioDataValue* aInputBuffer, bool iterate = mBuffer.Available(); IterationResult result = - iterate ? Graph()->OneIteration(nextStateComputedTime, &mMixer) - : IterationResult::CreateStillProcessing(); + iterate + ? Graph()->OneIteration(nextStateComputedTime, mIterationEnd, &mMixer) + : IterationResult::CreateStillProcessing(); if (iterate) { // We totally filled the buffer (and mScratchBuffer isn't empty). // We don't need to run an iteration and if we do so we may overflow. diff --git a/dom/media/GraphDriver.h b/dom/media/GraphDriver.h index edd7a08321e2..8ee8a67295ee 100644 --- a/dom/media/GraphDriver.h +++ b/dom/media/GraphDriver.h @@ -178,7 +178,8 @@ struct GraphInterface { virtual void DeviceChanged() = 0; /* Called by GraphDriver to iterate the graph. Output from the graph gets * mixed into aMixer, if it is non-null. */ - virtual IterationResult OneIteration(GraphTime aStateEnd, + virtual IterationResult OneIteration(GraphTime aStateComputedEnd, + GraphTime aIterationEnd, AudioMixer* aMixer) = 0; #ifdef DEBUG /* True if we're on aDriver's thread, or if we're on mGraphRunner's thread @@ -271,8 +272,6 @@ class GraphDriver { GraphDriver* PreviousDriver(); void SetPreviousDriver(GraphDriver* aPreviousDriver); - GraphTime IterationEnd() { return mIterationEnd; } - virtual AudioCallbackDriver* AsAudioCallbackDriver() { return nullptr; } virtual OfflineClockDriver* AsOfflineClockDriver() { return nullptr; } @@ -314,11 +313,9 @@ class GraphDriver { } protected: - // Time of the start of this graph iteration. This must be accessed while - // having the monitor. + // Time of the start of this graph iteration. GraphTime mIterationStart = 0; - // Time of the end of this graph iteration. This must be accessed while having - // the monitor. + // Time of the end of this graph iteration. GraphTime mIterationEnd = 0; // Time until which the graph has processed data. GraphTime mStateComputedTime = 0; diff --git a/dom/media/GraphRunner.cpp b/dom/media/GraphRunner.cpp index 8527114283a0..e4462ad09958 100644 --- a/dom/media/GraphRunner.cpp +++ b/dom/media/GraphRunner.cpp @@ -56,13 +56,13 @@ void GraphRunner::Shutdown() { mThread->Shutdown(); } -auto GraphRunner::OneIteration(GraphTime aStateEnd, AudioMixer* aMixer) - -> IterationResult { +auto GraphRunner::OneIteration(GraphTime aStateEnd, GraphTime aIterationEnd, + AudioMixer* aMixer) -> IterationResult { TRACE_AUDIO_CALLBACK(); MonitorAutoLock lock(mMonitor); MOZ_ASSERT(mThreadState == ThreadState::Wait); - mIterationState = Some(IterationState(aStateEnd, aMixer)); + mIterationState = Some(IterationState(aStateEnd, aIterationEnd, aMixer)); #ifdef DEBUG if (auto audioDriver = mGraph->CurrentDriver()->AsAudioCallbackDriver()) { @@ -109,6 +109,7 @@ NS_IMETHODIMP GraphRunner::Run() { MOZ_DIAGNOSTIC_ASSERT(mIterationState.isSome()); TRACE(); mIterationResult = mGraph->OneIterationImpl(mIterationState->StateEnd(), + mIterationState->IterationEnd(), mIterationState->Mixer()); // Signal that mIterationResult was updated mThreadState = ThreadState::Wait; diff --git a/dom/media/GraphRunner.h b/dom/media/GraphRunner.h index b4966807b125..e5d0cb9379af 100644 --- a/dom/media/GraphRunner.h +++ b/dom/media/GraphRunner.h @@ -32,10 +32,11 @@ class GraphRunner final : public Runnable { MOZ_CAN_RUN_SCRIPT void Shutdown(); /** - * Signals one iteration of mGraph. Hands aStateEnd over to mThread and runs + * Signals one iteration of mGraph. Hands state over to mThread and runs * the iteration there. */ - IterationResult OneIteration(GraphTime aStateEnd, AudioMixer* aMixer); + IterationResult OneIteration(GraphTime aStateEnd, GraphTime aIterationEnd, + AudioMixer* aMixer); /** * Runs mGraph until it shuts down. @@ -62,17 +63,21 @@ class GraphRunner final : public Runnable { class IterationState { GraphTime mStateEnd; + GraphTime mIterationEnd; AudioMixer* MOZ_NON_OWNING_REF mMixer; public: - IterationState(GraphTime aStateEnd, AudioMixer* aMixer) - : mStateEnd(aStateEnd), mMixer(aMixer) {} + IterationState(GraphTime aStateEnd, GraphTime aIterationEnd, + AudioMixer* aMixer) + : mStateEnd(aStateEnd), mIterationEnd(aIterationEnd), mMixer(aMixer) {} IterationState& operator=(const IterationState& aOther) { mStateEnd = aOther.mStateEnd; + mIterationEnd = aOther.mIterationEnd; mMixer = aOther.mMixer; return *this; } GraphTime StateEnd() const { return mStateEnd; } + GraphTime IterationEnd() const { return mIterationEnd; } AudioMixer* Mixer() const { return mMixer; } }; diff --git a/dom/media/MediaTrackGraph.cpp b/dom/media/MediaTrackGraph.cpp index 6cf7f6db70ba..ef35b949536b 100644 --- a/dom/media/MediaTrackGraph.cpp +++ b/dom/media/MediaTrackGraph.cpp @@ -126,7 +126,7 @@ TrackTime MediaTrackGraphImpl::GraphTimeToTrackTimeWithBlocking( GraphTime MediaTrackGraphImpl::IterationEnd() const { MOZ_ASSERT(OnGraphThread()); - return CurrentDriver()->IterationEnd(); + return mIterationEndTime; } void MediaTrackGraphImpl::UpdateCurrentTimeForTracks( @@ -1302,20 +1302,24 @@ bool MediaTrackGraphImpl::UpdateMainThreadState() { return true; } -auto MediaTrackGraphImpl::OneIteration(GraphTime aStateEnd, AudioMixer* aMixer) - -> IterationResult { +auto MediaTrackGraphImpl::OneIteration(GraphTime aStateEnd, + GraphTime aIterationEnd, + AudioMixer* aMixer) -> IterationResult { if (mGraphRunner) { - return mGraphRunner->OneIteration(aStateEnd, aMixer); + return mGraphRunner->OneIteration(aStateEnd, aIterationEnd, aMixer); } - return OneIterationImpl(aStateEnd, aMixer); + return OneIterationImpl(aStateEnd, aIterationEnd, aMixer); } auto MediaTrackGraphImpl::OneIterationImpl(GraphTime aStateEnd, + GraphTime aIterationEnd, AudioMixer* aMixer) -> IterationResult { TRACE_AUDIO_CALLBACK(); + mIterationEndTime = aIterationEnd; + if (SoftRealTimeLimitReached()) { DemoteThreadFromRealTime(); } diff --git a/dom/media/MediaTrackGraphImpl.h b/dom/media/MediaTrackGraphImpl.h index 831066186aa0..4f9f95e9ec06 100644 --- a/dom/media/MediaTrackGraphImpl.h +++ b/dom/media/MediaTrackGraphImpl.h @@ -216,13 +216,14 @@ class MediaTrackGraphImpl : public MediaTrackGraph, * OneIterationImpl is called directly. Output from the graph gets mixed into * aMixer, if it is non-null. */ - IterationResult OneIteration(GraphTime aStateEnd, + IterationResult OneIteration(GraphTime aStateEnd, GraphTime aIterationEnd, AudioMixer* aMixer) override; /** * Returns true if this MediaTrackGraph should keep running */ - IterationResult OneIterationImpl(GraphTime aStateEnd, AudioMixer* aMixer); + IterationResult OneIterationImpl(GraphTime aStateEnd, GraphTime aIterationEnd, + AudioMixer* aMixer); /** * Called from the driver, when the graph thread is about to stop, to tell @@ -725,6 +726,10 @@ class MediaTrackGraphImpl : public MediaTrackGraph, * at this time. This is behind mStateComputedTime during processing. */ GraphTime mProcessedTime = 0; + /** + * The end of the current iteration. Only access on the graph thread. + */ + GraphTime mIterationEndTime = 0; /** * The graph should stop processing at this time. */ diff --git a/dom/media/gtest/TestAudioCallbackDriver.cpp b/dom/media/gtest/TestAudioCallbackDriver.cpp index e7a811779752..bd295cfc6e15 100644 --- a/dom/media/gtest/TestAudioCallbackDriver.cpp +++ b/dom/media/gtest/TestAudioCallbackDriver.cpp @@ -30,7 +30,7 @@ class MockGraphInterface : public GraphInterface { MOCK_METHOD0(DeviceChanged, void()); /* OneIteration cannot be mocked because IterationResult is non-memmovable and * cannot be passed as a parameter, which GMock does internally. */ - IterationResult OneIteration(GraphTime, AudioMixer*) { + IterationResult OneIteration(GraphTime, GraphTime, AudioMixer*) { return mKeepProcessing ? IterationResult::CreateStillProcessing() : IterationResult::CreateStop( NS_NewRunnableFunction(__func__, [] {}));