Commit 16d731f0 authored by Robert O'Callahan's avatar Robert O'Callahan
Browse files

Bug 750258. Advance mBlockingDecisionsMadeUntilTime to include time lost when...

Bug 750258. Advance mBlockingDecisionsMadeUntilTime to include time lost when the media graph control thread was stopped and all streams had underruns. r=jesup
The first part just handles the case where nsAudioStream failed to allocate a stream. It won't be playing
anything, so instead of trying to get the audio position, just fall back to the media graph current time.
Otherwise GetPositionInFrames returns -1 and things go badly from there.
The second part simplifies the calculation of the next mCurrentTime to just make it based on real time.
We had some code to not let it advance past the end of a stream's buffer, but the next part will make that
unnecessary.
The third part is the real fix. When the new current time has advanced past mBlockingDecisionsMadeUntilTime,
that means the control loop didn't run in time to replenish the audio output buffers and keep up with its
other duties. Effectively all streams have been blocked between mBlockingDecisionsMadeUntilTime and
the new current time. Account for that by adding the difference as extra blocked time for every stream.
We only need to ensure that the stream is marked blocked from mBlockingDecisionsMadeUntilTime indefinitely
far into the future, and then update mBlockingDecisionsMadeUntilTime to the new current time, because the
code takes into account that only blocking decisions up to mBlockingDecisionsMadeUntilTime are valid.
parent f5224451
Loading
Loading
Loading
Loading
+16 −32
Original line number Diff line number Diff line
@@ -766,52 +766,36 @@ MediaStreamGraphImpl::GetAudioPosition(MediaStream* aStream)
  if (!aStream->mAudioOutput) {
    return mCurrentTime;
  }
  PRInt64 positionInFrames = aStream->mAudioOutput->GetPositionInFrames();
  if (positionInFrames < 0) {
    return mCurrentTime;
  }
  return aStream->mAudioPlaybackStartTime +
      TicksToTimeRoundDown(aStream->mAudioOutput->GetRate(),
                           aStream->mAudioOutput->GetPositionInFrames());
                           positionInFrames);
}

void
MediaStreamGraphImpl::UpdateCurrentTime()
{
  GraphTime prevCurrentTime = mCurrentTime;

  TimeStamp now = TimeStamp::Now();
  // The earliest buffer end time for streams that haven't finished. We can't
  // advance the current time past this point.
  GraphTime minBufferEndTime = GRAPH_TIME_MAX;
  for (PRUint32 i = 0; i < mStreams.Length(); ++i) {
    MediaStream* stream = mStreams[i];
    GraphTime blockedBufferEndTime =
      StreamTimeToGraphTime(stream, stream->GetBufferEnd(), INCLUDE_TRAILING_BLOCKED_INTERVAL);
    if (stream->mAudioOutput &&
        (!stream->mFinished || mBlockingDecisionsMadeUntilTime <= blockedBufferEndTime)) {
      // XXX We should take audio positions into account when determining how
      // far to advance the current time. Basically the current time should
      // track the average or minimum of the audio positions. We don't do this
      // currently since the audio positions aren't accurate enough. This
      // logging code is helpful to track the accuracy of audio positions.
      GraphTime audioPosition = GetAudioPosition(stream);
      LOG(PR_LOG_DEBUG, ("Audio position for stream %p is %f", stream,
                         MediaTimeToSeconds(audioPosition)));
    }
    if (!stream->mFinished) {
      minBufferEndTime = NS_MIN(minBufferEndTime, blockedBufferEndTime);
    }
  }

  NS_ASSERTION(mCurrentTime <= minBufferEndTime,
               "We shouldn't have already advanced beyond buffer end!");
  GraphTime nextCurrentTime =
    SecondsToMediaTime((now - mCurrentTimeStamp).ToSeconds()) + mCurrentTime;
  if (minBufferEndTime < nextCurrentTime) {
    LOG(PR_LOG_WARNING, ("Reducing current time to minimum buffer end"));
    nextCurrentTime = minBufferEndTime;
  if (mBlockingDecisionsMadeUntilTime < nextCurrentTime) {
    LOG(PR_LOG_WARNING, ("Media graph global underrun detected"));
    LOG(PR_LOG_DEBUG, ("Advancing mBlockingDecisionsMadeUntilTime from %f to %f",
                       MediaTimeToSeconds(mBlockingDecisionsMadeUntilTime),
                       MediaTimeToSeconds(nextCurrentTime)));
    // Advance mBlockingDecisionsMadeUntilTime to nextCurrentTime by
    // adding blocked time to all streams starting at mBlockingDecisionsMadeUntilTime
    for (PRUint32 i = 0; i < mStreams.Length(); ++i) {
      mStreams[i]->mBlocked.SetAtAndAfter(mBlockingDecisionsMadeUntilTime, true);
    }
    mBlockingDecisionsMadeUntilTime = nextCurrentTime;
  }
  mCurrentTimeStamp = now;

  mBlockingDecisionsMadeUntilTime =
    NS_MAX(nextCurrentTime, mBlockingDecisionsMadeUntilTime);
  LOG(PR_LOG_DEBUG, ("Updating current time to %f (minBufferEndTime %f, real %f, mBlockingDecisionsMadeUntilTime %f)",
                     MediaTimeToSeconds(nextCurrentTime),
                     MediaTimeToSeconds(minBufferEndTime),