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 |
(...skipping 22 matching lines...) Expand all Loading... | |
33 RENDER_EVENT_MAX = RENDER_ERROR, | 33 RENDER_EVENT_MAX = RENDER_ERROR, |
34 }; | 34 }; |
35 | 35 |
36 void HistogramRendererEvent(AudioRendererEvent event) { | 36 void HistogramRendererEvent(AudioRendererEvent event) { |
37 UMA_HISTOGRAM_ENUMERATION( | 37 UMA_HISTOGRAM_ENUMERATION( |
38 "Media.AudioRendererEvents", event, RENDER_EVENT_MAX + 1); | 38 "Media.AudioRendererEvents", event, RENDER_EVENT_MAX + 1); |
39 } | 39 } |
40 | 40 |
41 } // namespace | 41 } // namespace |
42 | 42 |
43 AudioRendererImpl::RenderResult::RenderResult() | |
44 : requested_frames(0), | |
45 delay_frames(0), | |
46 frames_written(0), | |
47 playback_rate(0), | |
48 endpoint_timestamp(kNoTimestamp()) { | |
49 } | |
50 | |
43 AudioRendererImpl::AudioRendererImpl( | 51 AudioRendererImpl::AudioRendererImpl( |
44 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, | 52 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, |
45 media::AudioRendererSink* sink, | 53 media::AudioRendererSink* sink, |
46 ScopedVector<AudioDecoder> decoders, | 54 ScopedVector<AudioDecoder> decoders, |
47 const SetDecryptorReadyCB& set_decryptor_ready_cb, | 55 const SetDecryptorReadyCB& set_decryptor_ready_cb, |
48 AudioHardwareConfig* hardware_config) | 56 AudioHardwareConfig* hardware_config) |
49 : task_runner_(task_runner), | 57 : task_runner_(task_runner), |
50 sink_(sink), | 58 sink_(sink), |
51 audio_buffer_stream_(task_runner, | 59 audio_buffer_stream_(task_runner, |
52 decoders.Pass(), | 60 decoders.Pass(), |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
169 | 177 |
170 DCHECK_EQ(state_, kFlushed); | 178 DCHECK_EQ(state_, kFlushed); |
171 DCHECK(!flush_cb_.is_null()); | 179 DCHECK(!flush_cb_.is_null()); |
172 | 180 |
173 audio_clock_.reset(new AudioClock(audio_parameters_.sample_rate())); | 181 audio_clock_.reset(new AudioClock(audio_parameters_.sample_rate())); |
174 received_end_of_stream_ = false; | 182 received_end_of_stream_ = false; |
175 rendered_end_of_stream_ = false; | 183 rendered_end_of_stream_ = false; |
176 | 184 |
177 // Flush() may have been called while underflowed/not fully buffered. | 185 // Flush() may have been called while underflowed/not fully buffered. |
178 if (buffering_state_ != BUFFERING_HAVE_NOTHING) | 186 if (buffering_state_ != BUFFERING_HAVE_NOTHING) |
179 SetBufferingState_Locked(BUFFERING_HAVE_NOTHING); | 187 SetBufferingState(BUFFERING_HAVE_NOTHING); |
180 | 188 |
181 splicer_->Reset(); | 189 splicer_->Reset(); |
182 if (buffer_converter_) | 190 if (buffer_converter_) |
183 buffer_converter_->Reset(); | 191 buffer_converter_->Reset(); |
184 algorithm_->FlushBuffers(); | 192 algorithm_->FlushBuffers(); |
185 } | 193 } |
186 | 194 |
187 // Changes in buffering state are always posted. Flush callback must only be | 195 // Changes in buffering state are always posted. Flush callback must only be |
188 // run after buffering state has been set back to nothing. | 196 // run after buffering state has been set back to nothing. |
189 task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&flush_cb_)); | 197 task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&flush_cb_)); |
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
410 | 418 |
411 if (!splicer_->HasNextBuffer()) { | 419 if (!splicer_->HasNextBuffer()) { |
412 AttemptRead_Locked(); | 420 AttemptRead_Locked(); |
413 return; | 421 return; |
414 } | 422 } |
415 | 423 |
416 bool need_another_buffer = false; | 424 bool need_another_buffer = false; |
417 while (splicer_->HasNextBuffer()) | 425 while (splicer_->HasNextBuffer()) |
418 need_another_buffer = HandleSplicerBuffer_Locked(splicer_->GetNextBuffer()); | 426 need_another_buffer = HandleSplicerBuffer_Locked(splicer_->GetNextBuffer()); |
419 | 427 |
420 if (!need_another_buffer && !CanRead_Locked()) | 428 if (!need_another_buffer) |
421 return; | 429 return; |
422 | 430 |
423 AttemptRead_Locked(); | 431 AttemptRead_Locked(); |
424 } | 432 } |
425 | 433 |
426 bool AudioRendererImpl::HandleSplicerBuffer_Locked( | 434 bool AudioRendererImpl::HandleSplicerBuffer_Locked( |
427 const scoped_refptr<AudioBuffer>& buffer) { | 435 const scoped_refptr<AudioBuffer>& buffer) { |
428 lock_.AssertAcquired(); | 436 lock_.AssertAcquired(); |
429 if (buffer->end_of_stream()) { | 437 if (buffer->end_of_stream()) { |
430 received_end_of_stream_ = true; | 438 received_end_of_stream_ = true; |
(...skipping 25 matching lines...) Expand all Loading... | |
456 NOTREACHED(); | 464 NOTREACHED(); |
457 return false; | 465 return false; |
458 | 466 |
459 case kFlushed: | 467 case kFlushed: |
460 DCHECK(!pending_read_); | 468 DCHECK(!pending_read_); |
461 return false; | 469 return false; |
462 | 470 |
463 case kPlaying: | 471 case kPlaying: |
464 if (buffer->end_of_stream() || algorithm_->IsQueueFull()) { | 472 if (buffer->end_of_stream() || algorithm_->IsQueueFull()) { |
465 if (buffering_state_ == BUFFERING_HAVE_NOTHING) | 473 if (buffering_state_ == BUFFERING_HAVE_NOTHING) |
466 SetBufferingState_Locked(BUFFERING_HAVE_ENOUGH); | 474 SetBufferingState(BUFFERING_HAVE_ENOUGH); |
467 return false; | 475 return false; |
468 } | 476 } |
469 return true; | 477 return true; |
470 | 478 |
471 case kStopped: | 479 case kStopped: |
472 return false; | 480 return false; |
473 } | 481 } |
474 return false; | 482 return false; |
475 } | 483 } |
476 | 484 |
477 void AudioRendererImpl::AttemptRead() { | |
478 base::AutoLock auto_lock(lock_); | |
479 AttemptRead_Locked(); | |
480 } | |
481 | |
482 void AudioRendererImpl::AttemptRead_Locked() { | 485 void AudioRendererImpl::AttemptRead_Locked() { |
483 DCHECK(task_runner_->BelongsToCurrentThread()); | 486 DCHECK(task_runner_->BelongsToCurrentThread()); |
484 lock_.AssertAcquired(); | 487 lock_.AssertAcquired(); |
485 | 488 |
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_) { | 489 switch (state_) { |
498 case kUninitialized: | 490 case kUninitialized: |
499 case kInitializing: | 491 case kInitializing: |
500 case kFlushing: | 492 case kFlushing: |
501 case kFlushed: | 493 case kFlushed: |
502 case kStopped: | 494 case kStopped: |
503 return false; | 495 return; |
504 | 496 |
505 case kPlaying: | 497 case kPlaying: |
506 break; | 498 break; |
507 } | 499 } |
508 | 500 |
509 return !pending_read_ && !received_end_of_stream_ && | 501 if (pending_read_ || received_end_of_stream_ || algorithm_->IsQueueFull()) |
510 !algorithm_->IsQueueFull(); | 502 return; |
503 | |
504 pending_read_ = true; | |
505 audio_buffer_stream_.Read(base::Bind(&AudioRendererImpl::DecodedAudioReady, | |
506 weak_factory_.GetWeakPtr())); | |
511 } | 507 } |
512 | 508 |
513 void AudioRendererImpl::SetPlaybackRate(float playback_rate) { | 509 void AudioRendererImpl::SetPlaybackRate(float playback_rate) { |
514 DVLOG(1) << __FUNCTION__ << "(" << playback_rate << ")"; | 510 DVLOG(1) << __FUNCTION__ << "(" << playback_rate << ")"; |
515 DCHECK(task_runner_->BelongsToCurrentThread()); | 511 DCHECK(task_runner_->BelongsToCurrentThread()); |
516 DCHECK_GE(playback_rate, 0); | 512 DCHECK_GE(playback_rate, 0); |
517 DCHECK(sink_); | 513 DCHECK(sink_); |
518 | 514 |
519 base::AutoLock auto_lock(lock_); | 515 base::AutoLock auto_lock(lock_); |
520 | 516 |
(...skipping 19 matching lines...) Expand all Loading... | |
540 | 536 |
541 bool AudioRendererImpl::IsBeforeStartTime( | 537 bool AudioRendererImpl::IsBeforeStartTime( |
542 const scoped_refptr<AudioBuffer>& buffer) { | 538 const scoped_refptr<AudioBuffer>& buffer) { |
543 DCHECK_EQ(state_, kPlaying); | 539 DCHECK_EQ(state_, kPlaying); |
544 return buffer && !buffer->end_of_stream() && | 540 return buffer && !buffer->end_of_stream() && |
545 (buffer->timestamp() + buffer->duration()) < start_timestamp_; | 541 (buffer->timestamp() + buffer->duration()) < start_timestamp_; |
546 } | 542 } |
547 | 543 |
548 int AudioRendererImpl::Render(AudioBus* audio_bus, | 544 int AudioRendererImpl::Render(AudioBus* audio_bus, |
549 int audio_delay_milliseconds) { | 545 int audio_delay_milliseconds) { |
550 const int requested_frames = audio_bus->frames(); | 546 DVLOG(2) << __FUNCTION__; |
DaleCurtis
2014/07/10 23:37:00
Probably you should remove this, or make DVLOG(3).
| |
551 base::TimeDelta playback_delay = base::TimeDelta::FromMilliseconds( | 547 base::TimeDelta playback_delay = |
552 audio_delay_milliseconds); | 548 base::TimeDelta::FromMilliseconds(audio_delay_milliseconds); |
553 const int delay_frames = static_cast<int>(playback_delay.InSecondsF() * | 549 |
554 audio_parameters_.sample_rate()); | 550 RenderResult result; |
555 int frames_written = 0; | 551 result.requested_frames = audio_bus->frames(); |
556 base::Closure time_cb; | 552 result.delay_frames = static_cast<int>(playback_delay.InSecondsF() * |
553 audio_parameters_.sample_rate()); | |
554 | |
557 { | 555 { |
558 base::AutoLock auto_lock(lock_); | 556 base::AutoLock auto_lock(lock_); |
559 | 557 if (state_ == kPlaying && algorithm_->frames_buffered() > 0) { |
560 // Ensure Stop() hasn't destroyed our |algorithm_| on the pipeline thread. | 558 result.frames_written = |
561 if (!algorithm_) { | 559 algorithm_->FillBuffer(audio_bus, result.requested_frames); |
562 audio_clock_->WroteSilence(requested_frames, delay_frames); | 560 result.playback_rate = algorithm_->playback_rate(); |
563 return 0; | 561 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(); | |
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() == | |
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() && | |
623 !rendered_end_of_stream_) { | |
624 time_cb = base::Bind(time_cb_, | |
625 audio_clock_->CurrentMediaTimestamp(), | |
626 audio_clock_->last_endpoint_timestamp()); | |
627 } | 562 } |
628 } | 563 } |
629 | 564 |
630 if (!time_cb.is_null()) | 565 task_runner_->PostTask( |
631 task_runner_->PostTask(FROM_HERE, time_cb); | 566 FROM_HERE, |
567 base::Bind( | |
568 &AudioRendererImpl::DidRender, weak_factory_.GetWeakPtr(), result)); | |
632 | 569 |
633 DCHECK_LE(frames_written, requested_frames); | 570 return result.frames_written; |
634 return frames_written; | 571 } |
572 | |
573 void AudioRendererImpl::DidRender(RenderResult result) { | |
574 DCHECK(task_runner_->BelongsToCurrentThread()); | |
575 DVLOG(2) << __FUNCTION__; | |
DaleCurtis
2014/07/10 23:37:00
Ditto.
| |
576 | |
577 base::AutoLock auto_lock(lock_); | |
DaleCurtis
2014/07/10 23:37:00
Only needed when accessing algorithm_ and reading?
| |
578 if (state_ == kStopped) | |
579 return; | |
580 | |
581 base::TimeDelta previous_media_timestamp = | |
582 audio_clock_->CurrentMediaTimestamp(); | |
583 | |
584 if (result.frames_written > 0) { | |
585 audio_clock_->WroteAudio(result.frames_written, | |
586 result.delay_frames, | |
587 result.playback_rate, | |
588 result.endpoint_timestamp); | |
589 } | |
590 audio_clock_->WroteSilence(result.requested_frames - result.frames_written, | |
591 result.delay_frames); | |
592 | |
593 // We use the following conditions to determine end of playback: | |
594 // 1) Algorithm can not fill the audio callback buffer | |
595 // 2) We received an end of stream buffer | |
596 // 3) We haven't already signalled that we've ended | |
597 // 4) We've played all known audio data sent to hardware | |
598 // | |
599 // We use the following conditions to determine underflow: | |
600 // 1) Algorithm can not fill the audio callback buffer | |
601 // 2) We have NOT received an end of stream buffer | |
602 // 3) We are in the kPlaying state | |
603 if (result.frames_written == 0) { | |
604 if (received_end_of_stream_ && !rendered_end_of_stream_ && | |
605 audio_clock_->CurrentMediaTimestamp() == | |
606 audio_clock_->last_endpoint_timestamp()) { | |
607 rendered_end_of_stream_ = true; | |
608 ended_cb_.Run(); | |
609 } else if (!received_end_of_stream_ && state_ == kPlaying) { | |
610 if (buffering_state_ != BUFFERING_HAVE_NOTHING) { | |
611 algorithm_->IncreaseQueueCapacity(); | |
612 SetBufferingState(BUFFERING_HAVE_NOTHING); | |
613 } | |
614 } | |
615 } | |
616 | |
617 // Don't fire time updates if we don't need to (e.g., time hasn't changed, | |
618 // playback has ended). | |
619 if (previous_media_timestamp != audio_clock_->CurrentMediaTimestamp() && | |
620 !rendered_end_of_stream_) { | |
621 time_cb_.Run(audio_clock_->CurrentMediaTimestamp(), | |
622 audio_clock_->last_endpoint_timestamp()); | |
623 } | |
624 | |
625 AttemptRead_Locked(); | |
635 } | 626 } |
636 | 627 |
637 void AudioRendererImpl::OnRenderError() { | 628 void AudioRendererImpl::OnRenderError() { |
638 // UMA data tells us this happens ~0.01% of the time. Trigger an error instead | 629 // UMA data tells us this happens ~0.01% of the time. Trigger an error instead |
639 // of trying to gracefully fall back to a fake sink. It's very likely | 630 // of trying to gracefully fall back to a fake sink. It's very likely |
640 // OnRenderError() should be removed and the audio stack handle errors without | 631 // OnRenderError() should be removed and the audio stack handle errors without |
641 // notifying clients. See http://crbug.com/234708 for details. | 632 // notifying clients. See http://crbug.com/234708 for details. |
642 HistogramRendererEvent(RENDER_ERROR); | 633 HistogramRendererEvent(RENDER_ERROR); |
643 error_cb_.Run(PIPELINE_ERROR_DECODE); | 634 error_cb_.Run(PIPELINE_ERROR_DECODE); |
644 } | 635 } |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
687 DCHECK(task_runner_->BelongsToCurrentThread()); | 678 DCHECK(task_runner_->BelongsToCurrentThread()); |
688 DCHECK(expecting_config_changes_); | 679 DCHECK(expecting_config_changes_); |
689 buffer_converter_->ResetTimestampState(); | 680 buffer_converter_->ResetTimestampState(); |
690 // Drain flushed buffers from the converter so the AudioSplicer receives all | 681 // Drain flushed buffers from the converter so the AudioSplicer receives all |
691 // data ahead of any OnNewSpliceBuffer() calls. Since discontinuities should | 682 // data ahead of any OnNewSpliceBuffer() calls. Since discontinuities should |
692 // only appear after config changes, AddInput() should never fail here. | 683 // only appear after config changes, AddInput() should never fail here. |
693 while (buffer_converter_->HasNextBuffer()) | 684 while (buffer_converter_->HasNextBuffer()) |
694 CHECK(splicer_->AddInput(buffer_converter_->GetNextBuffer())); | 685 CHECK(splicer_->AddInput(buffer_converter_->GetNextBuffer())); |
695 } | 686 } |
696 | 687 |
697 void AudioRendererImpl::SetBufferingState_Locked( | 688 void AudioRendererImpl::SetBufferingState(BufferingState buffering_state) { |
698 BufferingState buffering_state) { | |
699 DVLOG(1) << __FUNCTION__ << " : " << buffering_state_ << " -> " | 689 DVLOG(1) << __FUNCTION__ << " : " << buffering_state_ << " -> " |
700 << buffering_state; | 690 << buffering_state; |
691 DCHECK(task_runner_->BelongsToCurrentThread()); | |
701 DCHECK_NE(buffering_state_, buffering_state); | 692 DCHECK_NE(buffering_state_, buffering_state); |
702 lock_.AssertAcquired(); | |
703 buffering_state_ = buffering_state; | 693 buffering_state_ = buffering_state; |
704 | 694 |
705 task_runner_->PostTask(FROM_HERE, | 695 task_runner_->PostTask(FROM_HERE, |
706 base::Bind(buffering_state_cb_, buffering_state_)); | 696 base::Bind(buffering_state_cb_, buffering_state_)); |
707 } | 697 } |
708 | 698 |
709 } // namespace media | 699 } // namespace media |
OLD | NEW |