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 |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
45 media::AudioRendererSink* sink, | 45 media::AudioRendererSink* sink, |
46 ScopedVector<AudioDecoder> decoders, | 46 ScopedVector<AudioDecoder> decoders, |
47 const SetDecryptorReadyCB& set_decryptor_ready_cb, | 47 const SetDecryptorReadyCB& set_decryptor_ready_cb, |
48 AudioHardwareConfig* hardware_config) | 48 AudioHardwareConfig* hardware_config) |
49 : task_runner_(task_runner), | 49 : task_runner_(task_runner), |
50 sink_(sink), | 50 sink_(sink), |
51 audio_buffer_stream_(task_runner, | 51 audio_buffer_stream_(task_runner, |
52 decoders.Pass(), | 52 decoders.Pass(), |
53 set_decryptor_ready_cb), | 53 set_decryptor_ready_cb), |
54 hardware_config_(hardware_config), | 54 hardware_config_(hardware_config), |
55 buffering_state_(BUFFERING_HAVE_NOTHING), | |
55 now_cb_(base::Bind(&base::TimeTicks::Now)), | 56 now_cb_(base::Bind(&base::TimeTicks::Now)), |
56 state_(kUninitialized), | 57 state_(kUninitialized), |
57 rendering_(false), | 58 rendering_(false), |
58 sink_playing_(false), | 59 sink_playing_(false), |
59 pending_read_(false), | 60 pending_read_(false), |
60 received_end_of_stream_(false), | 61 received_end_of_stream_(false), |
61 rendered_end_of_stream_(false), | 62 rendered_end_of_stream_(false), |
62 underflow_disabled_(false), | |
63 preroll_aborted_(false), | |
64 weak_factory_(this) { | 63 weak_factory_(this) { |
65 audio_buffer_stream_.set_splice_observer(base::Bind( | 64 audio_buffer_stream_.set_splice_observer(base::Bind( |
66 &AudioRendererImpl::OnNewSpliceBuffer, weak_factory_.GetWeakPtr())); | 65 &AudioRendererImpl::OnNewSpliceBuffer, weak_factory_.GetWeakPtr())); |
67 audio_buffer_stream_.set_config_change_observer(base::Bind( | 66 audio_buffer_stream_.set_config_change_observer(base::Bind( |
68 &AudioRendererImpl::OnConfigChange, weak_factory_.GetWeakPtr())); | 67 &AudioRendererImpl::OnConfigChange, weak_factory_.GetWeakPtr())); |
69 } | 68 } |
70 | 69 |
71 AudioRendererImpl::~AudioRendererImpl() { | 70 AudioRendererImpl::~AudioRendererImpl() { |
72 // Stop() should have been called and |algorithm_| should have been destroyed. | 71 // Stop() should have been called and |algorithm_| should have been destroyed. |
73 DCHECK(state_ == kUninitialized || state_ == kStopped); | 72 DCHECK(state_ == kUninitialized || state_ == kStopped); |
(...skipping 12 matching lines...) Expand all Loading... | |
86 DCHECK(!sink_playing_); | 85 DCHECK(!sink_playing_); |
87 return; | 86 return; |
88 } | 87 } |
89 | 88 |
90 StartRendering_Locked(); | 89 StartRendering_Locked(); |
91 } | 90 } |
92 | 91 |
93 void AudioRendererImpl::StartRendering_Locked() { | 92 void AudioRendererImpl::StartRendering_Locked() { |
94 DVLOG(1) << __FUNCTION__; | 93 DVLOG(1) << __FUNCTION__; |
95 DCHECK(task_runner_->BelongsToCurrentThread()); | 94 DCHECK(task_runner_->BelongsToCurrentThread()); |
96 DCHECK(state_ == kPlaying || state_ == kRebuffering || state_ == kUnderflow) | 95 DCHECK_EQ(state_, kPlaying); |
97 << "state_=" << state_; | |
98 DCHECK(!sink_playing_); | 96 DCHECK(!sink_playing_); |
99 DCHECK_NE(algorithm_->playback_rate(), 0); | 97 DCHECK_NE(algorithm_->playback_rate(), 0); |
100 lock_.AssertAcquired(); | 98 lock_.AssertAcquired(); |
101 | 99 |
102 earliest_end_time_ = now_cb_.Run(); | 100 earliest_end_time_ = now_cb_.Run(); |
103 sink_playing_ = true; | 101 sink_playing_ = true; |
104 | 102 |
105 base::AutoUnlock auto_unlock(lock_); | 103 base::AutoUnlock auto_unlock(lock_); |
106 sink_->Play(); | 104 sink_->Play(); |
107 } | 105 } |
108 | 106 |
109 void AudioRendererImpl::StopRendering() { | 107 void AudioRendererImpl::StopRendering() { |
110 DVLOG(1) << __FUNCTION__; | 108 DVLOG(1) << __FUNCTION__; |
111 DCHECK(task_runner_->BelongsToCurrentThread()); | 109 DCHECK(task_runner_->BelongsToCurrentThread()); |
112 DCHECK(rendering_); | 110 DCHECK(rendering_); |
113 rendering_ = false; | 111 rendering_ = false; |
114 | 112 |
115 base::AutoLock auto_lock(lock_); | 113 base::AutoLock auto_lock(lock_); |
116 // Rendering should have already been stopped with a zero playback rate. | 114 // Rendering should have already been stopped with a zero playback rate. |
117 if (algorithm_->playback_rate() == 0) { | 115 if (algorithm_->playback_rate() == 0) { |
118 DCHECK(!sink_playing_); | 116 DCHECK(!sink_playing_); |
119 return; | 117 return; |
120 } | 118 } |
121 | 119 |
122 StopRendering_Locked(); | 120 StopRendering_Locked(); |
123 } | 121 } |
124 | 122 |
125 void AudioRendererImpl::StopRendering_Locked() { | 123 void AudioRendererImpl::StopRendering_Locked() { |
126 DCHECK(task_runner_->BelongsToCurrentThread()); | 124 DCHECK(task_runner_->BelongsToCurrentThread()); |
127 DCHECK(state_ == kPlaying || state_ == kRebuffering || state_ == kUnderflow) | 125 DCHECK_EQ(state_, kPlaying); |
128 << "state_=" << state_; | |
129 DCHECK(sink_playing_); | 126 DCHECK(sink_playing_); |
130 lock_.AssertAcquired(); | 127 lock_.AssertAcquired(); |
131 | 128 |
132 sink_playing_ = false; | 129 sink_playing_ = false; |
133 | 130 |
134 base::AutoUnlock auto_unlock(lock_); | 131 base::AutoUnlock auto_unlock(lock_); |
135 sink_->Pause(); | 132 sink_->Pause(); |
136 } | 133 } |
137 | 134 |
138 void AudioRendererImpl::Flush(const base::Closure& callback) { | 135 void AudioRendererImpl::Flush(const base::Closure& callback) { |
136 DVLOG(1) << __FUNCTION__; | |
139 DCHECK(task_runner_->BelongsToCurrentThread()); | 137 DCHECK(task_runner_->BelongsToCurrentThread()); |
140 | 138 |
141 base::AutoLock auto_lock(lock_); | 139 base::AutoLock auto_lock(lock_); |
142 DCHECK_EQ(state_, kPlaying); | 140 DCHECK_EQ(state_, kPlaying); |
143 DCHECK(flush_cb_.is_null()); | 141 DCHECK(flush_cb_.is_null()); |
144 | 142 |
145 flush_cb_ = callback; | 143 flush_cb_ = callback; |
144 ChangeState_Locked(kFlushing); | |
146 | 145 |
147 if (pending_read_) { | 146 if (pending_read_) |
148 ChangeState_Locked(kFlushing); | |
149 return; | 147 return; |
150 } | |
151 | 148 |
152 ChangeState_Locked(kFlushed); | 149 ChangeState_Locked(kFlushed); |
153 DoFlush_Locked(); | 150 DoFlush_Locked(); |
154 } | 151 } |
155 | 152 |
156 void AudioRendererImpl::DoFlush_Locked() { | 153 void AudioRendererImpl::DoFlush_Locked() { |
157 DCHECK(task_runner_->BelongsToCurrentThread()); | 154 DCHECK(task_runner_->BelongsToCurrentThread()); |
158 lock_.AssertAcquired(); | 155 lock_.AssertAcquired(); |
159 | 156 |
160 DCHECK(!pending_read_); | 157 DCHECK(!pending_read_); |
161 DCHECK_EQ(state_, kFlushed); | 158 DCHECK_EQ(state_, kFlushed); |
162 | 159 |
163 audio_buffer_stream_.Reset(base::Bind(&AudioRendererImpl::ResetDecoderDone, | 160 audio_buffer_stream_.Reset(base::Bind(&AudioRendererImpl::ResetDecoderDone, |
164 weak_factory_.GetWeakPtr())); | 161 weak_factory_.GetWeakPtr())); |
165 } | 162 } |
166 | 163 |
167 void AudioRendererImpl::ResetDecoderDone() { | 164 void AudioRendererImpl::ResetDecoderDone() { |
168 DCHECK(task_runner_->BelongsToCurrentThread()); | 165 DCHECK(task_runner_->BelongsToCurrentThread()); |
169 { | 166 { |
170 base::AutoLock auto_lock(lock_); | 167 base::AutoLock auto_lock(lock_); |
171 if (state_ == kStopped) | 168 if (state_ == kStopped) |
172 return; | 169 return; |
173 | 170 |
174 DCHECK_EQ(state_, kFlushed); | 171 DCHECK_EQ(state_, kFlushed); |
175 DCHECK(!flush_cb_.is_null()); | 172 DCHECK(!flush_cb_.is_null()); |
176 | 173 |
177 audio_clock_.reset(new AudioClock(audio_parameters_.sample_rate())); | 174 audio_clock_.reset(new AudioClock(audio_parameters_.sample_rate())); |
175 buffering_state_ = BUFFERING_HAVE_NOTHING; | |
178 received_end_of_stream_ = false; | 176 received_end_of_stream_ = false; |
179 rendered_end_of_stream_ = false; | 177 rendered_end_of_stream_ = false; |
180 preroll_aborted_ = false; | |
181 | 178 |
182 earliest_end_time_ = now_cb_.Run(); | 179 earliest_end_time_ = now_cb_.Run(); |
183 splicer_->Reset(); | 180 splicer_->Reset(); |
184 if (buffer_converter_) | 181 if (buffer_converter_) |
185 buffer_converter_->Reset(); | 182 buffer_converter_->Reset(); |
186 algorithm_->FlushBuffers(); | 183 algorithm_->FlushBuffers(); |
184 | |
185 ChangeState_Locked(kFlushed); | |
acolwell GONE FROM CHROMIUM
2014/05/13 20:44:27
Why do we need this? The DCHECK on line 171 indica
scherkus (not reviewing)
2014/05/15 23:28:43
Done.
| |
187 } | 186 } |
188 base::ResetAndReturn(&flush_cb_).Run(); | 187 base::ResetAndReturn(&flush_cb_).Run(); |
189 } | 188 } |
190 | 189 |
191 void AudioRendererImpl::Stop(const base::Closure& callback) { | 190 void AudioRendererImpl::Stop(const base::Closure& callback) { |
192 DCHECK(task_runner_->BelongsToCurrentThread()); | 191 DCHECK(task_runner_->BelongsToCurrentThread()); |
193 DCHECK(!callback.is_null()); | 192 DCHECK(!callback.is_null()); |
194 | 193 |
195 // TODO(scherkus): Consider invalidating |weak_factory_| and replacing | 194 // TODO(scherkus): Consider invalidating |weak_factory_| and replacing |
196 // task-running guards that check |state_| with DCHECK(). | 195 // task-running guards that check |state_| with DCHECK(). |
197 | 196 |
198 { | 197 { |
199 base::AutoLock auto_lock(lock_); | 198 base::AutoLock auto_lock(lock_); |
200 | 199 |
201 if (state_ == kStopped) { | 200 if (state_ == kStopped) { |
202 task_runner_->PostTask(FROM_HERE, callback); | 201 task_runner_->PostTask(FROM_HERE, callback); |
203 return; | 202 return; |
204 } | 203 } |
205 | 204 |
206 ChangeState_Locked(kStopped); | 205 ChangeState_Locked(kStopped); |
207 algorithm_.reset(); | 206 algorithm_.reset(); |
208 underflow_cb_.Reset(); | |
209 time_cb_.Reset(); | 207 time_cb_.Reset(); |
210 flush_cb_.Reset(); | 208 flush_cb_.Reset(); |
211 } | 209 } |
212 | 210 |
213 if (sink_) { | 211 if (sink_) { |
214 sink_->Stop(); | 212 sink_->Stop(); |
215 sink_ = NULL; | 213 sink_ = NULL; |
216 } | 214 } |
217 | 215 |
218 audio_buffer_stream_.Stop(callback); | 216 audio_buffer_stream_.Stop(callback); |
219 } | 217 } |
220 | 218 |
221 void AudioRendererImpl::Preroll(base::TimeDelta time, | 219 void AudioRendererImpl::StartPlayingFrom(base::TimeDelta timestamp) { |
222 const PipelineStatusCB& cb) { | 220 DVLOG(1) << __FUNCTION__ << "(" << timestamp.InMicroseconds() << ")"; |
223 DCHECK(task_runner_->BelongsToCurrentThread()); | 221 DCHECK(task_runner_->BelongsToCurrentThread()); |
224 | 222 |
225 base::AutoLock auto_lock(lock_); | 223 base::AutoLock auto_lock(lock_); |
226 DCHECK(!sink_playing_); | 224 DCHECK(!sink_playing_); |
227 DCHECK_EQ(state_, kFlushed); | 225 DCHECK_EQ(state_, kFlushed); |
226 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING); | |
228 DCHECK(!pending_read_) << "Pending read must complete before seeking"; | 227 DCHECK(!pending_read_) << "Pending read must complete before seeking"; |
229 DCHECK(preroll_cb_.is_null()); | |
230 | 228 |
231 ChangeState_Locked(kPrerolling); | 229 ChangeState_Locked(kPlaying); |
232 preroll_cb_ = cb; | 230 start_timestamp_ = timestamp; |
233 preroll_timestamp_ = time; | |
234 | 231 |
235 AttemptRead_Locked(); | 232 AttemptRead_Locked(); |
236 } | 233 } |
237 | 234 |
238 void AudioRendererImpl::Initialize(DemuxerStream* stream, | 235 void AudioRendererImpl::Initialize(DemuxerStream* stream, |
239 const PipelineStatusCB& init_cb, | 236 const PipelineStatusCB& init_cb, |
240 const StatisticsCB& statistics_cb, | 237 const StatisticsCB& statistics_cb, |
241 const base::Closure& underflow_cb, | |
242 const TimeCB& time_cb, | 238 const TimeCB& time_cb, |
239 const BufferingStateCB& buffering_state_cb, | |
243 const base::Closure& ended_cb, | 240 const base::Closure& ended_cb, |
244 const PipelineStatusCB& error_cb) { | 241 const PipelineStatusCB& error_cb) { |
245 DCHECK(task_runner_->BelongsToCurrentThread()); | 242 DCHECK(task_runner_->BelongsToCurrentThread()); |
246 DCHECK(stream); | 243 DCHECK(stream); |
247 DCHECK_EQ(stream->type(), DemuxerStream::AUDIO); | 244 DCHECK_EQ(stream->type(), DemuxerStream::AUDIO); |
248 DCHECK(!init_cb.is_null()); | 245 DCHECK(!init_cb.is_null()); |
249 DCHECK(!statistics_cb.is_null()); | 246 DCHECK(!statistics_cb.is_null()); |
250 DCHECK(!underflow_cb.is_null()); | |
251 DCHECK(!time_cb.is_null()); | 247 DCHECK(!time_cb.is_null()); |
248 DCHECK(!buffering_state_cb.is_null()); | |
252 DCHECK(!ended_cb.is_null()); | 249 DCHECK(!ended_cb.is_null()); |
253 DCHECK(!error_cb.is_null()); | 250 DCHECK(!error_cb.is_null()); |
254 DCHECK_EQ(kUninitialized, state_); | 251 DCHECK_EQ(kUninitialized, state_); |
255 DCHECK(sink_); | 252 DCHECK(sink_); |
256 | 253 |
257 state_ = kInitializing; | 254 state_ = kInitializing; |
258 | 255 |
259 init_cb_ = init_cb; | 256 init_cb_ = init_cb; |
260 underflow_cb_ = underflow_cb; | |
261 time_cb_ = time_cb; | 257 time_cb_ = time_cb; |
258 buffering_state_cb_ = buffering_state_cb; | |
262 ended_cb_ = ended_cb; | 259 ended_cb_ = ended_cb; |
263 error_cb_ = error_cb; | 260 error_cb_ = error_cb; |
264 | 261 |
265 expecting_config_changes_ = stream->SupportsConfigChanges(); | 262 expecting_config_changes_ = stream->SupportsConfigChanges(); |
266 if (!expecting_config_changes_) { | 263 if (!expecting_config_changes_) { |
267 // The actual buffer size is controlled via the size of the AudioBus | 264 // The actual buffer size is controlled via the size of the AudioBus |
268 // provided to Render(), so just choose something reasonable here for looks. | 265 // provided to Render(), so just choose something reasonable here for looks. |
269 int buffer_size = stream->audio_decoder_config().samples_per_second() / 100; | 266 int buffer_size = stream->audio_decoder_config().samples_per_second() / 100; |
270 audio_parameters_.Reset( | 267 audio_parameters_.Reset( |
271 AudioParameters::AUDIO_PCM_LOW_LATENCY, | 268 AudioParameters::AUDIO_PCM_LOW_LATENCY, |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
341 | 338 |
342 // Some sinks play on start... | 339 // Some sinks play on start... |
343 sink_->Pause(); | 340 sink_->Pause(); |
344 } | 341 } |
345 | 342 |
346 DCHECK(!sink_playing_); | 343 DCHECK(!sink_playing_); |
347 | 344 |
348 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); | 345 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); |
349 } | 346 } |
350 | 347 |
351 void AudioRendererImpl::ResumeAfterUnderflow() { | |
352 DCHECK(task_runner_->BelongsToCurrentThread()); | |
353 base::AutoLock auto_lock(lock_); | |
354 if (state_ == kUnderflow) { | |
355 // The "!preroll_aborted_" is a hack. If preroll is aborted, then we | |
356 // shouldn't even reach the kUnderflow state to begin with. But for now | |
357 // we're just making sure that the audio buffer capacity (i.e. the | |
358 // number of bytes that need to be buffered for preroll to complete) | |
359 // does not increase due to an aborted preroll. | |
360 // TODO(vrk): Fix this bug correctly! (crbug.com/151352) | |
361 if (!preroll_aborted_) | |
362 algorithm_->IncreaseQueueCapacity(); | |
363 | |
364 ChangeState_Locked(kRebuffering); | |
365 } | |
366 } | |
367 | |
368 void AudioRendererImpl::SetVolume(float volume) { | 348 void AudioRendererImpl::SetVolume(float volume) { |
369 DCHECK(task_runner_->BelongsToCurrentThread()); | 349 DCHECK(task_runner_->BelongsToCurrentThread()); |
370 DCHECK(sink_); | 350 DCHECK(sink_); |
371 sink_->SetVolume(volume); | 351 sink_->SetVolume(volume); |
372 } | 352 } |
373 | 353 |
374 void AudioRendererImpl::DecodedAudioReady( | 354 void AudioRendererImpl::DecodedAudioReady( |
375 AudioBufferStream::Status status, | 355 AudioBufferStream::Status status, |
376 const scoped_refptr<AudioBuffer>& buffer) { | 356 const scoped_refptr<AudioBuffer>& buffer) { |
377 DVLOG(2) << __FUNCTION__ << "(" << status << ")"; | 357 DVLOG(2) << __FUNCTION__ << "(" << status << ")"; |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
431 if (!need_another_buffer && !CanRead_Locked()) | 411 if (!need_another_buffer && !CanRead_Locked()) |
432 return; | 412 return; |
433 | 413 |
434 AttemptRead_Locked(); | 414 AttemptRead_Locked(); |
435 } | 415 } |
436 | 416 |
437 bool AudioRendererImpl::HandleSplicerBuffer( | 417 bool AudioRendererImpl::HandleSplicerBuffer( |
438 const scoped_refptr<AudioBuffer>& buffer) { | 418 const scoped_refptr<AudioBuffer>& buffer) { |
439 if (buffer->end_of_stream()) { | 419 if (buffer->end_of_stream()) { |
440 received_end_of_stream_ = true; | 420 received_end_of_stream_ = true; |
441 | |
442 // Transition to kPlaying if we are currently handling an underflow since | |
443 // no more data will be arriving. | |
444 if (state_ == kUnderflow || state_ == kRebuffering) | |
445 ChangeState_Locked(kPlaying); | |
446 } else { | 421 } else { |
447 if (state_ == kPrerolling) { | 422 if (state_ == kPlaying) { |
448 if (IsBeforePrerollTime(buffer)) | 423 if (IsBeforeStartTime(buffer)) |
449 return true; | 424 return true; |
450 | 425 |
451 // Trim off any additional time before the preroll timestamp. | 426 // Trim off any additional time before the start timestamp. |
452 const base::TimeDelta trim_time = | 427 const base::TimeDelta trim_time = start_timestamp_ - buffer->timestamp(); |
453 preroll_timestamp_ - buffer->timestamp(); | |
454 if (trim_time > base::TimeDelta()) { | 428 if (trim_time > base::TimeDelta()) { |
455 buffer->TrimStart(buffer->frame_count() * | 429 buffer->TrimStart(buffer->frame_count() * |
456 (static_cast<double>(trim_time.InMicroseconds()) / | 430 (static_cast<double>(trim_time.InMicroseconds()) / |
457 buffer->duration().InMicroseconds())); | 431 buffer->duration().InMicroseconds())); |
458 } | 432 } |
459 // If the entire buffer was trimmed, request a new one. | 433 // If the entire buffer was trimmed, request a new one. |
460 if (!buffer->frame_count()) | 434 if (!buffer->frame_count()) |
461 return true; | 435 return true; |
462 } | 436 } |
463 | 437 |
464 if (state_ != kUninitialized && state_ != kStopped) | 438 if (state_ != kUninitialized && state_ != kStopped) |
465 algorithm_->EnqueueBuffer(buffer); | 439 algorithm_->EnqueueBuffer(buffer); |
466 } | 440 } |
467 | 441 |
468 switch (state_) { | 442 switch (state_) { |
469 case kUninitialized: | 443 case kUninitialized: |
470 case kInitializing: | 444 case kInitializing: |
471 case kFlushing: | 445 case kFlushing: |
472 NOTREACHED(); | 446 NOTREACHED(); |
473 return false; | 447 return false; |
474 | 448 |
475 case kFlushed: | 449 case kFlushed: |
476 DCHECK(!pending_read_); | 450 DCHECK(!pending_read_); |
477 return false; | 451 return false; |
478 | 452 |
479 case kPrerolling: | |
480 if (!buffer->end_of_stream() && !algorithm_->IsQueueFull()) | |
481 return true; | |
482 ChangeState_Locked(kPlaying); | |
483 base::ResetAndReturn(&preroll_cb_).Run(PIPELINE_OK); | |
484 return false; | |
485 | |
486 case kPlaying: | 453 case kPlaying: |
487 case kUnderflow: | 454 if (buffer->end_of_stream() || algorithm_->IsQueueFull()) { |
488 return false; | 455 if (buffering_state_ == BUFFERING_HAVE_NOTHING) { |
489 | 456 buffering_state_ = BUFFERING_HAVE_ENOUGH; |
490 case kRebuffering: | 457 buffering_state_cb_.Run(BUFFERING_HAVE_ENOUGH); |
491 if (!algorithm_->IsQueueFull()) | 458 } |
492 return true; | 459 return false; |
493 ChangeState_Locked(kPlaying); | 460 } |
494 return false; | 461 return true; |
495 | 462 |
496 case kStopped: | 463 case kStopped: |
497 return false; | 464 return false; |
498 } | 465 } |
499 return false; | 466 return false; |
500 } | 467 } |
501 | 468 |
502 void AudioRendererImpl::AttemptRead() { | 469 void AudioRendererImpl::AttemptRead() { |
503 base::AutoLock auto_lock(lock_); | 470 base::AutoLock auto_lock(lock_); |
504 AttemptRead_Locked(); | 471 AttemptRead_Locked(); |
(...skipping 10 matching lines...) Expand all Loading... | |
515 audio_buffer_stream_.Read(base::Bind(&AudioRendererImpl::DecodedAudioReady, | 482 audio_buffer_stream_.Read(base::Bind(&AudioRendererImpl::DecodedAudioReady, |
516 weak_factory_.GetWeakPtr())); | 483 weak_factory_.GetWeakPtr())); |
517 } | 484 } |
518 | 485 |
519 bool AudioRendererImpl::CanRead_Locked() { | 486 bool AudioRendererImpl::CanRead_Locked() { |
520 lock_.AssertAcquired(); | 487 lock_.AssertAcquired(); |
521 | 488 |
522 switch (state_) { | 489 switch (state_) { |
523 case kUninitialized: | 490 case kUninitialized: |
524 case kInitializing: | 491 case kInitializing: |
492 case kFlushing: | |
525 case kFlushed: | 493 case kFlushed: |
526 case kFlushing: | |
527 case kStopped: | 494 case kStopped: |
528 return false; | 495 return false; |
529 | 496 |
530 case kPrerolling: | |
531 case kPlaying: | 497 case kPlaying: |
532 case kUnderflow: | |
533 case kRebuffering: | |
534 break; | 498 break; |
535 } | 499 } |
536 | 500 |
537 return !pending_read_ && !received_end_of_stream_ && | 501 return !pending_read_ && !received_end_of_stream_ && |
538 !algorithm_->IsQueueFull(); | 502 !algorithm_->IsQueueFull(); |
539 } | 503 } |
540 | 504 |
541 void AudioRendererImpl::SetPlaybackRate(float playback_rate) { | 505 void AudioRendererImpl::SetPlaybackRate(float playback_rate) { |
542 DVLOG(1) << __FUNCTION__ << "(" << playback_rate << ")"; | 506 DVLOG(1) << __FUNCTION__ << "(" << playback_rate << ")"; |
543 DCHECK(task_runner_->BelongsToCurrentThread()); | 507 DCHECK(task_runner_->BelongsToCurrentThread()); |
(...skipping 15 matching lines...) Expand all Loading... | |
559 StartRendering_Locked(); | 523 StartRendering_Locked(); |
560 return; | 524 return; |
561 } | 525 } |
562 | 526 |
563 if (current_playback_rate != 0 && playback_rate == 0) { | 527 if (current_playback_rate != 0 && playback_rate == 0) { |
564 StopRendering_Locked(); | 528 StopRendering_Locked(); |
565 return; | 529 return; |
566 } | 530 } |
567 } | 531 } |
568 | 532 |
569 bool AudioRendererImpl::IsBeforePrerollTime( | 533 bool AudioRendererImpl::IsBeforeStartTime( |
570 const scoped_refptr<AudioBuffer>& buffer) { | 534 const scoped_refptr<AudioBuffer>& buffer) { |
571 DCHECK_EQ(state_, kPrerolling); | 535 DCHECK_EQ(state_, kPlaying); |
572 return buffer && !buffer->end_of_stream() && | 536 return buffer && !buffer->end_of_stream() && |
573 (buffer->timestamp() + buffer->duration()) < preroll_timestamp_; | 537 (buffer->timestamp() + buffer->duration()) < start_timestamp_; |
574 } | 538 } |
575 | 539 |
576 int AudioRendererImpl::Render(AudioBus* audio_bus, | 540 int AudioRendererImpl::Render(AudioBus* audio_bus, |
577 int audio_delay_milliseconds) { | 541 int audio_delay_milliseconds) { |
578 const int requested_frames = audio_bus->frames(); | 542 const int requested_frames = audio_bus->frames(); |
579 base::TimeDelta playback_delay = base::TimeDelta::FromMilliseconds( | 543 base::TimeDelta playback_delay = base::TimeDelta::FromMilliseconds( |
580 audio_delay_milliseconds); | 544 audio_delay_milliseconds); |
581 const int delay_frames = static_cast<int>(playback_delay.InSecondsF() * | 545 const int delay_frames = static_cast<int>(playback_delay.InSecondsF() * |
582 audio_parameters_.sample_rate()); | 546 audio_parameters_.sample_rate()); |
583 int frames_written = 0; | 547 int frames_written = 0; |
584 base::Closure time_cb; | 548 base::Closure time_cb; |
585 base::Closure underflow_cb; | |
586 { | 549 { |
587 base::AutoLock auto_lock(lock_); | 550 base::AutoLock auto_lock(lock_); |
588 | 551 |
589 // Ensure Stop() hasn't destroyed our |algorithm_| on the pipeline thread. | 552 // Ensure Stop() hasn't destroyed our |algorithm_| on the pipeline thread. |
590 if (!algorithm_) { | 553 if (!algorithm_) { |
591 audio_clock_->WroteSilence(requested_frames, delay_frames); | 554 audio_clock_->WroteSilence(requested_frames, delay_frames); |
592 return 0; | 555 return 0; |
593 } | 556 } |
594 | 557 |
595 float playback_rate = algorithm_->playback_rate(); | 558 float playback_rate = algorithm_->playback_rate(); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
628 } | 591 } |
629 audio_clock_->WroteSilence(requested_frames - frames_written, delay_frames); | 592 audio_clock_->WroteSilence(requested_frames - frames_written, delay_frames); |
630 | 593 |
631 if (frames_written == 0) { | 594 if (frames_written == 0) { |
632 const base::TimeTicks now = now_cb_.Run(); | 595 const base::TimeTicks now = now_cb_.Run(); |
633 | 596 |
634 if (received_end_of_stream_ && !rendered_end_of_stream_ && | 597 if (received_end_of_stream_ && !rendered_end_of_stream_ && |
635 now >= earliest_end_time_) { | 598 now >= earliest_end_time_) { |
636 rendered_end_of_stream_ = true; | 599 rendered_end_of_stream_ = true; |
637 ended_cb_.Run(); | 600 ended_cb_.Run(); |
638 } else if (!received_end_of_stream_ && state_ == kPlaying && | 601 } else if (!received_end_of_stream_ && state_ == kPlaying) { |
639 !underflow_disabled_) { | 602 if (buffering_state_ != BUFFERING_HAVE_NOTHING) { |
640 ChangeState_Locked(kUnderflow); | 603 algorithm_->IncreaseQueueCapacity(); |
641 underflow_cb = underflow_cb_; | 604 buffering_state_ = BUFFERING_HAVE_NOTHING; |
605 buffering_state_cb_.Run(BUFFERING_HAVE_NOTHING); | |
606 } | |
642 } else { | 607 } else { |
643 // We can't write any data this cycle. For example, we may have | 608 // We can't write any data this cycle. For example, we may have |
644 // sent all available data to the audio device while not reaching | 609 // sent all available data to the audio device while not reaching |
645 // |earliest_end_time_|. | 610 // |earliest_end_time_|. |
646 } | 611 } |
647 } | 612 } |
648 | 613 |
649 if (CanRead_Locked()) { | 614 if (CanRead_Locked()) { |
650 task_runner_->PostTask(FROM_HERE, | 615 task_runner_->PostTask(FROM_HERE, |
651 base::Bind(&AudioRendererImpl::AttemptRead, | 616 base::Bind(&AudioRendererImpl::AttemptRead, |
(...skipping 12 matching lines...) Expand all Loading... | |
664 | 629 |
665 if (frames_written > 0) { | 630 if (frames_written > 0) { |
666 UpdateEarliestEndTime_Locked( | 631 UpdateEarliestEndTime_Locked( |
667 frames_written, playback_delay, now_cb_.Run()); | 632 frames_written, playback_delay, now_cb_.Run()); |
668 } | 633 } |
669 } | 634 } |
670 | 635 |
671 if (!time_cb.is_null()) | 636 if (!time_cb.is_null()) |
672 time_cb.Run(); | 637 time_cb.Run(); |
673 | 638 |
674 if (!underflow_cb.is_null()) | |
675 underflow_cb.Run(); | |
676 | |
677 DCHECK_LE(frames_written, requested_frames); | 639 DCHECK_LE(frames_written, requested_frames); |
678 return frames_written; | 640 return frames_written; |
679 } | 641 } |
680 | 642 |
681 void AudioRendererImpl::UpdateEarliestEndTime_Locked( | 643 void AudioRendererImpl::UpdateEarliestEndTime_Locked( |
682 int frames_filled, const base::TimeDelta& playback_delay, | 644 int frames_filled, const base::TimeDelta& playback_delay, |
683 const base::TimeTicks& time_now) { | 645 const base::TimeTicks& time_now) { |
684 DCHECK_GT(frames_filled, 0); | 646 DCHECK_GT(frames_filled, 0); |
685 | 647 |
686 base::TimeDelta predicted_play_time = base::TimeDelta::FromMicroseconds( | 648 base::TimeDelta predicted_play_time = base::TimeDelta::FromMicroseconds( |
687 static_cast<float>(frames_filled) * base::Time::kMicrosecondsPerSecond / | 649 static_cast<float>(frames_filled) * base::Time::kMicrosecondsPerSecond / |
688 audio_parameters_.sample_rate()); | 650 audio_parameters_.sample_rate()); |
689 | 651 |
690 lock_.AssertAcquired(); | 652 lock_.AssertAcquired(); |
691 earliest_end_time_ = std::max( | 653 earliest_end_time_ = std::max( |
692 earliest_end_time_, time_now + playback_delay + predicted_play_time); | 654 earliest_end_time_, time_now + playback_delay + predicted_play_time); |
693 } | 655 } |
694 | 656 |
695 void AudioRendererImpl::OnRenderError() { | 657 void AudioRendererImpl::OnRenderError() { |
696 // UMA data tells us this happens ~0.01% of the time. Trigger an error instead | 658 // UMA data tells us this happens ~0.01% of the time. Trigger an error instead |
697 // of trying to gracefully fall back to a fake sink. It's very likely | 659 // of trying to gracefully fall back to a fake sink. It's very likely |
698 // OnRenderError() should be removed and the audio stack handle errors without | 660 // OnRenderError() should be removed and the audio stack handle errors without |
699 // notifying clients. See http://crbug.com/234708 for details. | 661 // notifying clients. See http://crbug.com/234708 for details. |
700 HistogramRendererEvent(RENDER_ERROR); | 662 HistogramRendererEvent(RENDER_ERROR); |
701 error_cb_.Run(PIPELINE_ERROR_DECODE); | 663 error_cb_.Run(PIPELINE_ERROR_DECODE); |
702 } | 664 } |
703 | 665 |
704 void AudioRendererImpl::DisableUnderflowForTesting() { | |
705 underflow_disabled_ = true; | |
706 } | |
707 | |
708 void AudioRendererImpl::HandleAbortedReadOrDecodeError(bool is_decode_error) { | 666 void AudioRendererImpl::HandleAbortedReadOrDecodeError(bool is_decode_error) { |
709 lock_.AssertAcquired(); | 667 lock_.AssertAcquired(); |
710 | 668 |
711 PipelineStatus status = is_decode_error ? PIPELINE_ERROR_DECODE : PIPELINE_OK; | 669 PipelineStatus status = is_decode_error ? PIPELINE_ERROR_DECODE : PIPELINE_OK; |
712 switch (state_) { | 670 switch (state_) { |
713 case kUninitialized: | 671 case kUninitialized: |
714 case kInitializing: | 672 case kInitializing: |
715 NOTREACHED(); | 673 NOTREACHED(); |
716 return; | 674 return; |
717 case kFlushing: | 675 case kFlushing: |
718 ChangeState_Locked(kFlushed); | 676 ChangeState_Locked(kFlushed); |
719 | |
720 if (status == PIPELINE_OK) { | 677 if (status == PIPELINE_OK) { |
721 DoFlush_Locked(); | 678 DoFlush_Locked(); |
722 return; | 679 return; |
723 } | 680 } |
724 | 681 |
725 error_cb_.Run(status); | 682 error_cb_.Run(status); |
726 base::ResetAndReturn(&flush_cb_).Run(); | 683 base::ResetAndReturn(&flush_cb_).Run(); |
727 return; | 684 return; |
728 case kPrerolling: | 685 |
729 // This is a signal for abort if it's not an error. | |
730 preroll_aborted_ = !is_decode_error; | |
731 ChangeState_Locked(kPlaying); | |
732 base::ResetAndReturn(&preroll_cb_).Run(status); | |
733 return; | |
734 case kFlushed: | 686 case kFlushed: |
735 case kPlaying: | 687 case kPlaying: |
736 case kUnderflow: | |
737 case kRebuffering: | |
738 case kStopped: | 688 case kStopped: |
739 if (status != PIPELINE_OK) | 689 if (status != PIPELINE_OK) |
740 error_cb_.Run(status); | 690 error_cb_.Run(status); |
741 return; | 691 return; |
742 } | 692 } |
743 } | 693 } |
744 | 694 |
745 void AudioRendererImpl::ChangeState_Locked(State new_state) { | 695 void AudioRendererImpl::ChangeState_Locked(State new_state) { |
746 DVLOG(1) << __FUNCTION__ << " : " << state_ << " -> " << new_state; | 696 DVLOG(1) << __FUNCTION__ << " : " << state_ << " -> " << new_state; |
747 lock_.AssertAcquired(); | 697 lock_.AssertAcquired(); |
(...skipping 10 matching lines...) Expand all Loading... | |
758 DCHECK(expecting_config_changes_); | 708 DCHECK(expecting_config_changes_); |
759 buffer_converter_->ResetTimestampState(); | 709 buffer_converter_->ResetTimestampState(); |
760 // Drain flushed buffers from the converter so the AudioSplicer receives all | 710 // Drain flushed buffers from the converter so the AudioSplicer receives all |
761 // data ahead of any OnNewSpliceBuffer() calls. Since discontinuities should | 711 // data ahead of any OnNewSpliceBuffer() calls. Since discontinuities should |
762 // only appear after config changes, AddInput() should never fail here. | 712 // only appear after config changes, AddInput() should never fail here. |
763 while (buffer_converter_->HasNextBuffer()) | 713 while (buffer_converter_->HasNextBuffer()) |
764 CHECK(splicer_->AddInput(buffer_converter_->GetNextBuffer())); | 714 CHECK(splicer_->AddInput(buffer_converter_->GetNextBuffer())); |
765 } | 715 } |
766 | 716 |
767 } // namespace media | 717 } // namespace media |
OLD | NEW |