Index: media/filters/audio_renderer_impl.cc |
diff --git a/media/filters/audio_renderer_impl.cc b/media/filters/audio_renderer_impl.cc |
index 0dff76f37d7f3a222a30befb0bb057ee54f66d6c..e6a240b7dd260615f8e2bd9460597df4ce182bf2 100644 |
--- a/media/filters/audio_renderer_impl.cc |
+++ b/media/filters/audio_renderer_impl.cc |
@@ -54,12 +54,12 @@ AudioRendererImpl::AudioRendererImpl( |
hardware_config_(hardware_config), |
now_cb_(base::Bind(&base::TimeTicks::Now)), |
state_(kUninitialized), |
+ buffering_state_(BUFFERING_HAVE_NOTHING), |
rendering_(false), |
sink_playing_(false), |
pending_read_(false), |
received_end_of_stream_(false), |
rendered_end_of_stream_(false), |
- preroll_aborted_(false), |
weak_factory_(this) { |
audio_buffer_stream_.set_splice_observer(base::Bind( |
&AudioRendererImpl::OnNewSpliceBuffer, weak_factory_.GetWeakPtr())); |
@@ -92,8 +92,7 @@ void AudioRendererImpl::StartRendering() { |
void AudioRendererImpl::StartRendering_Locked() { |
DVLOG(1) << __FUNCTION__; |
DCHECK(task_runner_->BelongsToCurrentThread()); |
- DCHECK(state_ == kPlaying || state_ == kRebuffering || state_ == kUnderflow) |
- << "state_=" << state_; |
+ DCHECK_EQ(state_, kPlaying); |
DCHECK(!sink_playing_); |
DCHECK_NE(algorithm_->playback_rate(), 0); |
lock_.AssertAcquired(); |
@@ -123,8 +122,7 @@ void AudioRendererImpl::StopRendering() { |
void AudioRendererImpl::StopRendering_Locked() { |
DCHECK(task_runner_->BelongsToCurrentThread()); |
- DCHECK(state_ == kPlaying || state_ == kRebuffering || state_ == kUnderflow) |
- << "state_=" << state_; |
+ DCHECK_EQ(state_, kPlaying); |
DCHECK(sink_playing_); |
lock_.AssertAcquired(); |
@@ -139,16 +137,14 @@ void AudioRendererImpl::Flush(const base::Closure& callback) { |
DCHECK(task_runner_->BelongsToCurrentThread()); |
base::AutoLock auto_lock(lock_); |
- DCHECK(state_ == kPlaying || state_ == kRebuffering || state_ == kUnderflow) |
- << "state_=" << state_; |
+ DCHECK_EQ(state_, kPlaying); |
DCHECK(flush_cb_.is_null()); |
flush_cb_ = callback; |
+ ChangeState_Locked(kFlushing); |
- if (pending_read_) { |
- ChangeState_Locked(kFlushing); |
+ if (pending_read_) |
return; |
- } |
ChangeState_Locked(kFlushed); |
DoFlush_Locked(); |
@@ -178,7 +174,10 @@ void AudioRendererImpl::ResetDecoderDone() { |
audio_clock_.reset(new AudioClock(audio_parameters_.sample_rate())); |
received_end_of_stream_ = false; |
rendered_end_of_stream_ = false; |
- preroll_aborted_ = false; |
+ |
+ // Flush() may have been called while underflowed/not fully buffered. |
+ if (buffering_state_ != BUFFERING_HAVE_NOTHING) |
+ SetBufferingState_Locked(BUFFERING_HAVE_NOTHING); |
earliest_end_time_ = now_cb_.Run(); |
splicer_->Reset(); |
@@ -207,7 +206,6 @@ void AudioRendererImpl::Stop(const base::Closure& callback) { |
ChangeState_Locked(kStopped); |
algorithm_.reset(); |
- underflow_cb_.Reset(); |
time_cb_.Reset(); |
flush_cb_.Reset(); |
} |
@@ -220,20 +218,18 @@ void AudioRendererImpl::Stop(const base::Closure& callback) { |
audio_buffer_stream_.Stop(callback); |
} |
-void AudioRendererImpl::Preroll(base::TimeDelta time, |
- const PipelineStatusCB& cb) { |
- DVLOG(1) << __FUNCTION__ << "(" << time.InMicroseconds() << ")"; |
+void AudioRendererImpl::StartPlayingFrom(base::TimeDelta timestamp) { |
+ DVLOG(1) << __FUNCTION__ << "(" << timestamp.InMicroseconds() << ")"; |
DCHECK(task_runner_->BelongsToCurrentThread()); |
base::AutoLock auto_lock(lock_); |
DCHECK(!sink_playing_); |
DCHECK_EQ(state_, kFlushed); |
+ DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING); |
DCHECK(!pending_read_) << "Pending read must complete before seeking"; |
- DCHECK(preroll_cb_.is_null()); |
- ChangeState_Locked(kPrerolling); |
- preroll_cb_ = cb; |
- preroll_timestamp_ = time; |
+ ChangeState_Locked(kPlaying); |
+ start_timestamp_ = timestamp; |
AttemptRead_Locked(); |
} |
@@ -241,8 +237,8 @@ void AudioRendererImpl::Preroll(base::TimeDelta time, |
void AudioRendererImpl::Initialize(DemuxerStream* stream, |
const PipelineStatusCB& init_cb, |
const StatisticsCB& statistics_cb, |
- const base::Closure& underflow_cb, |
const TimeCB& time_cb, |
+ const BufferingStateCB& buffering_state_cb, |
const base::Closure& ended_cb, |
const PipelineStatusCB& error_cb) { |
DCHECK(task_runner_->BelongsToCurrentThread()); |
@@ -250,8 +246,8 @@ void AudioRendererImpl::Initialize(DemuxerStream* stream, |
DCHECK_EQ(stream->type(), DemuxerStream::AUDIO); |
DCHECK(!init_cb.is_null()); |
DCHECK(!statistics_cb.is_null()); |
- DCHECK(!underflow_cb.is_null()); |
DCHECK(!time_cb.is_null()); |
+ DCHECK(!buffering_state_cb.is_null()); |
DCHECK(!ended_cb.is_null()); |
DCHECK(!error_cb.is_null()); |
DCHECK_EQ(kUninitialized, state_); |
@@ -260,8 +256,9 @@ void AudioRendererImpl::Initialize(DemuxerStream* stream, |
state_ = kInitializing; |
init_cb_ = init_cb; |
- underflow_cb_ = underflow_cb; |
time_cb_ = time_cb; |
+ // Callback can be run from audio callback thread in Render(). |
+ buffering_state_cb_ = BindToCurrentLoop(buffering_state_cb); |
ended_cb_ = ended_cb; |
error_cb_ = error_cb; |
@@ -351,23 +348,6 @@ void AudioRendererImpl::OnAudioBufferStreamInitialized(bool success) { |
base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); |
} |
-void AudioRendererImpl::ResumeAfterUnderflow() { |
- DCHECK(task_runner_->BelongsToCurrentThread()); |
- base::AutoLock auto_lock(lock_); |
- if (state_ == kUnderflow) { |
- // The "!preroll_aborted_" is a hack. If preroll is aborted, then we |
- // shouldn't even reach the kUnderflow state to begin with. But for now |
- // we're just making sure that the audio buffer capacity (i.e. the |
- // number of bytes that need to be buffered for preroll to complete) |
- // does not increase due to an aborted preroll. |
- // TODO(vrk): Fix this bug correctly! (crbug.com/151352) |
- if (!preroll_aborted_) |
- algorithm_->IncreaseQueueCapacity(); |
- |
- ChangeState_Locked(kRebuffering); |
- } |
-} |
- |
void AudioRendererImpl::SetVolume(float volume) { |
DCHECK(task_runner_->BelongsToCurrentThread()); |
DCHECK(sink_); |
@@ -429,7 +409,7 @@ void AudioRendererImpl::DecodedAudioReady( |
bool need_another_buffer = false; |
while (splicer_->HasNextBuffer()) |
- need_another_buffer = HandleSplicerBuffer(splicer_->GetNextBuffer()); |
+ need_another_buffer = HandleSplicerBuffer_Locked(splicer_->GetNextBuffer()); |
if (!need_another_buffer && !CanRead_Locked()) |
return; |
@@ -437,23 +417,18 @@ void AudioRendererImpl::DecodedAudioReady( |
AttemptRead_Locked(); |
} |
-bool AudioRendererImpl::HandleSplicerBuffer( |
+bool AudioRendererImpl::HandleSplicerBuffer_Locked( |
const scoped_refptr<AudioBuffer>& buffer) { |
+ lock_.AssertAcquired(); |
if (buffer->end_of_stream()) { |
received_end_of_stream_ = true; |
- |
- // Transition to kPlaying if we are currently handling an underflow since |
- // no more data will be arriving. |
- if (state_ == kUnderflow || state_ == kRebuffering) |
- ChangeState_Locked(kPlaying); |
} else { |
- if (state_ == kPrerolling) { |
- if (IsBeforePrerollTime(buffer)) |
+ if (state_ == kPlaying) { |
+ if (IsBeforeStartTime(buffer)) |
return true; |
- // Trim off any additional time before the preroll timestamp. |
- const base::TimeDelta trim_time = |
- preroll_timestamp_ - buffer->timestamp(); |
+ // Trim off any additional time before the start timestamp. |
+ const base::TimeDelta trim_time = start_timestamp_ - buffer->timestamp(); |
if (trim_time > base::TimeDelta()) { |
buffer->TrimStart(buffer->frame_count() * |
(static_cast<double>(trim_time.InMicroseconds()) / |
@@ -479,22 +454,13 @@ bool AudioRendererImpl::HandleSplicerBuffer( |
DCHECK(!pending_read_); |
return false; |
- case kPrerolling: |
- if (!buffer->end_of_stream() && !algorithm_->IsQueueFull()) |
- return true; |
- ChangeState_Locked(kPlaying); |
- base::ResetAndReturn(&preroll_cb_).Run(PIPELINE_OK); |
- return false; |
- |
case kPlaying: |
- case kUnderflow: |
- return false; |
- |
- case kRebuffering: |
- if (!algorithm_->IsQueueFull()) |
- return true; |
- ChangeState_Locked(kPlaying); |
- return false; |
+ if (buffer->end_of_stream() || algorithm_->IsQueueFull()) { |
+ if (buffering_state_ == BUFFERING_HAVE_NOTHING) |
+ SetBufferingState_Locked(BUFFERING_HAVE_ENOUGH); |
+ return false; |
+ } |
+ return true; |
case kStopped: |
return false; |
@@ -525,15 +491,12 @@ bool AudioRendererImpl::CanRead_Locked() { |
switch (state_) { |
case kUninitialized: |
case kInitializing: |
- case kFlushed: |
case kFlushing: |
+ case kFlushed: |
case kStopped: |
return false; |
- case kPrerolling: |
case kPlaying: |
- case kUnderflow: |
- case kRebuffering: |
break; |
} |
@@ -569,11 +532,11 @@ void AudioRendererImpl::SetPlaybackRate(float playback_rate) { |
} |
} |
-bool AudioRendererImpl::IsBeforePrerollTime( |
+bool AudioRendererImpl::IsBeforeStartTime( |
const scoped_refptr<AudioBuffer>& buffer) { |
- DCHECK_EQ(state_, kPrerolling); |
+ DCHECK_EQ(state_, kPlaying); |
return buffer && !buffer->end_of_stream() && |
- (buffer->timestamp() + buffer->duration()) < preroll_timestamp_; |
+ (buffer->timestamp() + buffer->duration()) < start_timestamp_; |
} |
int AudioRendererImpl::Render(AudioBus* audio_bus, |
@@ -585,7 +548,6 @@ int AudioRendererImpl::Render(AudioBus* audio_bus, |
audio_parameters_.sample_rate()); |
int frames_written = 0; |
base::Closure time_cb; |
- base::Closure underflow_cb; |
{ |
base::AutoLock auto_lock(lock_); |
@@ -639,8 +601,10 @@ int AudioRendererImpl::Render(AudioBus* audio_bus, |
rendered_end_of_stream_ = true; |
ended_cb_.Run(); |
} else if (!received_end_of_stream_ && state_ == kPlaying) { |
- ChangeState_Locked(kUnderflow); |
- underflow_cb = underflow_cb_; |
+ if (buffering_state_ != BUFFERING_HAVE_NOTHING) { |
+ algorithm_->IncreaseQueueCapacity(); |
+ SetBufferingState_Locked(BUFFERING_HAVE_NOTHING); |
+ } |
} else { |
// We can't write any data this cycle. For example, we may have |
// sent all available data to the audio device while not reaching |
@@ -673,9 +637,6 @@ int AudioRendererImpl::Render(AudioBus* audio_bus, |
if (!time_cb.is_null()) |
time_cb.Run(); |
- if (!underflow_cb.is_null()) |
- underflow_cb.Run(); |
- |
DCHECK_LE(frames_written, requested_frames); |
return frames_written; |
} |
@@ -714,7 +675,6 @@ void AudioRendererImpl::HandleAbortedReadOrDecodeError(bool is_decode_error) { |
return; |
case kFlushing: |
ChangeState_Locked(kFlushed); |
- |
if (status == PIPELINE_OK) { |
DoFlush_Locked(); |
return; |
@@ -723,16 +683,9 @@ void AudioRendererImpl::HandleAbortedReadOrDecodeError(bool is_decode_error) { |
error_cb_.Run(status); |
base::ResetAndReturn(&flush_cb_).Run(); |
return; |
- case kPrerolling: |
- // This is a signal for abort if it's not an error. |
- preroll_aborted_ = !is_decode_error; |
- ChangeState_Locked(kPlaying); |
- base::ResetAndReturn(&preroll_cb_).Run(status); |
- return; |
+ |
case kFlushed: |
case kPlaying: |
- case kUnderflow: |
- case kRebuffering: |
case kStopped: |
if (status != PIPELINE_OK) |
error_cb_.Run(status); |
@@ -762,4 +715,14 @@ void AudioRendererImpl::OnConfigChange() { |
CHECK(splicer_->AddInput(buffer_converter_->GetNextBuffer())); |
} |
+void AudioRendererImpl::SetBufferingState_Locked( |
+ BufferingState buffering_state) { |
+ DVLOG(1) << __FUNCTION__ << " : " << buffering_state_ << " -> " |
+ << buffering_state; |
+ DCHECK_NE(buffering_state_, buffering_state); |
+ lock_.AssertAcquired(); |
+ buffering_state_ = buffering_state; |
+ buffering_state_cb_.Run(buffering_state_); |
+} |
+ |
} // namespace media |