| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/filters/audio_renderer_impl.h" | 5 #include "media/filters/audio_renderer_impl.h" |
| 6 | 6 |
| 7 #include <math.h> | 7 #include <math.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 | 10 |
| 11 #include "base/bind.h" | 11 #include "base/bind.h" |
| 12 #include "base/callback.h" | 12 #include "base/callback.h" |
| 13 #include "base/callback_helpers.h" | 13 #include "base/callback_helpers.h" |
| 14 #include "base/logging.h" | 14 #include "base/logging.h" |
| 15 #include "base/message_loop/message_loop_proxy.h" | |
| 16 #include "base/metrics/histogram.h" | 15 #include "base/metrics/histogram.h" |
| 16 #include "base/single_thread_task_runner.h" |
| 17 #include "media/base/audio_buffer.h" | 17 #include "media/base/audio_buffer.h" |
| 18 #include "media/base/audio_splicer.h" | 18 #include "media/base/audio_splicer.h" |
| 19 #include "media/base/bind_to_loop.h" | 19 #include "media/base/bind_to_loop.h" |
| 20 #include "media/base/demuxer_stream.h" | 20 #include "media/base/demuxer_stream.h" |
| 21 #include "media/filters/audio_decoder_selector.h" | 21 #include "media/filters/audio_decoder_selector.h" |
| 22 #include "media/filters/decrypting_demuxer_stream.h" | 22 #include "media/filters/decrypting_demuxer_stream.h" |
| 23 | 23 |
| 24 namespace media { | 24 namespace media { |
| 25 | 25 |
| 26 namespace { | 26 namespace { |
| 27 | 27 |
| 28 enum AudioRendererEvent { | 28 enum AudioRendererEvent { |
| 29 INITIALIZED, | 29 INITIALIZED, |
| 30 RENDER_ERROR, | 30 RENDER_ERROR, |
| 31 MAX_EVENTS | 31 MAX_EVENTS |
| 32 }; | 32 }; |
| 33 | 33 |
| 34 void HistogramRendererEvent(AudioRendererEvent event) { | 34 void HistogramRendererEvent(AudioRendererEvent event) { |
| 35 UMA_HISTOGRAM_ENUMERATION("Media.AudioRendererEvents", event, MAX_EVENTS); | 35 UMA_HISTOGRAM_ENUMERATION("Media.AudioRendererEvents", event, MAX_EVENTS); |
| 36 } | 36 } |
| 37 | 37 |
| 38 } // namespace | 38 } // namespace |
| 39 | 39 |
| 40 AudioRendererImpl::AudioRendererImpl( | 40 AudioRendererImpl::AudioRendererImpl( |
| 41 const scoped_refptr<base::MessageLoopProxy>& message_loop, | 41 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, |
| 42 media::AudioRendererSink* sink, | 42 media::AudioRendererSink* sink, |
| 43 ScopedVector<AudioDecoder> decoders, | 43 ScopedVector<AudioDecoder> decoders, |
| 44 const SetDecryptorReadyCB& set_decryptor_ready_cb, | 44 const SetDecryptorReadyCB& set_decryptor_ready_cb, |
| 45 bool increase_preroll_on_underflow) | 45 bool increase_preroll_on_underflow) |
| 46 : message_loop_(message_loop), | 46 : task_runner_(task_runner), |
| 47 weak_factory_(this), | 47 weak_factory_(this), |
| 48 sink_(sink), | 48 sink_(sink), |
| 49 decoder_selector_(new AudioDecoderSelector( | 49 decoder_selector_(new AudioDecoderSelector( |
| 50 message_loop, decoders.Pass(), set_decryptor_ready_cb)), | 50 task_runner, decoders.Pass(), set_decryptor_ready_cb)), |
| 51 now_cb_(base::Bind(&base::TimeTicks::Now)), | 51 now_cb_(base::Bind(&base::TimeTicks::Now)), |
| 52 state_(kUninitialized), | 52 state_(kUninitialized), |
| 53 sink_playing_(false), | 53 sink_playing_(false), |
| 54 pending_read_(false), | 54 pending_read_(false), |
| 55 received_end_of_stream_(false), | 55 received_end_of_stream_(false), |
| 56 rendered_end_of_stream_(false), | 56 rendered_end_of_stream_(false), |
| 57 audio_time_buffered_(kNoTimestamp()), | 57 audio_time_buffered_(kNoTimestamp()), |
| 58 current_time_(kNoTimestamp()), | 58 current_time_(kNoTimestamp()), |
| 59 underflow_disabled_(false), | 59 underflow_disabled_(false), |
| 60 increase_preroll_on_underflow_(increase_preroll_on_underflow), | 60 increase_preroll_on_underflow_(increase_preroll_on_underflow), |
| 61 preroll_aborted_(false) { | 61 preroll_aborted_(false) { |
| 62 } | 62 } |
| 63 | 63 |
| 64 AudioRendererImpl::~AudioRendererImpl() { | 64 AudioRendererImpl::~AudioRendererImpl() { |
| 65 // Stop() should have been called and |algorithm_| should have been destroyed. | 65 // Stop() should have been called and |algorithm_| should have been destroyed. |
| 66 DCHECK(state_ == kUninitialized || state_ == kStopped); | 66 DCHECK(state_ == kUninitialized || state_ == kStopped); |
| 67 DCHECK(!algorithm_.get()); | 67 DCHECK(!algorithm_.get()); |
| 68 } | 68 } |
| 69 | 69 |
| 70 void AudioRendererImpl::Play(const base::Closure& callback) { | 70 void AudioRendererImpl::Play(const base::Closure& callback) { |
| 71 DCHECK(message_loop_->BelongsToCurrentThread()); | 71 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 72 | 72 |
| 73 base::AutoLock auto_lock(lock_); | 73 base::AutoLock auto_lock(lock_); |
| 74 DCHECK_EQ(state_, kPaused); | 74 DCHECK_EQ(state_, kPaused); |
| 75 ChangeState_Locked(kPlaying); | 75 ChangeState_Locked(kPlaying); |
| 76 callback.Run(); | 76 callback.Run(); |
| 77 earliest_end_time_ = now_cb_.Run(); | 77 earliest_end_time_ = now_cb_.Run(); |
| 78 | 78 |
| 79 if (algorithm_->playback_rate() != 0) | 79 if (algorithm_->playback_rate() != 0) |
| 80 DoPlay_Locked(); | 80 DoPlay_Locked(); |
| 81 else | 81 else |
| 82 DCHECK(!sink_playing_); | 82 DCHECK(!sink_playing_); |
| 83 } | 83 } |
| 84 | 84 |
| 85 void AudioRendererImpl::DoPlay_Locked() { | 85 void AudioRendererImpl::DoPlay_Locked() { |
| 86 DCHECK(message_loop_->BelongsToCurrentThread()); | 86 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 87 lock_.AssertAcquired(); | 87 lock_.AssertAcquired(); |
| 88 earliest_end_time_ = now_cb_.Run(); | 88 earliest_end_time_ = now_cb_.Run(); |
| 89 | 89 |
| 90 if (state_ == kPlaying && !sink_playing_) { | 90 if (state_ == kPlaying && !sink_playing_) { |
| 91 { | 91 { |
| 92 base::AutoUnlock auto_unlock(lock_); | 92 base::AutoUnlock auto_unlock(lock_); |
| 93 sink_->Play(); | 93 sink_->Play(); |
| 94 } | 94 } |
| 95 | 95 |
| 96 sink_playing_ = true; | 96 sink_playing_ = true; |
| 97 } | 97 } |
| 98 } | 98 } |
| 99 | 99 |
| 100 void AudioRendererImpl::Pause(const base::Closure& callback) { | 100 void AudioRendererImpl::Pause(const base::Closure& callback) { |
| 101 DCHECK(message_loop_->BelongsToCurrentThread()); | 101 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 102 | 102 |
| 103 base::AutoLock auto_lock(lock_); | 103 base::AutoLock auto_lock(lock_); |
| 104 DCHECK(state_ == kPlaying || state_ == kUnderflow || | 104 DCHECK(state_ == kPlaying || state_ == kUnderflow || |
| 105 state_ == kRebuffering) << "state_ == " << state_; | 105 state_ == kRebuffering) << "state_ == " << state_; |
| 106 pause_cb_ = callback; | 106 pause_cb_ = callback; |
| 107 ChangeState_Locked(kPaused); | 107 ChangeState_Locked(kPaused); |
| 108 | 108 |
| 109 // Pause only when we've completed our pending read. | 109 // Pause only when we've completed our pending read. |
| 110 if (!pending_read_) | 110 if (!pending_read_) |
| 111 base::ResetAndReturn(&pause_cb_).Run(); | 111 base::ResetAndReturn(&pause_cb_).Run(); |
| 112 | 112 |
| 113 DoPause_Locked(); | 113 DoPause_Locked(); |
| 114 } | 114 } |
| 115 | 115 |
| 116 void AudioRendererImpl::DoPause_Locked() { | 116 void AudioRendererImpl::DoPause_Locked() { |
| 117 DCHECK(message_loop_->BelongsToCurrentThread()); | 117 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 118 lock_.AssertAcquired(); | 118 lock_.AssertAcquired(); |
| 119 | 119 |
| 120 if (sink_playing_) { | 120 if (sink_playing_) { |
| 121 { | 121 { |
| 122 base::AutoUnlock auto_unlock(lock_); | 122 base::AutoUnlock auto_unlock(lock_); |
| 123 sink_->Pause(); | 123 sink_->Pause(); |
| 124 } | 124 } |
| 125 sink_playing_ = false; | 125 sink_playing_ = false; |
| 126 } | 126 } |
| 127 } | 127 } |
| 128 | 128 |
| 129 void AudioRendererImpl::Flush(const base::Closure& callback) { | 129 void AudioRendererImpl::Flush(const base::Closure& callback) { |
| 130 DCHECK(message_loop_->BelongsToCurrentThread()); | 130 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 131 | 131 |
| 132 if (decrypting_demuxer_stream_) { | 132 if (decrypting_demuxer_stream_) { |
| 133 decrypting_demuxer_stream_->Reset(base::Bind( | 133 decrypting_demuxer_stream_->Reset(base::Bind( |
| 134 &AudioRendererImpl::ResetDecoder, weak_this_, callback)); | 134 &AudioRendererImpl::ResetDecoder, weak_this_, callback)); |
| 135 return; | 135 return; |
| 136 } | 136 } |
| 137 | 137 |
| 138 decoder_->Reset(callback); | 138 decoder_->Reset(callback); |
| 139 } | 139 } |
| 140 | 140 |
| 141 void AudioRendererImpl::ResetDecoder(const base::Closure& callback) { | 141 void AudioRendererImpl::ResetDecoder(const base::Closure& callback) { |
| 142 DCHECK(message_loop_->BelongsToCurrentThread()); | 142 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 143 decoder_->Reset(callback); | 143 decoder_->Reset(callback); |
| 144 } | 144 } |
| 145 | 145 |
| 146 void AudioRendererImpl::Stop(const base::Closure& callback) { | 146 void AudioRendererImpl::Stop(const base::Closure& callback) { |
| 147 DCHECK(message_loop_->BelongsToCurrentThread()); | 147 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 148 DCHECK(!callback.is_null()); | 148 DCHECK(!callback.is_null()); |
| 149 | 149 |
| 150 // TODO(scherkus): Consider invalidating |weak_factory_| and replacing | 150 // TODO(scherkus): Consider invalidating |weak_factory_| and replacing |
| 151 // task-running guards that check |state_| with DCHECK(). | 151 // task-running guards that check |state_| with DCHECK(). |
| 152 | 152 |
| 153 if (sink_) { | 153 if (sink_) { |
| 154 sink_->Stop(); | 154 sink_->Stop(); |
| 155 sink_ = NULL; | 155 sink_ = NULL; |
| 156 } | 156 } |
| 157 | 157 |
| 158 { | 158 { |
| 159 base::AutoLock auto_lock(lock_); | 159 base::AutoLock auto_lock(lock_); |
| 160 ChangeState_Locked(kStopped); | 160 ChangeState_Locked(kStopped); |
| 161 algorithm_.reset(NULL); | 161 algorithm_.reset(NULL); |
| 162 init_cb_.Reset(); | 162 init_cb_.Reset(); |
| 163 underflow_cb_.Reset(); | 163 underflow_cb_.Reset(); |
| 164 time_cb_.Reset(); | 164 time_cb_.Reset(); |
| 165 } | 165 } |
| 166 | 166 |
| 167 callback.Run(); | 167 callback.Run(); |
| 168 } | 168 } |
| 169 | 169 |
| 170 void AudioRendererImpl::Preroll(base::TimeDelta time, | 170 void AudioRendererImpl::Preroll(base::TimeDelta time, |
| 171 const PipelineStatusCB& cb) { | 171 const PipelineStatusCB& cb) { |
| 172 DCHECK(message_loop_->BelongsToCurrentThread()); | 172 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 173 | 173 |
| 174 base::AutoLock auto_lock(lock_); | 174 base::AutoLock auto_lock(lock_); |
| 175 DCHECK(!sink_playing_); | 175 DCHECK(!sink_playing_); |
| 176 DCHECK_EQ(state_, kPaused); | 176 DCHECK_EQ(state_, kPaused); |
| 177 DCHECK(!pending_read_) << "Pending read must complete before seeking"; | 177 DCHECK(!pending_read_) << "Pending read must complete before seeking"; |
| 178 DCHECK(pause_cb_.is_null()); | 178 DCHECK(pause_cb_.is_null()); |
| 179 DCHECK(preroll_cb_.is_null()); | 179 DCHECK(preroll_cb_.is_null()); |
| 180 | 180 |
| 181 ChangeState_Locked(kPrerolling); | 181 ChangeState_Locked(kPrerolling); |
| 182 preroll_cb_ = cb; | 182 preroll_cb_ = cb; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 197 } | 197 } |
| 198 | 198 |
| 199 void AudioRendererImpl::Initialize(DemuxerStream* stream, | 199 void AudioRendererImpl::Initialize(DemuxerStream* stream, |
| 200 const PipelineStatusCB& init_cb, | 200 const PipelineStatusCB& init_cb, |
| 201 const StatisticsCB& statistics_cb, | 201 const StatisticsCB& statistics_cb, |
| 202 const base::Closure& underflow_cb, | 202 const base::Closure& underflow_cb, |
| 203 const TimeCB& time_cb, | 203 const TimeCB& time_cb, |
| 204 const base::Closure& ended_cb, | 204 const base::Closure& ended_cb, |
| 205 const base::Closure& disabled_cb, | 205 const base::Closure& disabled_cb, |
| 206 const PipelineStatusCB& error_cb) { | 206 const PipelineStatusCB& error_cb) { |
| 207 DCHECK(message_loop_->BelongsToCurrentThread()); | 207 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 208 DCHECK(stream); | 208 DCHECK(stream); |
| 209 DCHECK_EQ(stream->type(), DemuxerStream::AUDIO); | 209 DCHECK_EQ(stream->type(), DemuxerStream::AUDIO); |
| 210 DCHECK(!init_cb.is_null()); | 210 DCHECK(!init_cb.is_null()); |
| 211 DCHECK(!statistics_cb.is_null()); | 211 DCHECK(!statistics_cb.is_null()); |
| 212 DCHECK(!underflow_cb.is_null()); | 212 DCHECK(!underflow_cb.is_null()); |
| 213 DCHECK(!time_cb.is_null()); | 213 DCHECK(!time_cb.is_null()); |
| 214 DCHECK(!ended_cb.is_null()); | 214 DCHECK(!ended_cb.is_null()); |
| 215 DCHECK(!disabled_cb.is_null()); | 215 DCHECK(!disabled_cb.is_null()); |
| 216 DCHECK(!error_cb.is_null()); | 216 DCHECK(!error_cb.is_null()); |
| 217 DCHECK_EQ(kUninitialized, state_); | 217 DCHECK_EQ(kUninitialized, state_); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 228 | 228 |
| 229 decoder_selector_->SelectAudioDecoder( | 229 decoder_selector_->SelectAudioDecoder( |
| 230 stream, | 230 stream, |
| 231 statistics_cb, | 231 statistics_cb, |
| 232 base::Bind(&AudioRendererImpl::OnDecoderSelected, weak_this_)); | 232 base::Bind(&AudioRendererImpl::OnDecoderSelected, weak_this_)); |
| 233 } | 233 } |
| 234 | 234 |
| 235 void AudioRendererImpl::OnDecoderSelected( | 235 void AudioRendererImpl::OnDecoderSelected( |
| 236 scoped_ptr<AudioDecoder> decoder, | 236 scoped_ptr<AudioDecoder> decoder, |
| 237 scoped_ptr<DecryptingDemuxerStream> decrypting_demuxer_stream) { | 237 scoped_ptr<DecryptingDemuxerStream> decrypting_demuxer_stream) { |
| 238 DCHECK(message_loop_->BelongsToCurrentThread()); | 238 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 239 | 239 |
| 240 base::AutoLock auto_lock(lock_); | 240 base::AutoLock auto_lock(lock_); |
| 241 scoped_ptr<AudioDecoderSelector> deleter(decoder_selector_.Pass()); | 241 scoped_ptr<AudioDecoderSelector> deleter(decoder_selector_.Pass()); |
| 242 | 242 |
| 243 if (state_ == kStopped) { | 243 if (state_ == kStopped) { |
| 244 DCHECK(!sink_); | 244 DCHECK(!sink_); |
| 245 return; | 245 return; |
| 246 } | 246 } |
| 247 | 247 |
| 248 if (!decoder) { | 248 if (!decoder) { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 285 // Some sinks play on start... | 285 // Some sinks play on start... |
| 286 sink_->Pause(); | 286 sink_->Pause(); |
| 287 } | 287 } |
| 288 | 288 |
| 289 DCHECK(!sink_playing_); | 289 DCHECK(!sink_playing_); |
| 290 | 290 |
| 291 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); | 291 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); |
| 292 } | 292 } |
| 293 | 293 |
| 294 void AudioRendererImpl::ResumeAfterUnderflow() { | 294 void AudioRendererImpl::ResumeAfterUnderflow() { |
| 295 DCHECK(message_loop_->BelongsToCurrentThread()); | 295 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 296 base::AutoLock auto_lock(lock_); | 296 base::AutoLock auto_lock(lock_); |
| 297 if (state_ == kUnderflow) { | 297 if (state_ == kUnderflow) { |
| 298 // The "&& preroll_aborted_" is a hack. If preroll is aborted, then we | 298 // The "&& preroll_aborted_" is a hack. If preroll is aborted, then we |
| 299 // shouldn't even reach the kUnderflow state to begin with. But for now | 299 // shouldn't even reach the kUnderflow state to begin with. But for now |
| 300 // we're just making sure that the audio buffer capacity (i.e. the | 300 // we're just making sure that the audio buffer capacity (i.e. the |
| 301 // number of bytes that need to be buffered for preroll to complete) | 301 // number of bytes that need to be buffered for preroll to complete) |
| 302 // does not increase due to an aborted preroll. | 302 // does not increase due to an aborted preroll. |
| 303 // TODO(vrk): Fix this bug correctly! (crbug.com/151352) | 303 // TODO(vrk): Fix this bug correctly! (crbug.com/151352) |
| 304 if (increase_preroll_on_underflow_ && !preroll_aborted_) | 304 if (increase_preroll_on_underflow_ && !preroll_aborted_) |
| 305 algorithm_->IncreaseQueueCapacity(); | 305 algorithm_->IncreaseQueueCapacity(); |
| 306 | 306 |
| 307 ChangeState_Locked(kRebuffering); | 307 ChangeState_Locked(kRebuffering); |
| 308 } | 308 } |
| 309 } | 309 } |
| 310 | 310 |
| 311 void AudioRendererImpl::SetVolume(float volume) { | 311 void AudioRendererImpl::SetVolume(float volume) { |
| 312 DCHECK(message_loop_->BelongsToCurrentThread()); | 312 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 313 DCHECK(sink_); | 313 DCHECK(sink_); |
| 314 sink_->SetVolume(volume); | 314 sink_->SetVolume(volume); |
| 315 } | 315 } |
| 316 | 316 |
| 317 void AudioRendererImpl::DecodedAudioReady( | 317 void AudioRendererImpl::DecodedAudioReady( |
| 318 AudioDecoder::Status status, | 318 AudioDecoder::Status status, |
| 319 const scoped_refptr<AudioBuffer>& buffer) { | 319 const scoped_refptr<AudioBuffer>& buffer) { |
| 320 DVLOG(1) << __FUNCTION__ << "(" << status << ")"; | 320 DVLOG(1) << __FUNCTION__ << "(" << status << ")"; |
| 321 DCHECK(message_loop_->BelongsToCurrentThread()); | 321 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 322 | 322 |
| 323 base::AutoLock auto_lock(lock_); | 323 base::AutoLock auto_lock(lock_); |
| 324 DCHECK(state_ == kPaused || state_ == kPrerolling || state_ == kPlaying || | 324 DCHECK(state_ == kPaused || state_ == kPrerolling || state_ == kPlaying || |
| 325 state_ == kUnderflow || state_ == kRebuffering || state_ == kStopped); | 325 state_ == kUnderflow || state_ == kRebuffering || state_ == kStopped); |
| 326 | 326 |
| 327 CHECK(pending_read_); | 327 CHECK(pending_read_); |
| 328 pending_read_ = false; | 328 pending_read_ = false; |
| 329 | 329 |
| 330 if (status == AudioDecoder::kAborted) { | 330 if (status == AudioDecoder::kAborted) { |
| 331 HandleAbortedReadOrDecodeError(false); | 331 HandleAbortedReadOrDecodeError(false); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 409 } | 409 } |
| 410 return false; | 410 return false; |
| 411 } | 411 } |
| 412 | 412 |
| 413 void AudioRendererImpl::AttemptRead() { | 413 void AudioRendererImpl::AttemptRead() { |
| 414 base::AutoLock auto_lock(lock_); | 414 base::AutoLock auto_lock(lock_); |
| 415 AttemptRead_Locked(); | 415 AttemptRead_Locked(); |
| 416 } | 416 } |
| 417 | 417 |
| 418 void AudioRendererImpl::AttemptRead_Locked() { | 418 void AudioRendererImpl::AttemptRead_Locked() { |
| 419 DCHECK(message_loop_->BelongsToCurrentThread()); | 419 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 420 lock_.AssertAcquired(); | 420 lock_.AssertAcquired(); |
| 421 | 421 |
| 422 if (!CanRead_Locked()) | 422 if (!CanRead_Locked()) |
| 423 return; | 423 return; |
| 424 | 424 |
| 425 pending_read_ = true; | 425 pending_read_ = true; |
| 426 decoder_->Read(base::Bind(&AudioRendererImpl::DecodedAudioReady, weak_this_)); | 426 decoder_->Read(base::Bind(&AudioRendererImpl::DecodedAudioReady, weak_this_)); |
| 427 } | 427 } |
| 428 | 428 |
| 429 bool AudioRendererImpl::CanRead_Locked() { | 429 bool AudioRendererImpl::CanRead_Locked() { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 441 case kRebuffering: | 441 case kRebuffering: |
| 442 break; | 442 break; |
| 443 } | 443 } |
| 444 | 444 |
| 445 return !pending_read_ && !received_end_of_stream_ && | 445 return !pending_read_ && !received_end_of_stream_ && |
| 446 !algorithm_->IsQueueFull(); | 446 !algorithm_->IsQueueFull(); |
| 447 } | 447 } |
| 448 | 448 |
| 449 void AudioRendererImpl::SetPlaybackRate(float playback_rate) { | 449 void AudioRendererImpl::SetPlaybackRate(float playback_rate) { |
| 450 DVLOG(1) << __FUNCTION__ << "(" << playback_rate << ")"; | 450 DVLOG(1) << __FUNCTION__ << "(" << playback_rate << ")"; |
| 451 DCHECK(message_loop_->BelongsToCurrentThread()); | 451 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 452 DCHECK_GE(playback_rate, 0); | 452 DCHECK_GE(playback_rate, 0); |
| 453 DCHECK(sink_); | 453 DCHECK(sink_); |
| 454 | 454 |
| 455 base::AutoLock auto_lock(lock_); | 455 base::AutoLock auto_lock(lock_); |
| 456 | 456 |
| 457 // We have two cases here: | 457 // We have two cases here: |
| 458 // Play: current_playback_rate == 0 && playback_rate != 0 | 458 // Play: current_playback_rate == 0 && playback_rate != 0 |
| 459 // Pause: current_playback_rate != 0 && playback_rate == 0 | 459 // Pause: current_playback_rate != 0 && playback_rate == 0 |
| 460 float current_playback_rate = algorithm_->playback_rate(); | 460 float current_playback_rate = algorithm_->playback_rate(); |
| 461 if (current_playback_rate == 0 && playback_rate != 0) | 461 if (current_playback_rate == 0 && playback_rate != 0) |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 526 ChangeState_Locked(kUnderflow); | 526 ChangeState_Locked(kUnderflow); |
| 527 underflow_cb = underflow_cb_; | 527 underflow_cb = underflow_cb_; |
| 528 } else { | 528 } else { |
| 529 // We can't write any data this cycle. For example, we may have | 529 // We can't write any data this cycle. For example, we may have |
| 530 // sent all available data to the audio device while not reaching | 530 // sent all available data to the audio device while not reaching |
| 531 // |earliest_end_time_|. | 531 // |earliest_end_time_|. |
| 532 } | 532 } |
| 533 } | 533 } |
| 534 | 534 |
| 535 if (CanRead_Locked()) { | 535 if (CanRead_Locked()) { |
| 536 message_loop_->PostTask(FROM_HERE, base::Bind( | 536 task_runner_->PostTask(FROM_HERE, base::Bind( |
| 537 &AudioRendererImpl::AttemptRead, weak_this_)); | 537 &AudioRendererImpl::AttemptRead, weak_this_)); |
| 538 } | 538 } |
| 539 | 539 |
| 540 // The |audio_time_buffered_| is the ending timestamp of the last frame | 540 // The |audio_time_buffered_| is the ending timestamp of the last frame |
| 541 // buffered at the audio device. |playback_delay| is the amount of time | 541 // buffered at the audio device. |playback_delay| is the amount of time |
| 542 // buffered at the audio device. The current time can be computed by their | 542 // buffered at the audio device. The current time can be computed by their |
| 543 // difference. | 543 // difference. |
| 544 if (audio_time_buffered_ != kNoTimestamp()) { | 544 if (audio_time_buffered_ != kNoTimestamp()) { |
| 545 // Adjust the delay according to playback rate. | 545 // Adjust the delay according to playback rate. |
| 546 base::TimeDelta adjusted_playback_delay = | 546 base::TimeDelta adjusted_playback_delay = |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 640 } | 640 } |
| 641 } | 641 } |
| 642 | 642 |
| 643 void AudioRendererImpl::ChangeState_Locked(State new_state) { | 643 void AudioRendererImpl::ChangeState_Locked(State new_state) { |
| 644 DVLOG(1) << __FUNCTION__ << " : " << state_ << " -> " << new_state; | 644 DVLOG(1) << __FUNCTION__ << " : " << state_ << " -> " << new_state; |
| 645 lock_.AssertAcquired(); | 645 lock_.AssertAcquired(); |
| 646 state_ = new_state; | 646 state_ = new_state; |
| 647 } | 647 } |
| 648 | 648 |
| 649 } // namespace media | 649 } // namespace media |
| OLD | NEW |