Chromium Code Reviews| 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 "base/time/default_tick_clock.h" | |
| 17 #include "media/base/audio_buffer.h" | 18 #include "media/base/audio_buffer.h" |
| 18 #include "media/base/audio_buffer_converter.h" | 19 #include "media/base/audio_buffer_converter.h" |
| 19 #include "media/base/audio_hardware_config.h" | 20 #include "media/base/audio_hardware_config.h" |
| 20 #include "media/base/audio_splicer.h" | 21 #include "media/base/audio_splicer.h" |
| 21 #include "media/base/bind_to_current_loop.h" | 22 #include "media/base/bind_to_current_loop.h" |
| 22 #include "media/base/demuxer_stream.h" | 23 #include "media/base/demuxer_stream.h" |
| 23 #include "media/filters/audio_clock.h" | 24 #include "media/filters/audio_clock.h" |
| 24 #include "media/filters/decrypting_demuxer_stream.h" | 25 #include "media/filters/decrypting_demuxer_stream.h" |
| 25 | 26 |
| 26 namespace media { | 27 namespace media { |
| 27 | 28 |
| 28 namespace { | 29 namespace { |
| 29 | 30 |
| 30 enum AudioRendererEvent { | 31 enum AudioRendererEvent { |
| 31 INITIALIZED, | 32 INITIALIZED, |
| 32 RENDER_ERROR, | 33 RENDER_ERROR, |
| 33 RENDER_EVENT_MAX = RENDER_ERROR, | 34 RENDER_EVENT_MAX = RENDER_ERROR, |
| 34 }; | 35 }; |
| 35 | 36 |
| 36 void HistogramRendererEvent(AudioRendererEvent event) { | 37 void HistogramRendererEvent(AudioRendererEvent event) { |
| 37 UMA_HISTOGRAM_ENUMERATION( | 38 UMA_HISTOGRAM_ENUMERATION( |
| 38 "Media.AudioRendererEvents", event, RENDER_EVENT_MAX + 1); | 39 "Media.AudioRendererEvents", event, RENDER_EVENT_MAX + 1); |
| 39 } | 40 } |
| 40 | 41 |
| 41 } // namespace | 42 } // namespace |
| 42 | 43 |
| 44 AudioRendererImpl::RenderResult::RenderResult() | |
| 45 : requested_frames(0), | |
| 46 delay_frames(0), | |
| 47 frames_written(0), | |
| 48 playback_rate(0), | |
| 49 endpoint_timestamp(kNoTimestamp()) { | |
| 50 } | |
| 51 | |
| 43 AudioRendererImpl::AudioRendererImpl( | 52 AudioRendererImpl::AudioRendererImpl( |
| 44 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, | 53 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, |
| 45 media::AudioRendererSink* sink, | 54 media::AudioRendererSink* sink, |
| 46 ScopedVector<AudioDecoder> decoders, | 55 ScopedVector<AudioDecoder> decoders, |
| 47 const SetDecryptorReadyCB& set_decryptor_ready_cb, | 56 const SetDecryptorReadyCB& set_decryptor_ready_cb, |
| 48 AudioHardwareConfig* hardware_config) | 57 AudioHardwareConfig* hardware_config) |
| 49 : task_runner_(task_runner), | 58 : task_runner_(task_runner), |
| 50 sink_(sink), | 59 sink_(sink), |
| 51 audio_buffer_stream_(task_runner, | 60 audio_buffer_stream_(task_runner, |
| 52 decoders.Pass(), | 61 decoders.Pass(), |
| 53 set_decryptor_ready_cb), | 62 set_decryptor_ready_cb), |
| 54 hardware_config_(hardware_config), | 63 hardware_config_(hardware_config), |
| 55 now_cb_(base::Bind(&base::TimeTicks::Now)), | 64 tick_clock_(new base::DefaultTickClock()), |
| 56 state_(kUninitialized), | 65 state_(kUninitialized), |
| 57 buffering_state_(BUFFERING_HAVE_NOTHING), | 66 buffering_state_(BUFFERING_HAVE_NOTHING), |
| 58 rendering_(false), | 67 rendering_(false), |
| 59 sink_playing_(false), | 68 sink_playing_(false), |
| 60 pending_read_(false), | 69 pending_read_(false), |
| 61 received_end_of_stream_(false), | 70 received_end_of_stream_(false), |
| 62 rendered_end_of_stream_(false), | 71 rendered_end_of_stream_(false), |
| 63 weak_factory_(this) { | 72 weak_factory_(this) { |
| 64 audio_buffer_stream_.set_splice_observer(base::Bind( | 73 audio_buffer_stream_.set_splice_observer(base::Bind( |
| 65 &AudioRendererImpl::OnNewSpliceBuffer, weak_factory_.GetWeakPtr())); | 74 &AudioRendererImpl::OnNewSpliceBuffer, weak_factory_.GetWeakPtr())); |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 169 | 178 |
| 170 DCHECK_EQ(state_, kFlushed); | 179 DCHECK_EQ(state_, kFlushed); |
| 171 DCHECK(!flush_cb_.is_null()); | 180 DCHECK(!flush_cb_.is_null()); |
| 172 | 181 |
| 173 audio_clock_.reset(new AudioClock(audio_parameters_.sample_rate())); | 182 audio_clock_.reset(new AudioClock(audio_parameters_.sample_rate())); |
| 174 received_end_of_stream_ = false; | 183 received_end_of_stream_ = false; |
| 175 rendered_end_of_stream_ = false; | 184 rendered_end_of_stream_ = false; |
| 176 | 185 |
| 177 // Flush() may have been called while underflowed/not fully buffered. | 186 // Flush() may have been called while underflowed/not fully buffered. |
| 178 if (buffering_state_ != BUFFERING_HAVE_NOTHING) | 187 if (buffering_state_ != BUFFERING_HAVE_NOTHING) |
| 179 SetBufferingState_Locked(BUFFERING_HAVE_NOTHING); | 188 SetBufferingState(BUFFERING_HAVE_NOTHING); |
| 180 | 189 |
| 181 splicer_->Reset(); | 190 splicer_->Reset(); |
| 182 if (buffer_converter_) | 191 if (buffer_converter_) |
| 183 buffer_converter_->Reset(); | 192 buffer_converter_->Reset(); |
| 184 algorithm_->FlushBuffers(); | 193 algorithm_->FlushBuffers(); |
| 185 } | 194 } |
| 186 | 195 |
| 187 // Changes in buffering state are always posted. Flush callback must only be | 196 // Changes in buffering state are always posted. Flush callback must only be |
| 188 // run after buffering state has been set back to nothing. | 197 // run after buffering state has been set back to nothing. |
| 189 task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&flush_cb_)); | 198 task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&flush_cb_)); |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 353 | 362 |
| 354 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); | 363 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); |
| 355 } | 364 } |
| 356 | 365 |
| 357 void AudioRendererImpl::SetVolume(float volume) { | 366 void AudioRendererImpl::SetVolume(float volume) { |
| 358 DCHECK(task_runner_->BelongsToCurrentThread()); | 367 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 359 DCHECK(sink_); | 368 DCHECK(sink_); |
| 360 sink_->SetVolume(volume); | 369 sink_->SetVolume(volume); |
| 361 } | 370 } |
| 362 | 371 |
| 372 void AudioRendererImpl::SetTickClockForTesting( | |
| 373 scoped_ptr<base::TickClock> tick_clock) { | |
| 374 tick_clock_.swap(tick_clock); | |
| 375 } | |
| 376 | |
| 363 void AudioRendererImpl::DecodedAudioReady( | 377 void AudioRendererImpl::DecodedAudioReady( |
| 364 AudioBufferStream::Status status, | 378 AudioBufferStream::Status status, |
| 365 const scoped_refptr<AudioBuffer>& buffer) { | 379 const scoped_refptr<AudioBuffer>& buffer) { |
| 366 DVLOG(2) << __FUNCTION__ << "(" << status << ")"; | 380 DVLOG(2) << __FUNCTION__ << "(" << status << ")"; |
| 367 DCHECK(task_runner_->BelongsToCurrentThread()); | 381 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 368 | 382 |
| 369 base::AutoLock auto_lock(lock_); | 383 base::AutoLock auto_lock(lock_); |
| 370 DCHECK(state_ != kUninitialized); | 384 DCHECK(state_ != kUninitialized); |
| 371 | 385 |
| 372 CHECK(pending_read_); | 386 CHECK(pending_read_); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 410 | 424 |
| 411 if (!splicer_->HasNextBuffer()) { | 425 if (!splicer_->HasNextBuffer()) { |
| 412 AttemptRead_Locked(); | 426 AttemptRead_Locked(); |
| 413 return; | 427 return; |
| 414 } | 428 } |
| 415 | 429 |
| 416 bool need_another_buffer = false; | 430 bool need_another_buffer = false; |
| 417 while (splicer_->HasNextBuffer()) | 431 while (splicer_->HasNextBuffer()) |
| 418 need_another_buffer = HandleSplicerBuffer_Locked(splicer_->GetNextBuffer()); | 432 need_another_buffer = HandleSplicerBuffer_Locked(splicer_->GetNextBuffer()); |
| 419 | 433 |
| 420 if (!need_another_buffer && !CanRead_Locked()) | 434 if (!need_another_buffer) |
| 421 return; | 435 return; |
| 422 | 436 |
| 423 AttemptRead_Locked(); | 437 AttemptRead_Locked(); |
| 424 } | 438 } |
| 425 | 439 |
| 426 bool AudioRendererImpl::HandleSplicerBuffer_Locked( | 440 bool AudioRendererImpl::HandleSplicerBuffer_Locked( |
| 427 const scoped_refptr<AudioBuffer>& buffer) { | 441 const scoped_refptr<AudioBuffer>& buffer) { |
| 428 lock_.AssertAcquired(); | 442 lock_.AssertAcquired(); |
| 429 if (buffer->end_of_stream()) { | 443 if (buffer->end_of_stream()) { |
| 430 received_end_of_stream_ = true; | 444 received_end_of_stream_ = true; |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 456 NOTREACHED(); | 470 NOTREACHED(); |
| 457 return false; | 471 return false; |
| 458 | 472 |
| 459 case kFlushed: | 473 case kFlushed: |
| 460 DCHECK(!pending_read_); | 474 DCHECK(!pending_read_); |
| 461 return false; | 475 return false; |
| 462 | 476 |
| 463 case kPlaying: | 477 case kPlaying: |
| 464 if (buffer->end_of_stream() || algorithm_->IsQueueFull()) { | 478 if (buffer->end_of_stream() || algorithm_->IsQueueFull()) { |
| 465 if (buffering_state_ == BUFFERING_HAVE_NOTHING) | 479 if (buffering_state_ == BUFFERING_HAVE_NOTHING) |
| 466 SetBufferingState_Locked(BUFFERING_HAVE_ENOUGH); | 480 SetBufferingState(BUFFERING_HAVE_ENOUGH); |
| 467 return false; | 481 return false; |
| 468 } | 482 } |
| 469 return true; | 483 return true; |
| 470 | 484 |
| 471 case kStopped: | 485 case kStopped: |
| 472 return false; | 486 return false; |
| 473 } | 487 } |
| 474 return false; | 488 return false; |
| 475 } | 489 } |
| 476 | 490 |
| 477 void AudioRendererImpl::AttemptRead() { | |
| 478 base::AutoLock auto_lock(lock_); | |
| 479 AttemptRead_Locked(); | |
| 480 } | |
| 481 | |
| 482 void AudioRendererImpl::AttemptRead_Locked() { | 491 void AudioRendererImpl::AttemptRead_Locked() { |
| 483 DCHECK(task_runner_->BelongsToCurrentThread()); | 492 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 484 lock_.AssertAcquired(); | 493 lock_.AssertAcquired(); |
| 485 | 494 |
| 486 if (!CanRead_Locked()) | |
| 487 return; | |
| 488 | |
| 489 pending_read_ = true; | |
| 490 audio_buffer_stream_.Read(base::Bind(&AudioRendererImpl::DecodedAudioReady, | |
| 491 weak_factory_.GetWeakPtr())); | |
| 492 } | |
| 493 | |
| 494 bool AudioRendererImpl::CanRead_Locked() { | |
| 495 lock_.AssertAcquired(); | |
| 496 | |
| 497 switch (state_) { | 495 switch (state_) { |
| 498 case kUninitialized: | 496 case kUninitialized: |
| 499 case kInitializing: | 497 case kInitializing: |
| 500 case kFlushing: | 498 case kFlushing: |
| 501 case kFlushed: | 499 case kFlushed: |
| 502 case kStopped: | 500 case kStopped: |
| 503 return false; | 501 return; |
| 504 | 502 |
| 505 case kPlaying: | 503 case kPlaying: |
| 506 break; | 504 break; |
| 507 } | 505 } |
| 508 | 506 |
| 509 return !pending_read_ && !received_end_of_stream_ && | 507 if (pending_read_ || received_end_of_stream_ || algorithm_->IsQueueFull()) |
| 510 !algorithm_->IsQueueFull(); | 508 return; |
| 509 | |
| 510 pending_read_ = true; | |
| 511 audio_buffer_stream_.Read(base::Bind(&AudioRendererImpl::DecodedAudioReady, | |
| 512 weak_factory_.GetWeakPtr())); | |
| 511 } | 513 } |
| 512 | 514 |
| 513 void AudioRendererImpl::SetPlaybackRate(float playback_rate) { | 515 void AudioRendererImpl::SetPlaybackRate(float playback_rate) { |
| 514 DVLOG(1) << __FUNCTION__ << "(" << playback_rate << ")"; | 516 DVLOG(1) << __FUNCTION__ << "(" << playback_rate << ")"; |
| 515 DCHECK(task_runner_->BelongsToCurrentThread()); | 517 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 516 DCHECK_GE(playback_rate, 0); | 518 DCHECK_GE(playback_rate, 0); |
| 517 DCHECK(sink_); | 519 DCHECK(sink_); |
| 518 | 520 |
| 519 base::AutoLock auto_lock(lock_); | 521 base::AutoLock auto_lock(lock_); |
| 520 | 522 |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 540 | 542 |
| 541 bool AudioRendererImpl::IsBeforeStartTime( | 543 bool AudioRendererImpl::IsBeforeStartTime( |
| 542 const scoped_refptr<AudioBuffer>& buffer) { | 544 const scoped_refptr<AudioBuffer>& buffer) { |
| 543 DCHECK_EQ(state_, kPlaying); | 545 DCHECK_EQ(state_, kPlaying); |
| 544 return buffer && !buffer->end_of_stream() && | 546 return buffer && !buffer->end_of_stream() && |
| 545 (buffer->timestamp() + buffer->duration()) < start_timestamp_; | 547 (buffer->timestamp() + buffer->duration()) < start_timestamp_; |
| 546 } | 548 } |
| 547 | 549 |
| 548 int AudioRendererImpl::Render(AudioBus* audio_bus, | 550 int AudioRendererImpl::Render(AudioBus* audio_bus, |
| 549 int audio_delay_milliseconds) { | 551 int audio_delay_milliseconds) { |
| 550 const int requested_frames = audio_bus->frames(); | 552 DVLOG(2) << __FUNCTION__; |
| 551 base::TimeDelta playback_delay = base::TimeDelta::FromMilliseconds( | 553 base::TimeDelta playback_delay = |
| 552 audio_delay_milliseconds); | 554 base::TimeDelta::FromMilliseconds(audio_delay_milliseconds); |
| 553 const int delay_frames = static_cast<int>(playback_delay.InSecondsF() * | 555 |
| 554 audio_parameters_.sample_rate()); | 556 RenderResult result; |
| 555 int frames_written = 0; | 557 result.ticks = tick_clock_->NowTicks(); |
| 556 base::Closure time_cb; | 558 result.requested_frames = audio_bus->frames(); |
| 559 result.delay_frames = static_cast<int>(playback_delay.InSecondsF() * | |
| 560 audio_parameters_.sample_rate()); | |
| 561 | |
| 557 { | 562 { |
| 558 base::AutoLock auto_lock(lock_); | 563 base::AutoLock auto_lock(lock_); |
| 559 | 564 if (state_ == kPlaying && algorithm_->frames_buffered() > 0) { |
| 560 // Ensure Stop() hasn't destroyed our |algorithm_| on the pipeline thread. | 565 result.frames_written = |
| 561 if (!algorithm_) { | 566 algorithm_->FillBuffer(audio_bus, result.requested_frames); |
| 562 audio_clock_->WroteSilence(requested_frames, delay_frames); | 567 result.playback_rate = algorithm_->playback_rate(); |
| 563 return 0; | 568 result.endpoint_timestamp = algorithm_->GetTime(); |
| 564 } | |
| 565 | |
| 566 float playback_rate = algorithm_->playback_rate(); | |
| 567 if (playback_rate == 0) { | |
| 568 audio_clock_->WroteSilence(requested_frames, delay_frames); | |
| 569 return 0; | |
| 570 } | |
| 571 | |
| 572 // Mute audio by returning 0 when not playing. | |
| 573 if (state_ != kPlaying) { | |
| 574 audio_clock_->WroteSilence(requested_frames, delay_frames); | |
| 575 return 0; | |
| 576 } | |
| 577 | |
| 578 // We use the following conditions to determine end of playback: | |
| 579 // 1) Algorithm can not fill the audio callback buffer | |
| 580 // 2) We received an end of stream buffer | |
| 581 // 3) We haven't already signalled that we've ended | |
| 582 // 4) We've played all known audio data sent to hardware | |
| 583 // | |
| 584 // We use the following conditions to determine underflow: | |
| 585 // 1) Algorithm can not fill the audio callback buffer | |
| 586 // 2) We have NOT received an end of stream buffer | |
| 587 // 3) We are in the kPlaying state | |
| 588 // | |
| 589 // Otherwise the buffer has data we can send to the device. | |
| 590 const base::TimeDelta media_timestamp_before_filling = | |
| 591 audio_clock_->CurrentMediaTimestamp(base::TimeDelta()); | |
| 592 if (algorithm_->frames_buffered() > 0) { | |
| 593 frames_written = algorithm_->FillBuffer(audio_bus, requested_frames); | |
| 594 audio_clock_->WroteAudio( | |
| 595 frames_written, delay_frames, playback_rate, algorithm_->GetTime()); | |
| 596 } | |
| 597 audio_clock_->WroteSilence(requested_frames - frames_written, delay_frames); | |
| 598 | |
| 599 if (frames_written == 0) { | |
| 600 if (received_end_of_stream_ && !rendered_end_of_stream_ && | |
| 601 audio_clock_->CurrentMediaTimestamp(base::TimeDelta()) == | |
| 602 audio_clock_->last_endpoint_timestamp()) { | |
| 603 rendered_end_of_stream_ = true; | |
| 604 ended_cb_.Run(); | |
| 605 } else if (!received_end_of_stream_ && state_ == kPlaying) { | |
| 606 if (buffering_state_ != BUFFERING_HAVE_NOTHING) { | |
| 607 algorithm_->IncreaseQueueCapacity(); | |
| 608 SetBufferingState_Locked(BUFFERING_HAVE_NOTHING); | |
| 609 } | |
| 610 } | |
| 611 } | |
| 612 | |
| 613 if (CanRead_Locked()) { | |
| 614 task_runner_->PostTask(FROM_HERE, | |
| 615 base::Bind(&AudioRendererImpl::AttemptRead, | |
| 616 weak_factory_.GetWeakPtr())); | |
| 617 } | |
| 618 | |
| 619 // We only want to execute |time_cb_| if time has progressed and we haven't | |
| 620 // signaled end of stream yet. | |
| 621 if (media_timestamp_before_filling != | |
| 622 audio_clock_->CurrentMediaTimestamp(base::TimeDelta()) && | |
| 623 !rendered_end_of_stream_) { | |
| 624 time_cb = | |
| 625 base::Bind(time_cb_, | |
| 626 audio_clock_->CurrentMediaTimestamp(base::TimeDelta()), | |
| 627 audio_clock_->last_endpoint_timestamp()); | |
| 628 } | 569 } |
| 629 } | 570 } |
| 630 | 571 |
| 631 if (!time_cb.is_null()) | 572 task_runner_->PostTask( |
| 632 task_runner_->PostTask(FROM_HERE, time_cb); | 573 FROM_HERE, |
| 574 base::Bind( | |
| 575 &AudioRendererImpl::DidRender, weak_factory_.GetWeakPtr(), result)); | |
| 633 | 576 |
| 634 DCHECK_LE(frames_written, requested_frames); | 577 return result.frames_written; |
| 635 return frames_written; | 578 } |
| 579 | |
| 580 void AudioRendererImpl::DidRender(RenderResult result) { | |
| 581 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 582 DVLOG(2) << __FUNCTION__; | |
| 583 | |
| 584 base::AutoLock auto_lock(lock_); | |
| 585 if (state_ == kStopped) | |
| 586 return; | |
| 587 | |
| 588 if (result.frames_written > 0) { | |
| 589 audio_clock_->WroteAudio(result.frames_written, | |
| 590 result.delay_frames, | |
| 591 result.playback_rate, | |
| 592 result.endpoint_timestamp); | |
| 593 } | |
| 594 audio_clock_->WroteSilence(result.requested_frames - result.frames_written, | |
| 595 result.delay_frames); | |
| 596 | |
| 597 // We use the following conditions to determine end of playback: | |
| 598 // 1) Algorithm can not fill the audio callback buffer | |
| 599 // 2) We received an end of stream buffer | |
| 600 // 3) We haven't already signalled that we've ended | |
| 601 // 4) We've played all known audio data sent to hardware | |
| 602 // | |
| 603 // We use the following conditions to determine underflow: | |
| 604 // 1) Algorithm can not fill the audio callback buffer | |
| 605 // 2) We have NOT received an end of stream buffer | |
| 606 // 3) We are in the kPlaying state | |
| 607 if (result.frames_written == 0) { | |
| 608 if (received_end_of_stream_ && !rendered_end_of_stream_ && | |
| 609 audio_clock_->CurrentMediaTimestamp(base::TimeDelta()) == | |
|
DaleCurtis
2014/07/15 19:25:28
Shouldn't this be using the time since writing?
scherkus (not reviewing)
2014/07/15 20:14:22
Maybe ... I'm still thinking what the right option
| |
| 610 audio_clock_->last_endpoint_timestamp()) { | |
| 611 rendered_end_of_stream_ = true; | |
| 612 ended_cb_.Run(); | |
| 613 } else if (!received_end_of_stream_ && state_ == kPlaying) { | |
| 614 if (buffering_state_ != BUFFERING_HAVE_NOTHING) { | |
| 615 algorithm_->IncreaseQueueCapacity(); | |
| 616 SetBufferingState(BUFFERING_HAVE_NOTHING); | |
| 617 } | |
| 618 } | |
| 619 } | |
| 620 | |
| 621 // Use adjusted media timestamp that takes time since writing into account. | |
| 622 if (!rendered_end_of_stream_) { | |
| 623 base::TimeDelta time_since_writing = tick_clock_->NowTicks() - result.ticks; | |
| 624 time_cb_.Run(audio_clock_->CurrentMediaTimestamp(time_since_writing), | |
| 625 audio_clock_->last_endpoint_timestamp()); | |
| 626 } | |
| 627 | |
| 628 AttemptRead_Locked(); | |
| 636 } | 629 } |
| 637 | 630 |
| 638 void AudioRendererImpl::OnRenderError() { | 631 void AudioRendererImpl::OnRenderError() { |
| 639 // UMA data tells us this happens ~0.01% of the time. Trigger an error instead | 632 // UMA data tells us this happens ~0.01% of the time. Trigger an error instead |
| 640 // of trying to gracefully fall back to a fake sink. It's very likely | 633 // of trying to gracefully fall back to a fake sink. It's very likely |
| 641 // OnRenderError() should be removed and the audio stack handle errors without | 634 // OnRenderError() should be removed and the audio stack handle errors without |
| 642 // notifying clients. See http://crbug.com/234708 for details. | 635 // notifying clients. See http://crbug.com/234708 for details. |
| 643 HistogramRendererEvent(RENDER_ERROR); | 636 HistogramRendererEvent(RENDER_ERROR); |
| 644 error_cb_.Run(PIPELINE_ERROR_DECODE); | 637 error_cb_.Run(PIPELINE_ERROR_DECODE); |
| 645 } | 638 } |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 688 DCHECK(task_runner_->BelongsToCurrentThread()); | 681 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 689 DCHECK(expecting_config_changes_); | 682 DCHECK(expecting_config_changes_); |
| 690 buffer_converter_->ResetTimestampState(); | 683 buffer_converter_->ResetTimestampState(); |
| 691 // Drain flushed buffers from the converter so the AudioSplicer receives all | 684 // Drain flushed buffers from the converter so the AudioSplicer receives all |
| 692 // data ahead of any OnNewSpliceBuffer() calls. Since discontinuities should | 685 // data ahead of any OnNewSpliceBuffer() calls. Since discontinuities should |
| 693 // only appear after config changes, AddInput() should never fail here. | 686 // only appear after config changes, AddInput() should never fail here. |
| 694 while (buffer_converter_->HasNextBuffer()) | 687 while (buffer_converter_->HasNextBuffer()) |
| 695 CHECK(splicer_->AddInput(buffer_converter_->GetNextBuffer())); | 688 CHECK(splicer_->AddInput(buffer_converter_->GetNextBuffer())); |
| 696 } | 689 } |
| 697 | 690 |
| 698 void AudioRendererImpl::SetBufferingState_Locked( | 691 void AudioRendererImpl::SetBufferingState(BufferingState buffering_state) { |
| 699 BufferingState buffering_state) { | |
| 700 DVLOG(1) << __FUNCTION__ << " : " << buffering_state_ << " -> " | 692 DVLOG(1) << __FUNCTION__ << " : " << buffering_state_ << " -> " |
| 701 << buffering_state; | 693 << buffering_state; |
| 694 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 702 DCHECK_NE(buffering_state_, buffering_state); | 695 DCHECK_NE(buffering_state_, buffering_state); |
| 703 lock_.AssertAcquired(); | |
| 704 buffering_state_ = buffering_state; | 696 buffering_state_ = buffering_state; |
| 705 | 697 |
| 706 task_runner_->PostTask(FROM_HERE, | 698 task_runner_->PostTask(FROM_HERE, |
| 707 base::Bind(buffering_state_cb_, buffering_state_)); | 699 base::Bind(buffering_state_cb_, buffering_state_)); |
| 708 } | 700 } |
| 709 | 701 |
| 710 } // namespace media | 702 } // namespace media |
| OLD | NEW |