Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(823)

Side by Side Diff: media/filters/audio_renderer_impl.cc

Issue 177333003: Add support for midstream audio configuration changes. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@ABS
Patch Set: address comments Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 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),
60 weak_factory_(this) { 64 weak_factory_(this) {
61 audio_buffer_stream_.set_splice_observer(base::Bind( 65 audio_buffer_stream_.set_splice_observer(base::Bind(
62 &AudioRendererImpl::OnNewSpliceBuffer, weak_factory_.GetWeakPtr())); 66 &AudioRendererImpl::OnNewSpliceBuffer, weak_factory_.GetWeakPtr()));
67 audio_buffer_stream_.set_config_change_observer(base::Bind(
68 &AudioRendererImpl::OnConfigChange, weak_factory_.GetWeakPtr()));
63 } 69 }
64 70
65 AudioRendererImpl::~AudioRendererImpl() { 71 AudioRendererImpl::~AudioRendererImpl() {
66 // Stop() should have been called and |algorithm_| should have been destroyed. 72 // Stop() should have been called and |algorithm_| should have been destroyed.
67 DCHECK(state_ == kUninitialized || state_ == kStopped); 73 DCHECK(state_ == kUninitialized || state_ == kStopped);
68 DCHECK(!algorithm_.get()); 74 DCHECK(!algorithm_.get());
69 } 75 }
70 76
71 void AudioRendererImpl::Play(const base::Closure& callback) { 77 void AudioRendererImpl::Play(const base::Closure& callback) {
72 DCHECK(task_runner_->BelongsToCurrentThread()); 78 DCHECK(task_runner_->BelongsToCurrentThread());
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
164 DCHECK(!flush_cb_.is_null()); 170 DCHECK(!flush_cb_.is_null());
165 171
166 audio_time_buffered_ = kNoTimestamp(); 172 audio_time_buffered_ = kNoTimestamp();
167 current_time_ = kNoTimestamp(); 173 current_time_ = kNoTimestamp();
168 received_end_of_stream_ = false; 174 received_end_of_stream_ = false;
169 rendered_end_of_stream_ = false; 175 rendered_end_of_stream_ = false;
170 preroll_aborted_ = false; 176 preroll_aborted_ = false;
171 177
172 earliest_end_time_ = now_cb_.Run(); 178 earliest_end_time_ = now_cb_.Run();
173 splicer_->Reset(); 179 splicer_->Reset();
180 if (buffer_converter_)
181 buffer_converter_->Reset();
174 algorithm_->FlushBuffers(); 182 algorithm_->FlushBuffers();
175 } 183 }
176 base::ResetAndReturn(&flush_cb_).Run(); 184 base::ResetAndReturn(&flush_cb_).Run();
177 } 185 }
178 186
179 void AudioRendererImpl::Stop(const base::Closure& callback) { 187 void AudioRendererImpl::Stop(const base::Closure& callback) {
180 DCHECK(task_runner_->BelongsToCurrentThread()); 188 DCHECK(task_runner_->BelongsToCurrentThread());
181 DCHECK(!callback.is_null()); 189 DCHECK(!callback.is_null());
182 190
183 // TODO(scherkus): Consider invalidating |weak_factory_| and replacing 191 // TODO(scherkus): Consider invalidating |weak_factory_| and replacing
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
246 254
247 state_ = kInitializing; 255 state_ = kInitializing;
248 256
249 init_cb_ = init_cb; 257 init_cb_ = init_cb;
250 underflow_cb_ = underflow_cb; 258 underflow_cb_ = underflow_cb;
251 time_cb_ = time_cb; 259 time_cb_ = time_cb;
252 ended_cb_ = ended_cb; 260 ended_cb_ = ended_cb;
253 disabled_cb_ = disabled_cb; 261 disabled_cb_ = disabled_cb;
254 error_cb_ = error_cb; 262 error_cb_ = error_cb;
255 263
264 expecting_config_changes_ = stream->SupportsConfigChanges();
265 if (!expecting_config_changes_) {
266 // The actual buffer size is controlled via the size of the AudioBus
267 // provided to Render(), so just choose something reasonable here for looks.
268 int buffer_size = stream->audio_decoder_config().samples_per_second() / 100;
269 audio_parameters_.Reset(
270 AudioParameters::AUDIO_PCM_LOW_LATENCY,
271 stream->audio_decoder_config().channel_layout(),
272 ChannelLayoutToChannelCount(
273 stream->audio_decoder_config().channel_layout()),
274 0,
275 stream->audio_decoder_config().samples_per_second(),
276 stream->audio_decoder_config().bits_per_channel(),
277 buffer_size);
278 buffer_converter_.reset();
279 } else {
280 // TODO(rileya): Support hardware config changes
281 audio_parameters_ = hardware_config_->GetOutputConfig();
282 }
283
256 audio_buffer_stream_.Initialize( 284 audio_buffer_stream_.Initialize(
257 stream, 285 stream,
258 statistics_cb, 286 statistics_cb,
259 base::Bind(&AudioRendererImpl::OnAudioBufferStreamInitialized, 287 base::Bind(&AudioRendererImpl::OnAudioBufferStreamInitialized,
260 weak_factory_.GetWeakPtr())); 288 weak_factory_.GetWeakPtr()));
261 } 289 }
262 290
263 void AudioRendererImpl::OnAudioBufferStreamInitialized(bool success) { 291 void AudioRendererImpl::OnAudioBufferStreamInitialized(bool success) {
264 DCHECK(task_runner_->BelongsToCurrentThread()); 292 DCHECK(task_runner_->BelongsToCurrentThread());
265 293
266 base::AutoLock auto_lock(lock_); 294 base::AutoLock auto_lock(lock_);
267 295
268 if (state_ == kStopped) { 296 if (state_ == kStopped) {
269 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_ABORT); 297 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_ABORT);
270 return; 298 return;
271 } 299 }
272 300
273 if (!success) { 301 if (!success) {
274 state_ = kUninitialized; 302 state_ = kUninitialized;
275 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED); 303 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED);
276 return; 304 return;
277 } 305 }
278 306
279 int sample_rate = audio_buffer_stream_.decoder()->samples_per_second();
280
281 // The actual buffer size is controlled via the size of the AudioBus
282 // provided to Render(), so just choose something reasonable here for looks.
283 int buffer_size = audio_buffer_stream_.decoder()->samples_per_second() / 100;
284
285 // TODO(rileya): Remove the channel_layout/bits_per_channel/samples_per_second
286 // getters from AudioDecoder, and adjust this accordingly.
287 audio_parameters_ =
288 AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY,
289 audio_buffer_stream_.decoder()->channel_layout(),
290 sample_rate,
291 audio_buffer_stream_.decoder()->bits_per_channel(),
292 buffer_size);
293 if (!audio_parameters_.IsValid()) { 307 if (!audio_parameters_.IsValid()) {
294 ChangeState_Locked(kUninitialized); 308 ChangeState_Locked(kUninitialized);
295 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_INITIALIZATION_FAILED); 309 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_INITIALIZATION_FAILED);
296 return; 310 return;
297 } 311 }
298 312
299 splicer_.reset(new AudioSplicer(sample_rate)); 313 if (expecting_config_changes_)
314 buffer_converter_.reset(new AudioBufferConverter(audio_parameters_));
315 splicer_.reset(new AudioSplicer(audio_parameters_.sample_rate()));
300 316
301 // We're all good! Continue initializing the rest of the audio renderer 317 // We're all good! Continue initializing the rest of the audio renderer
302 // based on the decoder format. 318 // based on the decoder format.
303 algorithm_.reset(new AudioRendererAlgorithm()); 319 algorithm_.reset(new AudioRendererAlgorithm());
304 algorithm_->Initialize(0, audio_parameters_); 320 algorithm_->Initialize(0, audio_parameters_);
305 321
306 ChangeState_Locked(kPaused); 322 ChangeState_Locked(kPaused);
307 323
308 HistogramRendererEvent(INITIALIZED); 324 HistogramRendererEvent(INITIALIZED);
309 325
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
369 385
370 DCHECK_EQ(status, AudioBufferStream::OK); 386 DCHECK_EQ(status, AudioBufferStream::OK);
371 DCHECK(buffer.get()); 387 DCHECK(buffer.get());
372 388
373 if (state_ == kFlushing) { 389 if (state_ == kFlushing) {
374 ChangeState_Locked(kPaused); 390 ChangeState_Locked(kPaused);
375 DoFlush_Locked(); 391 DoFlush_Locked();
376 return; 392 return;
377 } 393 }
378 394
379 if (!splicer_->AddInput(buffer)) { 395 if (expecting_config_changes_) {
380 HandleAbortedReadOrDecodeError(true); 396 DCHECK(buffer_converter_);
381 return; 397 buffer_converter_->AddInput(buffer);
398 while (buffer_converter_->HasNextBuffer()) {
399 if (!splicer_->AddInput(buffer_converter_->GetNextBuffer())) {
400 HandleAbortedReadOrDecodeError(true);
401 return;
402 }
403 }
404 } else {
405 if (!splicer_->AddInput(buffer)) {
406 HandleAbortedReadOrDecodeError(true);
407 return;
408 }
382 } 409 }
383 410
384 if (!splicer_->HasNextBuffer()) { 411 if (!splicer_->HasNextBuffer()) {
385 AttemptRead_Locked(); 412 AttemptRead_Locked();
386 return; 413 return;
387 } 414 }
388 415
389 bool need_another_buffer = false; 416 bool need_another_buffer = false;
390 while (splicer_->HasNextBuffer()) 417 while (splicer_->HasNextBuffer())
391 need_another_buffer = HandleSplicerBuffer(splicer_->GetNextBuffer()); 418 need_another_buffer = HandleSplicerBuffer(splicer_->GetNextBuffer());
(...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after
712 DVLOG(1) << __FUNCTION__ << " : " << state_ << " -> " << new_state; 739 DVLOG(1) << __FUNCTION__ << " : " << state_ << " -> " << new_state;
713 lock_.AssertAcquired(); 740 lock_.AssertAcquired();
714 state_ = new_state; 741 state_ = new_state;
715 } 742 }
716 743
717 void AudioRendererImpl::OnNewSpliceBuffer(base::TimeDelta splice_timestamp) { 744 void AudioRendererImpl::OnNewSpliceBuffer(base::TimeDelta splice_timestamp) {
718 DCHECK(task_runner_->BelongsToCurrentThread()); 745 DCHECK(task_runner_->BelongsToCurrentThread());
719 splicer_->SetSpliceTimestamp(splice_timestamp); 746 splicer_->SetSpliceTimestamp(splice_timestamp);
720 } 747 }
721 748
749 void AudioRendererImpl::OnConfigChange() {
750 DCHECK(task_runner_->BelongsToCurrentThread());
751 buffer_converter_->ResetTimestampState();
DaleCurtis 2014/03/27 20:59:55 Need to check expecting_config_changes here.
752 }
753
722 } // namespace media 754 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698