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

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: Created 6 years, 9 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 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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698