diff --git a/dom/media/GraphDriver.cpp b/dom/media/GraphDriver.cpp index 05da60b0392b..c34fbd02d519 100644 --- a/dom/media/GraphDriver.cpp +++ b/dom/media/GraphDriver.cpp @@ -45,7 +45,6 @@ struct AutoProfilerUnregisterThread GraphDriver::GraphDriver(MediaStreamGraphImpl* aGraphImpl) : mIterationStart(0), mIterationEnd(0), - mStateComputedTime(0), mGraphImpl(aGraphImpl), mWaitState(WAITSTATE_RUNNING), mCurrentTimeStamp(TimeStamp::Now()), @@ -55,8 +54,7 @@ GraphDriver::GraphDriver(MediaStreamGraphImpl* aGraphImpl) void GraphDriver::SetGraphTime(GraphDriver* aPreviousDriver, GraphTime aLastSwitchNextIterationStart, - GraphTime aLastSwitchNextIterationEnd, - GraphTime aLastSwitchStateComputedTime) + GraphTime aLastSwitchNextIterationEnd) { // We set mIterationEnd here, because the first thing a driver do when it // does an iteration is to update graph times, so we are in fact setting @@ -64,7 +62,6 @@ void GraphDriver::SetGraphTime(GraphDriver* aPreviousDriver, // iteration. mIterationStart = aLastSwitchNextIterationStart; mIterationEnd = aLastSwitchNextIterationEnd; - mStateComputedTime = aLastSwitchStateComputedTime; STREAM_LOG(LogLevel::Debug, ("Setting previous driver: %p (%s)", aPreviousDriver, aPreviousDriver->AsAudioCallbackDriver() ? "AudioCallbackDriver" : "SystemClockDriver")); MOZ_ASSERT(!mPreviousDriver); @@ -99,17 +96,10 @@ void GraphDriver::EnsureImmediateWakeUpLocked() mGraphImpl->GetMonitor().Notify(); } -void GraphDriver::UpdateStateComputedTime(GraphTime aStateComputedTime) +GraphTime +GraphDriver::StateComputedTime() const { - MOZ_ASSERT(aStateComputedTime >= mIterationEnd); - // The next state computed time can be the same as the previous, here: it - // means the driver would be have been blocking indefinitly, but the graph has - // been woken up right after having been to sleep. - if (aStateComputedTime < mStateComputedTime) { - printf("State time can't go backward %ld < %ld.\n", static_cast(aStateComputedTime), static_cast(mStateComputedTime)); - } - - mStateComputedTime = aStateComputedTime; + return mGraphImpl->mStateComputedTime; } void GraphDriver::EnsureNextIteration() @@ -238,8 +228,7 @@ ThreadedDriver::Revive() // loop again. MonitorAutoLock mon(mGraphImpl->GetMonitor()); if (mNextDriver) { - mNextDriver->SetGraphTime(this, mIterationStart, mIterationEnd, - mStateComputedTime); + mNextDriver->SetGraphTime(this, mIterationStart, mIterationEnd); mGraphImpl->SetCurrentDriver(mNextDriver); mNextDriver->Start(); } else { @@ -280,9 +269,10 @@ ThreadedDriver::RunThread() mIterationStart = IterationEnd(); mIterationEnd += GetIntervalForIteration(); - if (mStateComputedTime < mIterationEnd) { + GraphTime stateComputedTime = StateComputedTime(); + if (stateComputedTime < mIterationEnd) { STREAM_LOG(LogLevel::Warning, ("Media graph global underrun detected")); - mIterationEnd = mStateComputedTime; + mIterationEnd = stateComputedTime; } if (mIterationStart >= mIterationEnd) { @@ -298,19 +288,18 @@ ThreadedDriver::RunThread() STREAM_LOG(LogLevel::Debug, ("interval[%ld; %ld] state[%ld; %ld]", (long)mIterationStart, (long)mIterationEnd, - (long)mStateComputedTime, (long)nextStateComputedTime)); + (long)stateComputedTime, (long)nextStateComputedTime)); mGraphImpl->mFlushSourcesNow = mGraphImpl->mFlushSourcesOnNextIteration; mGraphImpl->mFlushSourcesOnNextIteration = false; stillProcessing = mGraphImpl->OneIteration(mIterationStart, mIterationEnd, - StateComputedTime(), + stateComputedTime, nextStateComputedTime); if (mNextDriver && stillProcessing) { STREAM_LOG(LogLevel::Debug, ("Switching to AudioCallbackDriver")); - mNextDriver->SetGraphTime(this, mIterationStart, mIterationEnd, - mStateComputedTime); + mNextDriver->SetGraphTime(this, mIterationStart, mIterationEnd); mGraphImpl->SetCurrentDriver(mNextDriver); mNextDriver->Start(); return; @@ -327,7 +316,7 @@ SystemClockDriver::GetIntervalForIteration() mCurrentTimeStamp = now; MOZ_LOG(gMediaStreamGraphLog, LogLevel::Verbose, - ("Updating current time to %f (real %f, mStateComputedTime %f)", + ("Updating current time to %f (real %f, StateComputedTime() %f)", mGraphImpl->MediaTimeToSeconds(IterationEnd() + interval), (now - mInitialTimeStamp).ToSeconds(), mGraphImpl->MediaTimeToSeconds(StateComputedTime()))); @@ -573,8 +562,7 @@ AudioCallbackDriver::Init() NS_WARNING("Could not create a cubeb stream for MediaStreamGraph, falling back to a SystemClockDriver"); // Fall back to a driver using a normal thread. mNextDriver = new SystemClockDriver(GraphImpl()); - mNextDriver->SetGraphTime(this, mIterationStart, mIterationEnd, - mStateComputedTime); + mNextDriver->SetGraphTime(this, mIterationStart, mIterationEnd); mGraphImpl->SetCurrentDriver(mNextDriver); DebugOnly found = mGraphImpl->RemoveMixerCallback(this); NS_WARN_IF_FALSE(!found, "Mixer callback not added when switching?"); @@ -667,8 +655,7 @@ AudioCallbackDriver::Revive() // If we were switching, switch now. Otherwise, start the audio thread again. MonitorAutoLock mon(mGraphImpl->GetMonitor()); if (mNextDriver) { - mNextDriver->SetGraphTime(this, mIterationStart, mIterationEnd, - mStateComputedTime); + mNextDriver->SetGraphTime(this, mIterationStart, mIterationEnd); mGraphImpl->SetCurrentDriver(mNextDriver); mNextDriver->Start(); } else { @@ -786,7 +773,8 @@ AudioCallbackDriver::DataCallback(AudioDataValue* aBuffer, long aFrames) AutoInCallback aic(this); #endif - if (mStateComputedTime == 0) { + GraphTime stateComputedTime = StateComputedTime(); + if (stateComputedTime == 0) { MonitorAutoLock mon(mGraphImpl->GetMonitor()); // Because this function is called during cubeb_stream_init (to prefill the // audio buffers), it can be that we don't have a message here (because this @@ -822,15 +810,15 @@ AudioCallbackDriver::DataCallback(AudioDataValue* aBuffer, long aFrames) // compute the iteration start and end from there, trying to keep the amount // of buffering in the graph constant. GraphTime nextStateComputedTime = - mGraphImpl->RoundUpToNextAudioBlock(mStateComputedTime + mBuffer.Available()); + mGraphImpl->RoundUpToNextAudioBlock(stateComputedTime + mBuffer.Available()); mIterationStart = mIterationEnd; // inGraph is the number of audio frames there is between the state time and // the current time, i.e. the maximum theoretical length of the interval we // could use as [mIterationStart; mIterationEnd]. - GraphTime inGraph = mStateComputedTime - mIterationStart; + GraphTime inGraph = stateComputedTime - mIterationStart; // We want the interval [mIterationStart; mIterationEnd] to be before the - // interval [mStateComputedTime; nextStateComputedTime]. We also want + // interval [stateComputedTime; nextStateComputedTime]. We also want // the distance between these intervals to be roughly equivalent each time, to // ensure there is no clock drift between current time and state time. Since // we can't act on the state time because we have to fill the audio buffer, we @@ -839,20 +827,20 @@ AudioCallbackDriver::DataCallback(AudioDataValue* aBuffer, long aFrames) STREAM_LOG(LogLevel::Debug, ("interval[%ld; %ld] state[%ld; %ld] (frames: %ld) (durationMS: %u) (duration ticks: %ld)\n", (long)mIterationStart, (long)mIterationEnd, - (long)mStateComputedTime, (long)nextStateComputedTime, + (long)stateComputedTime, (long)nextStateComputedTime, (long)aFrames, (uint32_t)durationMS, - (long)(nextStateComputedTime - mStateComputedTime))); + (long)(nextStateComputedTime - stateComputedTime))); mCurrentTimeStamp = TimeStamp::Now(); - if (mStateComputedTime < mIterationEnd) { + if (stateComputedTime < mIterationEnd) { STREAM_LOG(LogLevel::Warning, ("Media graph global underrun detected")); - mIterationEnd = mStateComputedTime; + mIterationEnd = stateComputedTime; } stillProcessing = mGraphImpl->OneIteration(mIterationStart, mIterationEnd, - mStateComputedTime, + stateComputedTime, nextStateComputedTime); } else { NS_WARNING("DataCallback buffer filled entirely from scratch buffer, skipping iteration."); @@ -871,8 +859,7 @@ AudioCallbackDriver::DataCallback(AudioDataValue* aBuffer, long aFrames) } } STREAM_LOG(LogLevel::Debug, ("Switching to system driver.")); - mNextDriver->SetGraphTime(this, mIterationStart, mIterationEnd, - mStateComputedTime); + mNextDriver->SetGraphTime(this, mIterationStart, mIterationEnd); mGraphImpl->SetCurrentDriver(mNextDriver); mNextDriver->Start(); // Returning less than aFrames starts the draining and eventually stops the @@ -979,8 +966,7 @@ AudioCallbackDriver::DeviceChangedCallback() { mCallbackReceivedWhileSwitching = 0; mGraphImpl->mFlushSourcesOnNextIteration = true; mNextDriver = new SystemClockDriver(GraphImpl()); - mNextDriver->SetGraphTime(this, mIterationStart, mIterationEnd, - mStateComputedTime); + mNextDriver->SetGraphTime(this, mIterationStart, mIterationEnd); mGraphImpl->SetCurrentDriver(mNextDriver); mNextDriver->Start(); #endif diff --git a/dom/media/GraphDriver.h b/dom/media/GraphDriver.h index 9985c7a3fba1..a78dc766fa97 100644 --- a/dom/media/GraphDriver.h +++ b/dom/media/GraphDriver.h @@ -127,10 +127,6 @@ public: return mIterationEnd; } - GraphTime StateComputedTime() { - return mStateComputedTime; - } - virtual void GetAudioBuffer(float** aBuffer, long& aFrames) { MOZ_CRASH("This is not an Audio GraphDriver!"); } @@ -155,15 +151,7 @@ public: */ void SetGraphTime(GraphDriver* aPreviousDriver, GraphTime aLastSwitchNextIterationStart, - GraphTime aLastSwitchNextIterationEnd, - GraphTime aLastSwitchStateComputedTime); - - /** - * Whenever the graph has computed the time until it has all state - * (mStateComputedState), it calls this to indicate the new time until which - * we have computed state. - */ - void UpdateStateComputedTime(GraphTime aStateComputedTime); + GraphTime aLastSwitchNextIterationEnd); /** * Call this to indicate that another iteration of the control loop is @@ -190,12 +178,12 @@ public: virtual bool OnThread() = 0; protected: + GraphTime StateComputedTime() const; + // Time of the start of this graph iteration. GraphTime mIterationStart; // Time of the end of this graph iteration. GraphTime mIterationEnd; - // Time, in the future, for which blocking has been computed. - GraphTime mStateComputedTime; // The MediaStreamGraphImpl that owns this driver. This has a lifetime longer // than the driver, and will never be null. MediaStreamGraphImpl* mGraphImpl; diff --git a/dom/media/MediaStreamGraph.cpp b/dom/media/MediaStreamGraph.cpp index c066e2487d81..50c98d15cec8 100644 --- a/dom/media/MediaStreamGraph.cpp +++ b/dom/media/MediaStreamGraph.cpp @@ -171,8 +171,8 @@ MediaStreamGraphImpl::ExtractPendingInput(SourceMediaStream* aStream, // the stream at all between mBlockingDecisionsMadeUntilTime and // aDesiredUpToTime. StreamTime t = - GraphTimeToStreamTime(aStream, CurrentDriver()->StateComputedTime()) + - (aDesiredUpToTime - CurrentDriver()->StateComputedTime()); + GraphTimeToStreamTime(aStream, mStateComputedTime) + + (aDesiredUpToTime - mStateComputedTime); STREAM_LOG(LogLevel::Verbose, ("Calling NotifyPull aStream=%p t=%f current end=%f", aStream, MediaTimeToSeconds(t), MediaTimeToSeconds(aStream->mBuffer.GetEnd()))); @@ -254,7 +254,7 @@ StreamTime MediaStreamGraphImpl::GraphTimeToStreamTime(MediaStream* aStream, GraphTime aTime) { - MOZ_ASSERT(aTime <= CurrentDriver()->StateComputedTime(), + MOZ_ASSERT(aTime <= mStateComputedTime, "Don't ask about times where we haven't made blocking decisions yet"); if (aTime <= IterationEnd()) { return std::max(0, aTime - aStream->mBufferStartTime); @@ -275,7 +275,7 @@ StreamTime MediaStreamGraphImpl::GraphTimeToStreamTimeOptimistic(MediaStream* aStream, GraphTime aTime) { - GraphTime computedUpToTime = std::min(CurrentDriver()->StateComputedTime(), aTime); + GraphTime computedUpToTime = std::min(mStateComputedTime, aTime); StreamTime s = GraphTimeToStreamTime(aStream, computedUpToTime); return s + (aTime - computedUpToTime); } @@ -303,9 +303,9 @@ MediaStreamGraphImpl::StreamTimeToGraphTime(MediaStream* aStream, } bool blocked; GraphTime end; - if (t < CurrentDriver()->StateComputedTime()) { + if (t < mStateComputedTime) { blocked = aStream->mBlocked.GetAt(t, &end); - end = std::min(end, CurrentDriver()->StateComputedTime()); + end = std::min(end, mStateComputedTime); } else { blocked = false; end = GRAPH_TIME_MAX; @@ -752,7 +752,7 @@ MediaStreamGraphImpl::RecomputeBlocking(GraphTime aEndBlockingDecisions) bool blockingDecisionsWillChange = false; STREAM_LOG(LogLevel::Verbose, ("Media graph %p computing blocking for time %f", - this, MediaTimeToSeconds(CurrentDriver()->StateComputedTime()))); + this, MediaTimeToSeconds(mStateComputedTime))); nsTArray* runningAndSuspendedPair[2]; runningAndSuspendedPair[0] = &mStreams; runningAndSuspendedPair[1] = &mSuspendedStreams; @@ -768,7 +768,7 @@ MediaStreamGraphImpl::RecomputeBlocking(GraphTime aEndBlockingDecisions) AddBlockingRelatedStreamsToSet(&streamSet, stream); GraphTime end; - for (GraphTime t = CurrentDriver()->StateComputedTime(); + for (GraphTime t = mStateComputedTime; t < aEndBlockingDecisions; t = end) { end = GRAPH_TIME_MAX; RecomputeBlockingAt(streamSet, t, aEndBlockingDecisions, &end); @@ -786,10 +786,18 @@ MediaStreamGraphImpl::RecomputeBlocking(GraphTime aEndBlockingDecisions) } } STREAM_LOG(LogLevel::Verbose, ("Media graph %p computed blocking for interval %f to %f", - this, MediaTimeToSeconds(CurrentDriver()->StateComputedTime()), + this, MediaTimeToSeconds(mStateComputedTime), MediaTimeToSeconds(aEndBlockingDecisions))); - CurrentDriver()->UpdateStateComputedTime(aEndBlockingDecisions); + MOZ_ASSERT(aEndBlockingDecisions >= IterationEnd()); + // The next state computed time can be the same as the previous: it + // means the driver would be have been blocking indefinitly, but the graph has + // been woken up right after having been to sleep. + if (aEndBlockingDecisions < mStateComputedTime) { + printf("State time can't go backward %ld < %ld.\n", static_cast(aEndBlockingDecisions), static_cast(mStateComputedTime)); + } + + mStateComputedTime = aEndBlockingDecisions; if (blockingDecisionsWillChange) { // Make sure we wake up to notify listeners about these changes. @@ -1128,13 +1136,13 @@ MediaStreamGraphImpl::PlayVideo(MediaStream* aStream) // use, we can't really estimate the graph interval duration, we clamp it to // the current state computed time. GraphTime framePosition = IterationEnd() + MillisecondsToMediaTime(CurrentDriver()->IterationDuration()); - if (framePosition > CurrentDriver()->StateComputedTime()) { + if (framePosition > mStateComputedTime) { #ifdef DEBUG - if (std::abs(framePosition - CurrentDriver()->StateComputedTime()) >= MillisecondsToMediaTime(5)) { + if (std::abs(framePosition - mStateComputedTime) >= MillisecondsToMediaTime(5)) { STREAM_LOG(LogLevel::Debug, ("Graph thread slowdown?")); } #endif - framePosition = CurrentDriver()->StateComputedTime(); + framePosition = mStateComputedTime; } MOZ_ASSERT(framePosition >= aStream->mBufferStartTime, "frame position before buffer?"); StreamTime frameBufferTime = GraphTimeToStreamTime(aStream, framePosition); @@ -1316,13 +1324,13 @@ MediaStreamGraphImpl::UpdateGraph(GraphTime aEndBlockingDecision) } // The loop is woken up so soon that IterationEnd() barely advances and we - // end up having aEndBlockingDecision == CurrentDriver()->StateComputedTime(). + // end up having aEndBlockingDecision == mStateComputedTime. // Since stream blocking is computed in the interval of - // [CurrentDriver()->StateComputedTime(), aEndBlockingDecision), it won't be computed at all. + // [mStateComputedTime, aEndBlockingDecision), it won't be computed at all. // We should ensure next iteration so that pending blocking changes will be // computed in next loop. if (ensureNextIteration || - aEndBlockingDecision == CurrentDriver()->StateComputedTime()) { + aEndBlockingDecision == mStateComputedTime) { EnsureNextIteration(); } @@ -1904,7 +1912,7 @@ MediaStream::Init() MediaStreamGraphImpl* graph = GraphImpl(); mBlocked.SetAtAndAfter(graph->IterationEnd(), true); mExplicitBlockerCount.SetAtAndAfter(graph->IterationEnd(), true); - mExplicitBlockerCount.SetAtAndAfter(graph->CurrentDriver()->StateComputedTime(), false); + mExplicitBlockerCount.SetAtAndAfter(graph->mStateComputedTime, false); } MediaStreamGraphImpl* @@ -2139,7 +2147,7 @@ MediaStream::ChangeExplicitBlockerCount(int32_t aDelta) virtual void Run() { mStream->ChangeExplicitBlockerCountImpl( - mStream->GraphImpl()->CurrentDriver()->StateComputedTime(), mDelta); + mStream->GraphImpl()->mStateComputedTime, mDelta); } int32_t mDelta; }; @@ -2162,7 +2170,7 @@ MediaStream::BlockStreamIfNeeded() virtual void Run() { mStream->BlockStreamIfNeededImpl( - mStream->GraphImpl()->CurrentDriver()->StateComputedTime()); + mStream->GraphImpl()->mStateComputedTime); } }; @@ -2182,7 +2190,7 @@ MediaStream::UnblockStreamIfNeeded() virtual void Run() { mStream->UnblockStreamIfNeededImpl( - mStream->GraphImpl()->CurrentDriver()->StateComputedTime()); + mStream->GraphImpl()->mStateComputedTime); } }; @@ -2635,7 +2643,7 @@ SourceMediaStream::GetBufferedTicks(TrackID aID) MediaSegment* segment = track->GetSegment(); if (segment) { return segment->GetDuration() - - GraphTimeToStreamTime(GraphImpl()->CurrentDriver()->StateComputedTime()); + GraphTimeToStreamTime(GraphImpl()->mStateComputedTime); } } return 0; @@ -3445,7 +3453,7 @@ MediaStreamGraph::StartNonRealtimeProcessing(uint32_t aTicksToProcess) return; graph->mEndTime = - graph->RoundUpToNextAudioBlock(graph->CurrentDriver()->StateComputedTime() + + graph->RoundUpToNextAudioBlock(graph->mStateComputedTime + aTicksToProcess - 1); graph->mNonRealtimeProcessing = true; graph->EnsureRunInStableState(); diff --git a/dom/media/MediaStreamGraphImpl.h b/dom/media/MediaStreamGraphImpl.h index e6d395c2cf85..b01ce863d053 100644 --- a/dom/media/MediaStreamGraphImpl.h +++ b/dom/media/MediaStreamGraphImpl.h @@ -561,6 +561,12 @@ public: * cycles. */ uint32_t mFirstCycleBreaker; + /** + * Blocking decisions and all stream contents have been computed up to this + * time. The next batch of updates from the main thread will be processed + * at this time. + */ + GraphTime mStateComputedTime = 0; /** * Date of the last time we updated the main thread with the graph state. */