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 weak_factory_(this), | 49 weak_factory_(this), |
47 sink_(sink), | 50 sink_(sink), |
48 audio_buffer_stream_(task_runner, | 51 audio_buffer_stream_(task_runner, |
49 decoders.Pass(), | 52 decoders.Pass(), |
50 set_decryptor_ready_cb), | 53 set_decryptor_ready_cb), |
54 hardware_config_(hardware_config), | |
51 now_cb_(base::Bind(&base::TimeTicks::Now)), | 55 now_cb_(base::Bind(&base::TimeTicks::Now)), |
52 state_(kUninitialized), | 56 state_(kUninitialized), |
53 sink_playing_(false), | 57 sink_playing_(false), |
54 pending_read_(false), | 58 pending_read_(false), |
55 received_end_of_stream_(false), | 59 received_end_of_stream_(false), |
56 rendered_end_of_stream_(false), | 60 rendered_end_of_stream_(false), |
57 audio_time_buffered_(kNoTimestamp()), | 61 audio_time_buffered_(kNoTimestamp()), |
58 current_time_(kNoTimestamp()), | 62 current_time_(kNoTimestamp()), |
59 underflow_disabled_(false), | 63 underflow_disabled_(false), |
60 preroll_aborted_(false) {} | 64 preroll_aborted_(false) {} |
(...skipping 100 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() | |
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 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
267 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_ABORT); | 273 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_ABORT); |
268 return; | 274 return; |
269 } | 275 } |
270 | 276 |
271 if (!success) { | 277 if (!success) { |
272 state_ = kUninitialized; | 278 state_ = kUninitialized; |
273 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED); | 279 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED); |
274 return; | 280 return; |
275 } | 281 } |
276 | 282 |
277 int sample_rate = audio_buffer_stream_.decoder()->samples_per_second(); | 283 // TODO(rileya): Support hardware config changes |
rileya (GONE FROM CHROMIUM)
2014/03/07 01:19:29
What do we currently do when the hardware config c
DaleCurtis
2014/03/07 02:00:10
Nothing currently. It'll get resampled / remixed a
| |
284 audio_parameters_ = hardware_config_.GetOutputConfig(); | |
278 | 285 |
279 // The actual buffer size is controlled via the size of the AudioBus | |
280 // provided to Render(), so just choose something reasonable here for looks. | |
281 int buffer_size = audio_buffer_stream_.decoder()->samples_per_second() / 100; | |
282 | |
283 // TODO(rileya): Remove the channel_layout/bits_per_channel/samples_per_second | |
284 // getters from AudioDecoder, and adjust this accordingly. | |
285 audio_parameters_ = | |
286 AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY, | |
287 audio_buffer_stream_.decoder()->channel_layout(), | |
288 sample_rate, | |
289 audio_buffer_stream_.decoder()->bits_per_channel(), | |
290 buffer_size); | |
291 if (!audio_parameters_.IsValid()) { | 286 if (!audio_parameters_.IsValid()) { |
292 ChangeState_Locked(kUninitialized); | 287 ChangeState_Locked(kUninitialized); |
293 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_INITIALIZATION_FAILED); | 288 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_INITIALIZATION_FAILED); |
294 return; | 289 return; |
295 } | 290 } |
296 | 291 |
297 splicer_.reset(new AudioSplicer(sample_rate)); | 292 buffer_converter_.reset(new AudioBufferConverter(audio_parameters_)); |
293 splicer_.reset(new AudioSplicer(audio_parameters_.sample_rate())); | |
298 | 294 |
299 // We're all good! Continue initializing the rest of the audio renderer | 295 // We're all good! Continue initializing the rest of the audio renderer |
300 // based on the decoder format. | 296 // based on the decoder format. |
301 algorithm_.reset(new AudioRendererAlgorithm()); | 297 algorithm_.reset(new AudioRendererAlgorithm()); |
302 algorithm_->Initialize(0, audio_parameters_); | 298 algorithm_->Initialize(0, audio_parameters_); |
303 | 299 |
304 ChangeState_Locked(kPaused); | 300 ChangeState_Locked(kPaused); |
305 | 301 |
306 HistogramRendererEvent(INITIALIZED); | 302 HistogramRendererEvent(INITIALIZED); |
307 | 303 |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
367 | 363 |
368 DCHECK_EQ(status, AudioBufferStream::OK); | 364 DCHECK_EQ(status, AudioBufferStream::OK); |
369 DCHECK(buffer.get()); | 365 DCHECK(buffer.get()); |
370 | 366 |
371 if (state_ == kFlushing) { | 367 if (state_ == kFlushing) { |
372 ChangeState_Locked(kPaused); | 368 ChangeState_Locked(kPaused); |
373 DoFlush_Locked(); | 369 DoFlush_Locked(); |
374 return; | 370 return; |
375 } | 371 } |
376 | 372 |
377 if (!splicer_->AddInput(buffer)) { | 373 buffer_converter_->AddInput(buffer); |
378 HandleAbortedReadOrDecodeError(true); | 374 bool need_another_buffer = false; |
379 return; | |
380 } | |
381 | 375 |
382 if (!splicer_->HasNextBuffer()) { | 376 if (!buffer_converter_->HasNextBuffer()) { |
383 AttemptRead_Locked(); | 377 AttemptRead_Locked(); |
384 return; | 378 return; |
385 } | 379 } |
386 | 380 |
387 bool need_another_buffer = false; | 381 while (buffer_converter_->HasNextBuffer()) { |
388 while (splicer_->HasNextBuffer()) | 382 scoped_refptr<AudioBuffer> converted_buffer = |
389 need_another_buffer = HandleSplicerBuffer(splicer_->GetNextBuffer()); | 383 buffer_converter_->GetNextBuffer(); |
384 | |
385 if (!splicer_->AddInput(converted_buffer)) { | |
386 HandleAbortedReadOrDecodeError(true); | |
387 return; | |
388 } | |
389 | |
390 while (splicer_->HasNextBuffer()) | |
391 need_another_buffer = HandleSplicerBuffer(splicer_->GetNextBuffer()); | |
392 } | |
390 | 393 |
391 if (!need_another_buffer && !CanRead_Locked()) | 394 if (!need_another_buffer && !CanRead_Locked()) |
392 return; | 395 return; |
393 | 396 |
394 AttemptRead_Locked(); | 397 AttemptRead_Locked(); |
395 } | 398 } |
396 | 399 |
397 bool AudioRendererImpl::HandleSplicerBuffer( | 400 bool AudioRendererImpl::HandleSplicerBuffer( |
398 const scoped_refptr<AudioBuffer>& buffer) { | 401 const scoped_refptr<AudioBuffer>& buffer) { |
402 | |
399 if (buffer->end_of_stream()) { | 403 if (buffer->end_of_stream()) { |
400 received_end_of_stream_ = true; | 404 received_end_of_stream_ = true; |
401 | 405 |
402 // Transition to kPlaying if we are currently handling an underflow since | 406 // Transition to kPlaying if we are currently handling an underflow since |
403 // no more data will be arriving. | 407 // no more data will be arriving. |
404 if (state_ == kUnderflow || state_ == kRebuffering) | 408 if (state_ == kUnderflow || state_ == kRebuffering) |
405 ChangeState_Locked(kPlaying); | 409 ChangeState_Locked(kPlaying); |
406 } else { | 410 } else { |
407 if (state_ == kPrerolling) { | 411 if (state_ == kPrerolling) { |
408 if (IsBeforePrerollTime(buffer)) | 412 if (IsBeforePrerollTime(buffer)) |
(...skipping 296 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 |