Bug 1188643. Buffer more audio in audio capture mode to avoid glitches. r=cpearce.

This commit is contained in:
JW Wang 2015-09-30 10:32:49 +08:00
parent 40ce8b9666
commit 3e1e0e3b3f
2 changed files with 35 additions and 13 deletions

View File

@ -205,7 +205,7 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
mQuickBufferingLowDataThresholdUsecs(detail::QUICK_BUFFERING_LOW_DATA_USECS),
mIsAudioPrerolling(false),
mIsVideoPrerolling(false),
mAudioCaptured(false),
mAudioCaptured(false, "MediaDecoderStateMachine::mAudioCaptured"),
mAudioCompleted(false, "MediaDecoderStateMachine::mAudioCompleted"),
mNotifyMetadataBeforeFirstFrame(false),
mDispatchedEventToDecode(false),
@ -219,7 +219,7 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
mCorruptFrames(60),
mDecodingFirstFrame(true),
mSentLoadedMetadataEvent(false),
mSentFirstFrameLoadedEvent(false),
mSentFirstFrameLoadedEvent(false, "MediaDecoderStateMachine::mSentFirstFrameLoadedEvent"),
mSentPlaybackEndedEvent(false),
mStreamSink(new DecodedStream(mTaskQueue, mAudioQueue, mVideoQueue)),
mResource(aDecoder->GetResource()),
@ -350,6 +350,8 @@ MediaDecoderStateMachine::InitializationTask()
mWatchManager.Watch(mPlayState, &MediaDecoderStateMachine::PlayStateChanged);
mWatchManager.Watch(mLogicallySeeking, &MediaDecoderStateMachine::LogicallySeekingChanged);
mWatchManager.Watch(mSameOriginMedia, &MediaDecoderStateMachine::SameOriginMediaChanged);
mWatchManager.Watch(mSentFirstFrameLoadedEvent, &MediaDecoderStateMachine::AdjustAudioThresholds);
mWatchManager.Watch(mAudioCaptured, &MediaDecoderStateMachine::AdjustAudioThresholds);
// Propagate mSameOriginMedia to mDecodedStream.
SameOriginMediaChanged();
@ -2070,6 +2072,33 @@ MediaDecoderStateMachine::IsDecodingFirstFrame()
return mState == DECODER_STATE_DECODING && mDecodingFirstFrame;
}
void
MediaDecoderStateMachine::AdjustAudioThresholds()
{
MOZ_ASSERT(OnTaskQueue());
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
// Experiments show that we need to buffer more if audio is captured to avoid
// audio glitch. See bug 1188643 comment 16 for the details.
int64_t divisor = mAudioCaptured ? NO_VIDEO_AMPLE_AUDIO_DIVISOR / 2
: NO_VIDEO_AMPLE_AUDIO_DIVISOR;
// We're playing audio only. We don't need to worry about slow video
// decodes causing audio underruns, so don't buffer so much audio in
// order to reduce memory usage.
if (HasAudio() && !HasVideo() && mSentFirstFrameLoadedEvent) {
mAmpleAudioThresholdUsecs = detail::AMPLE_AUDIO_USECS / divisor;
mLowAudioThresholdUsecs = detail::LOW_AUDIO_USECS / divisor;
mQuickBufferingLowDataThresholdUsecs =
detail::QUICK_BUFFERING_LOW_DATA_USECS / divisor;
// Check if we need to stop audio prerolling for thresholds changed.
if (mIsAudioPrerolling && DonePrerollingAudio()) {
StopPrerollingAudio();
}
}
}
void
MediaDecoderStateMachine::FinishDecodeFirstFrame()
{
@ -2090,15 +2119,6 @@ MediaDecoderStateMachine::FinishDecodeFirstFrame()
"transportSeekable=%d, mediaSeekable=%d",
Duration().ToMicroseconds(), mResource->IsTransportSeekable(), mMediaSeekable.Ref());
if (HasAudio() && !HasVideo() && !mSentFirstFrameLoadedEvent) {
// We're playing audio only. We don't need to worry about slow video
// decodes causing audio underruns, so don't buffer so much audio in
// order to reduce memory usage.
mAmpleAudioThresholdUsecs /= NO_VIDEO_AMPLE_AUDIO_DIVISOR;
mLowAudioThresholdUsecs /= NO_VIDEO_AMPLE_AUDIO_DIVISOR;
mQuickBufferingLowDataThresholdUsecs /= NO_VIDEO_AMPLE_AUDIO_DIVISOR;
}
// Get potentially updated metadata
{
ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());

View File

@ -654,6 +654,8 @@ private:
// play time.
bool NeedToSkipToNextKeyframe();
void AdjustAudioThresholds();
// The decoder object that created this state machine. The state machine
// holds a strong reference to the decoder to ensure that the decoder stays
// alive once media element has started the decoder shutdown process, and has
@ -1136,7 +1138,7 @@ private:
// True if we shouldn't play our audio (but still write it to any capturing
// streams). When this is true, the audio thread will never start again after
// it has stopped.
bool mAudioCaptured;
Watchable<bool> mAudioCaptured;
// True if the audio playback thread has finished. It is finished
// when either all the audio frames have completed playing, or we've moved
@ -1228,7 +1230,7 @@ private:
// SetStartTime because the mStartTime already set before. Also we don't need
// to decode any audio/video since the MediaDecoder will trigger a seek
// operation soon.
bool mSentFirstFrameLoadedEvent;
Watchable<bool> mSentFirstFrameLoadedEvent;
bool mSentPlaybackEndedEvent;