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/metrics/histogram.h" | 15 #include "base/metrics/histogram.h" |
16 #include "base/single_thread_task_runner.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_buffer_converter.h" | |
19 #include "media/base/audio_hardware_config.h" | |
18 #include "media/base/audio_splicer.h" | 20 #include "media/base/audio_splicer.h" |
19 #include "media/base/bind_to_current_loop.h" | 21 #include "media/base/bind_to_current_loop.h" |
20 #include "media/base/demuxer_stream.h" | 22 #include "media/base/demuxer_stream.h" |
21 #include "media/filters/decrypting_demuxer_stream.h" | 23 #include "media/filters/decrypting_demuxer_stream.h" |
22 | 24 |
23 namespace media { | 25 namespace media { |
24 | 26 |
25 namespace { | 27 namespace { |
26 | 28 |
27 enum AudioRendererEvent { | 29 enum AudioRendererEvent { |
28 INITIALIZED, | 30 INITIALIZED, |
29 RENDER_ERROR, | 31 RENDER_ERROR, |
30 RENDER_EVENT_MAX = RENDER_ERROR, | 32 RENDER_EVENT_MAX = RENDER_ERROR, |
31 }; | 33 }; |
32 | 34 |
33 void HistogramRendererEvent(AudioRendererEvent event) { | 35 void HistogramRendererEvent(AudioRendererEvent event) { |
34 UMA_HISTOGRAM_ENUMERATION( | 36 UMA_HISTOGRAM_ENUMERATION( |
35 "Media.AudioRendererEvents", event, RENDER_EVENT_MAX + 1); | 37 "Media.AudioRendererEvents", event, RENDER_EVENT_MAX + 1); |
36 } | 38 } |
37 | 39 |
38 } // namespace | 40 } // namespace |
39 | 41 |
40 AudioRendererImpl::AudioRendererImpl( | 42 AudioRendererImpl::AudioRendererImpl( |
41 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, | 43 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, |
42 media::AudioRendererSink* sink, | 44 media::AudioRendererSink* sink, |
43 ScopedVector<AudioDecoder> decoders, | 45 ScopedVector<AudioDecoder> decoders, |
44 const SetDecryptorReadyCB& set_decryptor_ready_cb) | 46 const SetDecryptorReadyCB& set_decryptor_ready_cb, |
47 const AudioHardwareConfig& hardware_config) | |
45 : task_runner_(task_runner), | 48 : task_runner_(task_runner), |
46 sink_(sink), | 49 sink_(sink), |
47 audio_buffer_stream_(task_runner, | 50 audio_buffer_stream_(task_runner, |
48 decoders.Pass(), | 51 decoders.Pass(), |
49 set_decryptor_ready_cb), | 52 set_decryptor_ready_cb), |
53 hardware_config_(hardware_config), | |
50 now_cb_(base::Bind(&base::TimeTicks::Now)), | 54 now_cb_(base::Bind(&base::TimeTicks::Now)), |
51 state_(kUninitialized), | 55 state_(kUninitialized), |
52 sink_playing_(false), | 56 sink_playing_(false), |
53 pending_read_(false), | 57 pending_read_(false), |
54 received_end_of_stream_(false), | 58 received_end_of_stream_(false), |
55 rendered_end_of_stream_(false), | 59 rendered_end_of_stream_(false), |
56 audio_time_buffered_(kNoTimestamp()), | 60 audio_time_buffered_(kNoTimestamp()), |
57 current_time_(kNoTimestamp()), | 61 current_time_(kNoTimestamp()), |
58 underflow_disabled_(false), | 62 underflow_disabled_(false), |
59 preroll_aborted_(false), | 63 preroll_aborted_(false), |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
161 DCHECK(!flush_cb_.is_null()); | 165 DCHECK(!flush_cb_.is_null()); |
162 | 166 |
163 audio_time_buffered_ = kNoTimestamp(); | 167 audio_time_buffered_ = kNoTimestamp(); |
164 current_time_ = kNoTimestamp(); | 168 current_time_ = kNoTimestamp(); |
165 received_end_of_stream_ = false; | 169 received_end_of_stream_ = false; |
166 rendered_end_of_stream_ = false; | 170 rendered_end_of_stream_ = false; |
167 preroll_aborted_ = false; | 171 preroll_aborted_ = false; |
168 | 172 |
169 earliest_end_time_ = now_cb_.Run(); | 173 earliest_end_time_ = now_cb_.Run(); |
170 splicer_->Reset(); | 174 splicer_->Reset(); |
175 // TODO: add a Reset() or Flush() | |
rileya (GONE FROM CHROMIUM)
2014/03/20 00:55:11
This is an immediate TODO for this CL that I forgo
| |
176 buffer_converter_.reset(new AudioBufferConverter(audio_parameters_)); | |
171 algorithm_->FlushBuffers(); | 177 algorithm_->FlushBuffers(); |
172 } | 178 } |
173 base::ResetAndReturn(&flush_cb_).Run(); | 179 base::ResetAndReturn(&flush_cb_).Run(); |
174 } | 180 } |
175 | 181 |
176 void AudioRendererImpl::Stop(const base::Closure& callback) { | 182 void AudioRendererImpl::Stop(const base::Closure& callback) { |
177 DCHECK(task_runner_->BelongsToCurrentThread()); | 183 DCHECK(task_runner_->BelongsToCurrentThread()); |
178 DCHECK(!callback.is_null()); | 184 DCHECK(!callback.is_null()); |
179 | 185 |
180 // TODO(scherkus): Consider invalidating |weak_factory_| and replacing | 186 // TODO(scherkus): Consider invalidating |weak_factory_| and replacing |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
266 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_ABORT); | 272 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_ABORT); |
267 return; | 273 return; |
268 } | 274 } |
269 | 275 |
270 if (!success) { | 276 if (!success) { |
271 state_ = kUninitialized; | 277 state_ = kUninitialized; |
272 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED); | 278 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED); |
273 return; | 279 return; |
274 } | 280 } |
275 | 281 |
276 int sample_rate = audio_buffer_stream_.decoder()->samples_per_second(); | 282 // TODO(rileya): Support hardware config changes |
283 audio_parameters_ = hardware_config_.GetOutputConfig(); | |
277 | 284 |
278 // The actual buffer size is controlled via the size of the AudioBus | |
279 // provided to Render(), so just choose something reasonable here for looks. | |
280 int buffer_size = audio_buffer_stream_.decoder()->samples_per_second() / 100; | |
281 | |
282 // TODO(rileya): Remove the channel_layout/bits_per_channel/samples_per_second | |
283 // getters from AudioDecoder, and adjust this accordingly. | |
284 audio_parameters_ = | |
285 AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY, | |
286 audio_buffer_stream_.decoder()->channel_layout(), | |
287 sample_rate, | |
288 audio_buffer_stream_.decoder()->bits_per_channel(), | |
289 buffer_size); | |
290 if (!audio_parameters_.IsValid()) { | 285 if (!audio_parameters_.IsValid()) { |
291 ChangeState_Locked(kUninitialized); | 286 ChangeState_Locked(kUninitialized); |
292 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_INITIALIZATION_FAILED); | 287 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_INITIALIZATION_FAILED); |
293 return; | 288 return; |
294 } | 289 } |
295 | 290 |
296 splicer_.reset(new AudioSplicer(sample_rate)); | 291 buffer_converter_.reset(new AudioBufferConverter(audio_parameters_)); |
292 splicer_.reset(new AudioSplicer(audio_parameters_.sample_rate())); | |
297 | 293 |
298 // We're all good! Continue initializing the rest of the audio renderer | 294 // We're all good! Continue initializing the rest of the audio renderer |
299 // based on the decoder format. | 295 // based on the decoder format. |
300 algorithm_.reset(new AudioRendererAlgorithm()); | 296 algorithm_.reset(new AudioRendererAlgorithm()); |
301 algorithm_->Initialize(0, audio_parameters_); | 297 algorithm_->Initialize(0, audio_parameters_); |
302 | 298 |
303 ChangeState_Locked(kPaused); | 299 ChangeState_Locked(kPaused); |
304 | 300 |
305 HistogramRendererEvent(INITIALIZED); | 301 HistogramRendererEvent(INITIALIZED); |
306 | 302 |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
366 | 362 |
367 DCHECK_EQ(status, AudioBufferStream::OK); | 363 DCHECK_EQ(status, AudioBufferStream::OK); |
368 DCHECK(buffer.get()); | 364 DCHECK(buffer.get()); |
369 | 365 |
370 if (state_ == kFlushing) { | 366 if (state_ == kFlushing) { |
371 ChangeState_Locked(kPaused); | 367 ChangeState_Locked(kPaused); |
372 DoFlush_Locked(); | 368 DoFlush_Locked(); |
373 return; | 369 return; |
374 } | 370 } |
375 | 371 |
376 if (!splicer_->AddInput(buffer)) { | 372 buffer_converter_->AddInput(buffer); |
377 HandleAbortedReadOrDecodeError(true); | 373 bool need_another_buffer = false; |
DaleCurtis
2014/03/20 19:29:01
Move with while below?
rileya (GONE FROM CHROMIUM)
2014/03/21 20:58:49
Done.
| |
378 return; | |
379 } | |
380 | 374 |
381 if (!splicer_->HasNextBuffer()) { | 375 if (!buffer_converter_->HasNextBuffer()) { |
382 AttemptRead_Locked(); | 376 AttemptRead_Locked(); |
383 return; | 377 return; |
384 } | 378 } |
385 | 379 |
386 bool need_another_buffer = false; | 380 while (buffer_converter_->HasNextBuffer()) { |
387 while (splicer_->HasNextBuffer()) | 381 scoped_refptr<AudioBuffer> converted_buffer = |
388 need_another_buffer = HandleSplicerBuffer(splicer_->GetNextBuffer()); | 382 buffer_converter_->GetNextBuffer(); |
383 | |
384 if (!splicer_->AddInput(converted_buffer)) { | |
385 HandleAbortedReadOrDecodeError(true); | |
386 return; | |
387 } | |
388 | |
389 while (splicer_->HasNextBuffer()) | |
390 need_another_buffer = HandleSplicerBuffer(splicer_->GetNextBuffer()); | |
391 } | |
389 | 392 |
390 if (!need_another_buffer && !CanRead_Locked()) | 393 if (!need_another_buffer && !CanRead_Locked()) |
391 return; | 394 return; |
392 | 395 |
393 AttemptRead_Locked(); | 396 AttemptRead_Locked(); |
394 } | 397 } |
395 | 398 |
396 bool AudioRendererImpl::HandleSplicerBuffer( | 399 bool AudioRendererImpl::HandleSplicerBuffer( |
397 const scoped_refptr<AudioBuffer>& buffer) { | 400 const scoped_refptr<AudioBuffer>& buffer) { |
401 | |
DaleCurtis
2014/03/20 19:29:01
No extra line.
rileya (GONE FROM CHROMIUM)
2014/03/21 20:58:49
Done.
| |
398 if (buffer->end_of_stream()) { | 402 if (buffer->end_of_stream()) { |
399 received_end_of_stream_ = true; | 403 received_end_of_stream_ = true; |
400 | 404 |
401 // Transition to kPlaying if we are currently handling an underflow since | 405 // Transition to kPlaying if we are currently handling an underflow since |
402 // no more data will be arriving. | 406 // no more data will be arriving. |
403 if (state_ == kUnderflow || state_ == kRebuffering) | 407 if (state_ == kUnderflow || state_ == kRebuffering) |
404 ChangeState_Locked(kPlaying); | 408 ChangeState_Locked(kPlaying); |
405 } else { | 409 } else { |
406 if (state_ == kPrerolling) { | 410 if (state_ == kPrerolling) { |
407 if (IsBeforePrerollTime(buffer)) | 411 if (IsBeforePrerollTime(buffer)) |
(...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
705 } | 709 } |
706 } | 710 } |
707 | 711 |
708 void AudioRendererImpl::ChangeState_Locked(State new_state) { | 712 void AudioRendererImpl::ChangeState_Locked(State new_state) { |
709 DVLOG(1) << __FUNCTION__ << " : " << state_ << " -> " << new_state; | 713 DVLOG(1) << __FUNCTION__ << " : " << state_ << " -> " << new_state; |
710 lock_.AssertAcquired(); | 714 lock_.AssertAcquired(); |
711 state_ = new_state; | 715 state_ = new_state; |
712 } | 716 } |
713 | 717 |
714 } // namespace media | 718 } // namespace media |
OLD | NEW |