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 3// found in the LICENSE file. 4 5#include "media/filters/audio_renderer_impl.h" 6 7#include <math.h> 8 9#include <algorithm> 10 11#include "base/bind.h" 12#include "base/callback.h" 13#include "base/callback_helpers.h" 14#include "base/logging.h" 15#include "base/metrics/histogram.h" 16#include "base/single_thread_task_runner.h" 17#include "media/base/audio_buffer.h" 18#include "media/base/audio_buffer_converter.h" 19#include "media/base/audio_hardware_config.h" 20#include "media/base/audio_splicer.h" 21#include "media/base/bind_to_current_loop.h" 22#include "media/base/demuxer_stream.h" 23#include "media/filters/audio_clock.h" 24#include "media/filters/decrypting_demuxer_stream.h" 25 26namespace media { 27 28namespace { 29 30enum AudioRendererEvent { 31 INITIALIZED, 32 RENDER_ERROR, 33 RENDER_EVENT_MAX = RENDER_ERROR, 34}; 35 36void HistogramRendererEvent(AudioRendererEvent event) { 37 UMA_HISTOGRAM_ENUMERATION( 38 "Media.AudioRendererEvents", event, RENDER_EVENT_MAX + 1); 39} 40 41} // namespace 42 43AudioRendererImpl::AudioRendererImpl( 44 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, 45 media::AudioRendererSink* sink, 46 ScopedVector<AudioDecoder> decoders, 47 const SetDecryptorReadyCB& set_decryptor_ready_cb, 48 const AudioHardwareConfig& hardware_config, 49 const scoped_refptr<MediaLog>& media_log) 50 : task_runner_(task_runner), 51 expecting_config_changes_(false), 52 sink_(sink), 53 audio_buffer_stream_(new AudioBufferStream(task_runner, 54 decoders.Pass(), 55 set_decryptor_ready_cb, 56 media_log)), 57 hardware_config_(hardware_config), 58 playback_rate_(0), 59 state_(kUninitialized), 60 buffering_state_(BUFFERING_HAVE_NOTHING), 61 rendering_(false), 62 sink_playing_(false), 63 pending_read_(false), 64 received_end_of_stream_(false), 65 rendered_end_of_stream_(false), 66 weak_factory_(this) { 67 audio_buffer_stream_->set_splice_observer(base::Bind( 68 &AudioRendererImpl::OnNewSpliceBuffer, weak_factory_.GetWeakPtr())); 69 audio_buffer_stream_->set_config_change_observer(base::Bind( 70 &AudioRendererImpl::OnConfigChange, weak_factory_.GetWeakPtr())); 71} 72 73AudioRendererImpl::~AudioRendererImpl() { 74 DVLOG(1) << __FUNCTION__; 75 DCHECK(task_runner_->BelongsToCurrentThread()); 76 77 // If Render() is in progress, this call will wait for Render() to finish. 78 // After this call, the |sink_| will not call back into |this| anymore. 79 sink_->Stop(); 80 81 if (!init_cb_.is_null()) 82 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_ABORT); 83} 84 85void AudioRendererImpl::StartTicking() { 86 DVLOG(1) << __FUNCTION__; 87 DCHECK(task_runner_->BelongsToCurrentThread()); 88 DCHECK(!rendering_); 89 rendering_ = true; 90 91 base::AutoLock auto_lock(lock_); 92 // Wait for an eventual call to SetPlaybackRate() to start rendering. 93 if (playback_rate_ == 0) { 94 DCHECK(!sink_playing_); 95 return; 96 } 97 98 StartRendering_Locked(); 99} 100 101void AudioRendererImpl::StartRendering_Locked() { 102 DVLOG(1) << __FUNCTION__; 103 DCHECK(task_runner_->BelongsToCurrentThread()); 104 DCHECK_EQ(state_, kPlaying); 105 DCHECK(!sink_playing_); 106 DCHECK_NE(playback_rate_, 0); 107 lock_.AssertAcquired(); 108 109 sink_playing_ = true; 110 111 base::AutoUnlock auto_unlock(lock_); 112 sink_->Play(); 113} 114 115void AudioRendererImpl::StopTicking() { 116 DVLOG(1) << __FUNCTION__; 117 DCHECK(task_runner_->BelongsToCurrentThread()); 118 DCHECK(rendering_); 119 rendering_ = false; 120 121 base::AutoLock auto_lock(lock_); 122 // Rendering should have already been stopped with a zero playback rate. 123 if (playback_rate_ == 0) { 124 DCHECK(!sink_playing_); 125 return; 126 } 127 128 StopRendering_Locked(); 129} 130 131void AudioRendererImpl::StopRendering_Locked() { 132 DCHECK(task_runner_->BelongsToCurrentThread()); 133 DCHECK_EQ(state_, kPlaying); 134 DCHECK(sink_playing_); 135 lock_.AssertAcquired(); 136 137 sink_playing_ = false; 138 139 base::AutoUnlock auto_unlock(lock_); 140 sink_->Pause(); 141} 142 143void AudioRendererImpl::SetMediaTime(base::TimeDelta time) { 144 DVLOG(1) << __FUNCTION__ << "(" << time.InMicroseconds() << ")"; 145 DCHECK(task_runner_->BelongsToCurrentThread()); 146 147 base::AutoLock auto_lock(lock_); 148 DCHECK(!rendering_); 149 DCHECK_EQ(state_, kFlushed); 150 151 start_timestamp_ = time; 152 ended_timestamp_ = kInfiniteDuration(); 153 last_render_ticks_ = base::TimeTicks(); 154 audio_clock_.reset(new AudioClock(time, audio_parameters_.sample_rate())); 155} 156 157base::TimeDelta AudioRendererImpl::CurrentMediaTime() { 158 DVLOG(2) << __FUNCTION__; 159 160 // In practice the Render() method is called with a high enough frequency 161 // that returning only the front timestamp is good enough and also prevents 162 // returning values that go backwards in time. 163 base::AutoLock auto_lock(lock_); 164 return audio_clock_->front_timestamp(); 165} 166 167base::TimeDelta AudioRendererImpl::CurrentMediaTimeForSyncingVideo() { 168 DVLOG(2) << __FUNCTION__; 169 170 base::AutoLock auto_lock(lock_); 171 if (last_render_ticks_.is_null()) 172 return audio_clock_->front_timestamp(); 173 174 return audio_clock_->TimestampSinceWriting(base::TimeTicks::Now() - 175 last_render_ticks_); 176} 177 178TimeSource* AudioRendererImpl::GetTimeSource() { 179 return this; 180} 181 182void AudioRendererImpl::Flush(const base::Closure& callback) { 183 DVLOG(1) << __FUNCTION__; 184 DCHECK(task_runner_->BelongsToCurrentThread()); 185 186 base::AutoLock auto_lock(lock_); 187 DCHECK_EQ(state_, kPlaying); 188 DCHECK(flush_cb_.is_null()); 189 190 flush_cb_ = callback; 191 ChangeState_Locked(kFlushing); 192 193 if (pending_read_) 194 return; 195 196 ChangeState_Locked(kFlushed); 197 DoFlush_Locked(); 198} 199 200void AudioRendererImpl::DoFlush_Locked() { 201 DCHECK(task_runner_->BelongsToCurrentThread()); 202 lock_.AssertAcquired(); 203 204 DCHECK(!pending_read_); 205 DCHECK_EQ(state_, kFlushed); 206 207 audio_buffer_stream_->Reset(base::Bind(&AudioRendererImpl::ResetDecoderDone, 208 weak_factory_.GetWeakPtr())); 209} 210 211void AudioRendererImpl::ResetDecoderDone() { 212 DCHECK(task_runner_->BelongsToCurrentThread()); 213 { 214 base::AutoLock auto_lock(lock_); 215 216 DCHECK_EQ(state_, kFlushed); 217 DCHECK(!flush_cb_.is_null()); 218 219 received_end_of_stream_ = false; 220 rendered_end_of_stream_ = false; 221 222 // Flush() may have been called while underflowed/not fully buffered. 223 if (buffering_state_ != BUFFERING_HAVE_NOTHING) 224 SetBufferingState_Locked(BUFFERING_HAVE_NOTHING); 225 226 splicer_->Reset(); 227 if (buffer_converter_) 228 buffer_converter_->Reset(); 229 algorithm_->FlushBuffers(); 230 } 231 232 // Changes in buffering state are always posted. Flush callback must only be 233 // run after buffering state has been set back to nothing. 234 task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&flush_cb_)); 235} 236 237void AudioRendererImpl::StartPlaying() { 238 DVLOG(1) << __FUNCTION__; 239 DCHECK(task_runner_->BelongsToCurrentThread()); 240 241 base::AutoLock auto_lock(lock_); 242 DCHECK(!sink_playing_); 243 DCHECK_EQ(state_, kFlushed); 244 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING); 245 DCHECK(!pending_read_) << "Pending read must complete before seeking"; 246 247 ChangeState_Locked(kPlaying); 248 AttemptRead_Locked(); 249} 250 251void AudioRendererImpl::Initialize(DemuxerStream* stream, 252 const PipelineStatusCB& init_cb, 253 const StatisticsCB& statistics_cb, 254 const BufferingStateCB& buffering_state_cb, 255 const base::Closure& ended_cb, 256 const PipelineStatusCB& error_cb) { 257 DCHECK(task_runner_->BelongsToCurrentThread()); 258 DCHECK(stream); 259 DCHECK_EQ(stream->type(), DemuxerStream::AUDIO); 260 DCHECK(!init_cb.is_null()); 261 DCHECK(!statistics_cb.is_null()); 262 DCHECK(!buffering_state_cb.is_null()); 263 DCHECK(!ended_cb.is_null()); 264 DCHECK(!error_cb.is_null()); 265 DCHECK_EQ(kUninitialized, state_); 266 DCHECK(sink_.get()); 267 268 state_ = kInitializing; 269 270 // Always post |init_cb_| because |this| could be destroyed if initialization 271 // failed. 272 init_cb_ = BindToCurrentLoop(init_cb); 273 274 buffering_state_cb_ = buffering_state_cb; 275 ended_cb_ = ended_cb; 276 error_cb_ = error_cb; 277 278 expecting_config_changes_ = stream->SupportsConfigChanges(); 279 if (!expecting_config_changes_) { 280 // The actual buffer size is controlled via the size of the AudioBus 281 // provided to Render(), so just choose something reasonable here for looks. 282 int buffer_size = stream->audio_decoder_config().samples_per_second() / 100; 283 audio_parameters_.Reset( 284 AudioParameters::AUDIO_PCM_LOW_LATENCY, 285 stream->audio_decoder_config().channel_layout(), 286 ChannelLayoutToChannelCount( 287 stream->audio_decoder_config().channel_layout()), 288 stream->audio_decoder_config().samples_per_second(), 289 stream->audio_decoder_config().bits_per_channel(), 290 buffer_size); 291 buffer_converter_.reset(); 292 } else { 293 // TODO(rileya): Support hardware config changes 294 const AudioParameters& hw_params = hardware_config_.GetOutputConfig(); 295 audio_parameters_.Reset( 296 hw_params.format(), 297 // Always use the source's channel layout and channel count to avoid 298 // premature downmixing (http://crbug.com/379288), platform specific 299 // issues around channel layouts (http://crbug.com/266674), and 300 // unnecessary upmixing overhead. 301 stream->audio_decoder_config().channel_layout(), 302 ChannelLayoutToChannelCount( 303 stream->audio_decoder_config().channel_layout()), 304 hw_params.sample_rate(), 305 hw_params.bits_per_sample(), 306 hardware_config_.GetHighLatencyBufferSize()); 307 } 308 309 audio_clock_.reset( 310 new AudioClock(base::TimeDelta(), audio_parameters_.sample_rate())); 311 312 audio_buffer_stream_->Initialize( 313 stream, 314 false, 315 statistics_cb, 316 base::Bind(&AudioRendererImpl::OnAudioBufferStreamInitialized, 317 weak_factory_.GetWeakPtr())); 318} 319 320void AudioRendererImpl::OnAudioBufferStreamInitialized(bool success) { 321 DCHECK(task_runner_->BelongsToCurrentThread()); 322 323 base::AutoLock auto_lock(lock_); 324 325 if (!success) { 326 state_ = kUninitialized; 327 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED); 328 return; 329 } 330 331 if (!audio_parameters_.IsValid()) { 332 ChangeState_Locked(kUninitialized); 333 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_INITIALIZATION_FAILED); 334 return; 335 } 336 337 if (expecting_config_changes_) 338 buffer_converter_.reset(new AudioBufferConverter(audio_parameters_)); 339 splicer_.reset(new AudioSplicer(audio_parameters_.sample_rate())); 340 341 // We're all good! Continue initializing the rest of the audio renderer 342 // based on the decoder format. 343 algorithm_.reset(new AudioRendererAlgorithm()); 344 algorithm_->Initialize(audio_parameters_); 345 346 ChangeState_Locked(kFlushed); 347 348 HistogramRendererEvent(INITIALIZED); 349 350 { 351 base::AutoUnlock auto_unlock(lock_); 352 sink_->Initialize(audio_parameters_, this); 353 sink_->Start(); 354 355 // Some sinks play on start... 356 sink_->Pause(); 357 } 358 359 DCHECK(!sink_playing_); 360 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); 361} 362 363void AudioRendererImpl::SetVolume(float volume) { 364 DCHECK(task_runner_->BelongsToCurrentThread()); 365 DCHECK(sink_.get()); 366 sink_->SetVolume(volume); 367} 368 369void AudioRendererImpl::DecodedAudioReady( 370 AudioBufferStream::Status status, 371 const scoped_refptr<AudioBuffer>& buffer) { 372 DVLOG(2) << __FUNCTION__ << "(" << status << ")"; 373 DCHECK(task_runner_->BelongsToCurrentThread()); 374 375 base::AutoLock auto_lock(lock_); 376 DCHECK(state_ != kUninitialized); 377 378 CHECK(pending_read_); 379 pending_read_ = false; 380 381 if (status == AudioBufferStream::ABORTED || 382 status == AudioBufferStream::DEMUXER_READ_ABORTED) { 383 HandleAbortedReadOrDecodeError(false); 384 return; 385 } 386 387 if (status == AudioBufferStream::DECODE_ERROR) { 388 HandleAbortedReadOrDecodeError(true); 389 return; 390 } 391 392 DCHECK_EQ(status, AudioBufferStream::OK); 393 DCHECK(buffer.get()); 394 395 if (state_ == kFlushing) { 396 ChangeState_Locked(kFlushed); 397 DoFlush_Locked(); 398 return; 399 } 400 401 if (expecting_config_changes_) { 402 DCHECK(buffer_converter_); 403 buffer_converter_->AddInput(buffer); 404 while (buffer_converter_->HasNextBuffer()) { 405 if (!splicer_->AddInput(buffer_converter_->GetNextBuffer())) { 406 HandleAbortedReadOrDecodeError(true); 407 return; 408 } 409 } 410 } else { 411 if (!splicer_->AddInput(buffer)) { 412 HandleAbortedReadOrDecodeError(true); 413 return; 414 } 415 } 416 417 if (!splicer_->HasNextBuffer()) { 418 AttemptRead_Locked(); 419 return; 420 } 421 422 bool need_another_buffer = false; 423 while (splicer_->HasNextBuffer()) 424 need_another_buffer = HandleSplicerBuffer_Locked(splicer_->GetNextBuffer()); 425 426 if (!need_another_buffer && !CanRead_Locked()) 427 return; 428 429 AttemptRead_Locked(); 430} 431 432bool AudioRendererImpl::HandleSplicerBuffer_Locked( 433 const scoped_refptr<AudioBuffer>& buffer) { 434 lock_.AssertAcquired(); 435 if (buffer->end_of_stream()) { 436 received_end_of_stream_ = true; 437 } else { 438 if (state_ == kPlaying) { 439 if (IsBeforeStartTime(buffer)) 440 return true; 441 442 // Trim off any additional time before the start timestamp. 443 const base::TimeDelta trim_time = start_timestamp_ - buffer->timestamp(); 444 if (trim_time > base::TimeDelta()) { 445 buffer->TrimStart(buffer->frame_count() * 446 (static_cast<double>(trim_time.InMicroseconds()) / 447 buffer->duration().InMicroseconds())); 448 } 449 // If the entire buffer was trimmed, request a new one. 450 if (!buffer->frame_count()) 451 return true; 452 } 453 454 if (state_ != kUninitialized) 455 algorithm_->EnqueueBuffer(buffer); 456 } 457 458 switch (state_) { 459 case kUninitialized: 460 case kInitializing: 461 case kFlushing: 462 NOTREACHED(); 463 return false; 464 465 case kFlushed: 466 DCHECK(!pending_read_); 467 return false; 468 469 case kPlaying: 470 if (buffer->end_of_stream() || algorithm_->IsQueueFull()) { 471 if (buffering_state_ == BUFFERING_HAVE_NOTHING) 472 SetBufferingState_Locked(BUFFERING_HAVE_ENOUGH); 473 return false; 474 } 475 return true; 476 } 477 return false; 478} 479 480void AudioRendererImpl::AttemptRead() { 481 base::AutoLock auto_lock(lock_); 482 AttemptRead_Locked(); 483} 484 485void AudioRendererImpl::AttemptRead_Locked() { 486 DCHECK(task_runner_->BelongsToCurrentThread()); 487 lock_.AssertAcquired(); 488 489 if (!CanRead_Locked()) 490 return; 491 492 pending_read_ = true; 493 audio_buffer_stream_->Read(base::Bind(&AudioRendererImpl::DecodedAudioReady, 494 weak_factory_.GetWeakPtr())); 495} 496 497bool AudioRendererImpl::CanRead_Locked() { 498 lock_.AssertAcquired(); 499 500 switch (state_) { 501 case kUninitialized: 502 case kInitializing: 503 case kFlushing: 504 case kFlushed: 505 return false; 506 507 case kPlaying: 508 break; 509 } 510 511 return !pending_read_ && !received_end_of_stream_ && 512 !algorithm_->IsQueueFull(); 513} 514 515void AudioRendererImpl::SetPlaybackRate(float playback_rate) { 516 DVLOG(1) << __FUNCTION__ << "(" << playback_rate << ")"; 517 DCHECK(task_runner_->BelongsToCurrentThread()); 518 DCHECK_GE(playback_rate, 0); 519 DCHECK(sink_.get()); 520 521 base::AutoLock auto_lock(lock_); 522 523 // We have two cases here: 524 // Play: current_playback_rate == 0 && playback_rate != 0 525 // Pause: current_playback_rate != 0 && playback_rate == 0 526 float current_playback_rate = playback_rate_; 527 playback_rate_ = playback_rate; 528 529 if (!rendering_) 530 return; 531 532 if (current_playback_rate == 0 && playback_rate != 0) { 533 StartRendering_Locked(); 534 return; 535 } 536 537 if (current_playback_rate != 0 && playback_rate == 0) { 538 StopRendering_Locked(); 539 return; 540 } 541} 542 543bool AudioRendererImpl::IsBeforeStartTime( 544 const scoped_refptr<AudioBuffer>& buffer) { 545 DCHECK_EQ(state_, kPlaying); 546 return buffer.get() && !buffer->end_of_stream() && 547 (buffer->timestamp() + buffer->duration()) < start_timestamp_; 548} 549 550int AudioRendererImpl::Render(AudioBus* audio_bus, 551 int audio_delay_milliseconds) { 552 const int requested_frames = audio_bus->frames(); 553 base::TimeDelta playback_delay = base::TimeDelta::FromMilliseconds( 554 audio_delay_milliseconds); 555 const int delay_frames = static_cast<int>(playback_delay.InSecondsF() * 556 audio_parameters_.sample_rate()); 557 int frames_written = 0; 558 { 559 base::AutoLock auto_lock(lock_); 560 last_render_ticks_ = base::TimeTicks::Now(); 561 562 // Ensure Stop() hasn't destroyed our |algorithm_| on the pipeline thread. 563 if (!algorithm_) { 564 audio_clock_->WroteAudio( 565 0, requested_frames, delay_frames, playback_rate_); 566 return 0; 567 } 568 569 if (playback_rate_ == 0) { 570 audio_clock_->WroteAudio( 571 0, requested_frames, delay_frames, playback_rate_); 572 return 0; 573 } 574 575 // Mute audio by returning 0 when not playing. 576 if (state_ != kPlaying) { 577 audio_clock_->WroteAudio( 578 0, requested_frames, delay_frames, playback_rate_); 579 return 0; 580 } 581 582 // We use the following conditions to determine end of playback: 583 // 1) Algorithm can not fill the audio callback buffer 584 // 2) We received an end of stream buffer 585 // 3) We haven't already signalled that we've ended 586 // 4) We've played all known audio data sent to hardware 587 // 588 // We use the following conditions to determine underflow: 589 // 1) Algorithm can not fill the audio callback buffer 590 // 2) We have NOT received an end of stream buffer 591 // 3) We are in the kPlaying state 592 // 593 // Otherwise the buffer has data we can send to the device. 594 if (algorithm_->frames_buffered() > 0) { 595 frames_written = 596 algorithm_->FillBuffer(audio_bus, requested_frames, playback_rate_); 597 } 598 599 // Per the TimeSource API the media time should always increase even after 600 // we've rendered all known audio data. Doing so simplifies scenarios where 601 // we have other sources of media data that need to be scheduled after audio 602 // data has ended. 603 // 604 // That being said, we don't want to advance time when underflowed as we 605 // know more decoded frames will eventually arrive. If we did, we would 606 // throw things out of sync when said decoded frames arrive. 607 int frames_after_end_of_stream = 0; 608 if (frames_written == 0) { 609 if (received_end_of_stream_) { 610 if (ended_timestamp_ == kInfiniteDuration()) 611 ended_timestamp_ = audio_clock_->back_timestamp(); 612 frames_after_end_of_stream = requested_frames; 613 } else if (state_ == kPlaying && 614 buffering_state_ != BUFFERING_HAVE_NOTHING) { 615 algorithm_->IncreaseQueueCapacity(); 616 SetBufferingState_Locked(BUFFERING_HAVE_NOTHING); 617 } 618 } 619 620 audio_clock_->WroteAudio(frames_written + frames_after_end_of_stream, 621 requested_frames, 622 delay_frames, 623 playback_rate_); 624 625 if (CanRead_Locked()) { 626 task_runner_->PostTask(FROM_HERE, 627 base::Bind(&AudioRendererImpl::AttemptRead, 628 weak_factory_.GetWeakPtr())); 629 } 630 631 if (audio_clock_->front_timestamp() >= ended_timestamp_ && 632 !rendered_end_of_stream_) { 633 rendered_end_of_stream_ = true; 634 task_runner_->PostTask(FROM_HERE, ended_cb_); 635 } 636 } 637 638 DCHECK_LE(frames_written, requested_frames); 639 return frames_written; 640} 641 642void AudioRendererImpl::OnRenderError() { 643 // UMA data tells us this happens ~0.01% of the time. Trigger an error instead 644 // of trying to gracefully fall back to a fake sink. It's very likely 645 // OnRenderError() should be removed and the audio stack handle errors without 646 // notifying clients. See http://crbug.com/234708 for details. 647 HistogramRendererEvent(RENDER_ERROR); 648 // Post to |task_runner_| as this is called on the audio callback thread. 649 task_runner_->PostTask(FROM_HERE, 650 base::Bind(error_cb_, PIPELINE_ERROR_DECODE)); 651} 652 653void AudioRendererImpl::HandleAbortedReadOrDecodeError(bool is_decode_error) { 654 DCHECK(task_runner_->BelongsToCurrentThread()); 655 lock_.AssertAcquired(); 656 657 PipelineStatus status = is_decode_error ? PIPELINE_ERROR_DECODE : PIPELINE_OK; 658 switch (state_) { 659 case kUninitialized: 660 case kInitializing: 661 NOTREACHED(); 662 return; 663 case kFlushing: 664 ChangeState_Locked(kFlushed); 665 if (status == PIPELINE_OK) { 666 DoFlush_Locked(); 667 return; 668 } 669 670 error_cb_.Run(status); 671 base::ResetAndReturn(&flush_cb_).Run(); 672 return; 673 674 case kFlushed: 675 case kPlaying: 676 if (status != PIPELINE_OK) 677 error_cb_.Run(status); 678 return; 679 } 680} 681 682void AudioRendererImpl::ChangeState_Locked(State new_state) { 683 DVLOG(1) << __FUNCTION__ << " : " << state_ << " -> " << new_state; 684 lock_.AssertAcquired(); 685 state_ = new_state; 686} 687 688void AudioRendererImpl::OnNewSpliceBuffer(base::TimeDelta splice_timestamp) { 689 DCHECK(task_runner_->BelongsToCurrentThread()); 690 splicer_->SetSpliceTimestamp(splice_timestamp); 691} 692 693void AudioRendererImpl::OnConfigChange() { 694 DCHECK(task_runner_->BelongsToCurrentThread()); 695 DCHECK(expecting_config_changes_); 696 buffer_converter_->ResetTimestampState(); 697 // Drain flushed buffers from the converter so the AudioSplicer receives all 698 // data ahead of any OnNewSpliceBuffer() calls. Since discontinuities should 699 // only appear after config changes, AddInput() should never fail here. 700 while (buffer_converter_->HasNextBuffer()) 701 CHECK(splicer_->AddInput(buffer_converter_->GetNextBuffer())); 702} 703 704void AudioRendererImpl::SetBufferingState_Locked( 705 BufferingState buffering_state) { 706 DVLOG(1) << __FUNCTION__ << " : " << buffering_state_ << " -> " 707 << buffering_state; 708 DCHECK_NE(buffering_state_, buffering_state); 709 lock_.AssertAcquired(); 710 buffering_state_ = buffering_state; 711 712 task_runner_->PostTask(FROM_HERE, 713 base::Bind(buffering_state_cb_, buffering_state_)); 714} 715 716} // namespace media 717