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

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

Issue 1687213002: Express audio delay more precisely in frames rather than milliseconds. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase Created 4 years, 10 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
« no previous file with comments | « media/renderers/audio_renderer_impl.h ('k') | media/renderers/audio_renderer_impl_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/renderers/audio_renderer_impl.h" 5 #include "media/renderers/audio_renderer_impl.h"
6 6
7 #include <math.h> 7 #include <math.h>
8 #include <stddef.h> 8 #include <stddef.h>
9 #include <algorithm> 9 #include <algorithm>
10 #include <utility> 10 #include <utility>
(...skipping 616 matching lines...) Expand 10 before | Expand all | Expand 10 after
627 } 627 }
628 628
629 bool AudioRendererImpl::IsBeforeStartTime( 629 bool AudioRendererImpl::IsBeforeStartTime(
630 const scoped_refptr<AudioBuffer>& buffer) { 630 const scoped_refptr<AudioBuffer>& buffer) {
631 DCHECK_EQ(state_, kPlaying); 631 DCHECK_EQ(state_, kPlaying);
632 return buffer.get() && !buffer->end_of_stream() && 632 return buffer.get() && !buffer->end_of_stream() &&
633 (buffer->timestamp() + buffer->duration()) < start_timestamp_; 633 (buffer->timestamp() + buffer->duration()) < start_timestamp_;
634 } 634 }
635 635
636 int AudioRendererImpl::Render(AudioBus* audio_bus, 636 int AudioRendererImpl::Render(AudioBus* audio_bus,
637 uint32_t audio_delay_milliseconds, 637 uint32_t frames_delayed,
638 uint32_t frames_skipped) { 638 uint32_t frames_skipped) {
639 const int requested_frames = audio_bus->frames(); 639 const int frames_requested = audio_bus->frames();
640 base::TimeDelta playback_delay = base::TimeDelta::FromMilliseconds( 640 DVLOG(4) << __FUNCTION__ << " frames_delayed:" << frames_delayed
641 audio_delay_milliseconds); 641 << " frames_skipped:" << frames_skipped
642 const int delay_frames = static_cast<int>(playback_delay.InSecondsF() * 642 << " frames_requested:" << frames_requested;
643 audio_parameters_.sample_rate()); 643
644 int frames_written = 0; 644 int frames_written = 0;
645 { 645 {
646 base::AutoLock auto_lock(lock_); 646 base::AutoLock auto_lock(lock_);
647 last_render_time_ = tick_clock_->NowTicks(); 647 last_render_time_ = tick_clock_->NowTicks();
648 648
649 if (!stop_rendering_time_.is_null()) { 649 if (!stop_rendering_time_.is_null()) {
650 audio_clock_->CompensateForSuspendedWrites( 650 audio_clock_->CompensateForSuspendedWrites(
651 last_render_time_ - stop_rendering_time_, delay_frames); 651 last_render_time_ - stop_rendering_time_, frames_delayed);
652 stop_rendering_time_ = base::TimeTicks(); 652 stop_rendering_time_ = base::TimeTicks();
653 } 653 }
654 654
655 // Ensure Stop() hasn't destroyed our |algorithm_| on the pipeline thread. 655 // Ensure Stop() hasn't destroyed our |algorithm_| on the pipeline thread.
656 if (!algorithm_) { 656 if (!algorithm_) {
657 audio_clock_->WroteAudio( 657 audio_clock_->WroteAudio(0, frames_requested, frames_delayed,
658 0, requested_frames, delay_frames, playback_rate_); 658 playback_rate_);
659 return 0; 659 return 0;
660 } 660 }
661 661
662 if (playback_rate_ == 0) { 662 if (playback_rate_ == 0) {
663 audio_clock_->WroteAudio( 663 audio_clock_->WroteAudio(0, frames_requested, frames_delayed,
664 0, requested_frames, delay_frames, playback_rate_); 664 playback_rate_);
665 return 0; 665 return 0;
666 } 666 }
667 667
668 // Mute audio by returning 0 when not playing. 668 // Mute audio by returning 0 when not playing.
669 if (state_ != kPlaying) { 669 if (state_ != kPlaying) {
670 audio_clock_->WroteAudio( 670 audio_clock_->WroteAudio(0, frames_requested, frames_delayed,
671 0, requested_frames, delay_frames, playback_rate_); 671 playback_rate_);
672 return 0; 672 return 0;
673 } 673 }
674 674
675 // Delay playback by writing silence if we haven't reached the first 675 // Delay playback by writing silence if we haven't reached the first
676 // timestamp yet; this can occur if the video starts before the audio. 676 // timestamp yet; this can occur if the video starts before the audio.
677 if (algorithm_->frames_buffered() > 0) { 677 if (algorithm_->frames_buffered() > 0) {
678 CHECK_NE(first_packet_timestamp_, kNoTimestamp()); 678 CHECK_NE(first_packet_timestamp_, kNoTimestamp());
679 CHECK_GE(first_packet_timestamp_, base::TimeDelta()); 679 CHECK_GE(first_packet_timestamp_, base::TimeDelta());
680 const base::TimeDelta play_delay = 680 const base::TimeDelta play_delay =
681 first_packet_timestamp_ - audio_clock_->back_timestamp(); 681 first_packet_timestamp_ - audio_clock_->back_timestamp();
682 CHECK_LT(play_delay.InSeconds(), 1000) 682 CHECK_LT(play_delay.InSeconds(), 1000)
683 << "first_packet_timestamp_ = " << first_packet_timestamp_ 683 << "first_packet_timestamp_ = " << first_packet_timestamp_
684 << ", audio_clock_->back_timestamp() = " 684 << ", audio_clock_->back_timestamp() = "
685 << audio_clock_->back_timestamp(); 685 << audio_clock_->back_timestamp();
686 if (play_delay > base::TimeDelta()) { 686 if (play_delay > base::TimeDelta()) {
687 DCHECK_EQ(frames_written, 0); 687 DCHECK_EQ(frames_written, 0);
688 frames_written = 688 frames_written =
689 std::min(static_cast<int>(play_delay.InSecondsF() * 689 std::min(static_cast<int>(play_delay.InSecondsF() *
690 audio_parameters_.sample_rate()), 690 audio_parameters_.sample_rate()),
691 requested_frames); 691 frames_requested);
692 audio_bus->ZeroFramesPartial(0, frames_written); 692 audio_bus->ZeroFramesPartial(0, frames_written);
693 } 693 }
694 694
695 // If there's any space left, actually render the audio; this is where the 695 // If there's any space left, actually render the audio; this is where the
696 // aural magic happens. 696 // aural magic happens.
697 if (frames_written < requested_frames) { 697 if (frames_written < frames_requested) {
698 frames_written += algorithm_->FillBuffer( 698 frames_written += algorithm_->FillBuffer(
699 audio_bus, frames_written, requested_frames - frames_written, 699 audio_bus, frames_written, frames_requested - frames_written,
700 playback_rate_); 700 playback_rate_);
701 } 701 }
702 } 702 }
703 703
704 // We use the following conditions to determine end of playback: 704 // We use the following conditions to determine end of playback:
705 // 1) Algorithm can not fill the audio callback buffer 705 // 1) Algorithm can not fill the audio callback buffer
706 // 2) We received an end of stream buffer 706 // 2) We received an end of stream buffer
707 // 3) We haven't already signalled that we've ended 707 // 3) We haven't already signalled that we've ended
708 // 4) We've played all known audio data sent to hardware 708 // 4) We've played all known audio data sent to hardware
709 // 709 //
(...skipping 10 matching lines...) Expand all
720 // data has ended. 720 // data has ended.
721 // 721 //
722 // That being said, we don't want to advance time when underflowed as we 722 // That being said, we don't want to advance time when underflowed as we
723 // know more decoded frames will eventually arrive. If we did, we would 723 // know more decoded frames will eventually arrive. If we did, we would
724 // throw things out of sync when said decoded frames arrive. 724 // throw things out of sync when said decoded frames arrive.
725 int frames_after_end_of_stream = 0; 725 int frames_after_end_of_stream = 0;
726 if (frames_written == 0) { 726 if (frames_written == 0) {
727 if (received_end_of_stream_) { 727 if (received_end_of_stream_) {
728 if (ended_timestamp_ == kInfiniteDuration()) 728 if (ended_timestamp_ == kInfiniteDuration())
729 ended_timestamp_ = audio_clock_->back_timestamp(); 729 ended_timestamp_ = audio_clock_->back_timestamp();
730 frames_after_end_of_stream = requested_frames; 730 frames_after_end_of_stream = frames_requested;
731 } else if (state_ == kPlaying && 731 } else if (state_ == kPlaying &&
732 buffering_state_ != BUFFERING_HAVE_NOTHING) { 732 buffering_state_ != BUFFERING_HAVE_NOTHING) {
733 algorithm_->IncreaseQueueCapacity(); 733 algorithm_->IncreaseQueueCapacity();
734 SetBufferingState_Locked(BUFFERING_HAVE_NOTHING); 734 SetBufferingState_Locked(BUFFERING_HAVE_NOTHING);
735 } 735 }
736 } 736 }
737 737
738 audio_clock_->WroteAudio(frames_written + frames_after_end_of_stream, 738 audio_clock_->WroteAudio(frames_written + frames_after_end_of_stream,
739 requested_frames, 739 frames_requested, frames_delayed, playback_rate_);
740 delay_frames,
741 playback_rate_);
742 740
743 if (CanRead_Locked()) { 741 if (CanRead_Locked()) {
744 task_runner_->PostTask(FROM_HERE, 742 task_runner_->PostTask(FROM_HERE,
745 base::Bind(&AudioRendererImpl::AttemptRead, 743 base::Bind(&AudioRendererImpl::AttemptRead,
746 weak_factory_.GetWeakPtr())); 744 weak_factory_.GetWeakPtr()));
747 } 745 }
748 746
749 if (audio_clock_->front_timestamp() >= ended_timestamp_ && 747 if (audio_clock_->front_timestamp() >= ended_timestamp_ &&
750 !rendered_end_of_stream_) { 748 !rendered_end_of_stream_) {
751 rendered_end_of_stream_ = true; 749 rendered_end_of_stream_ = true;
752 task_runner_->PostTask(FROM_HERE, ended_cb_); 750 task_runner_->PostTask(FROM_HERE, ended_cb_);
753 } 751 }
754 } 752 }
755 753
756 DCHECK_LE(frames_written, requested_frames); 754 DCHECK_LE(frames_written, frames_requested);
757 return frames_written; 755 return frames_written;
758 } 756 }
759 757
760 void AudioRendererImpl::OnRenderError() { 758 void AudioRendererImpl::OnRenderError() {
761 // UMA data tells us this happens ~0.01% of the time. Trigger an error instead 759 // UMA data tells us this happens ~0.01% of the time. Trigger an error instead
762 // of trying to gracefully fall back to a fake sink. It's very likely 760 // of trying to gracefully fall back to a fake sink. It's very likely
763 // OnRenderError() should be removed and the audio stack handle errors without 761 // OnRenderError() should be removed and the audio stack handle errors without
764 // notifying clients. See http://crbug.com/234708 for details. 762 // notifying clients. See http://crbug.com/234708 for details.
765 HistogramRendererEvent(RENDER_ERROR); 763 HistogramRendererEvent(RENDER_ERROR);
766 764
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
831 << buffering_state; 829 << buffering_state;
832 DCHECK_NE(buffering_state_, buffering_state); 830 DCHECK_NE(buffering_state_, buffering_state);
833 lock_.AssertAcquired(); 831 lock_.AssertAcquired();
834 buffering_state_ = buffering_state; 832 buffering_state_ = buffering_state;
835 833
836 task_runner_->PostTask(FROM_HERE, 834 task_runner_->PostTask(FROM_HERE,
837 base::Bind(buffering_state_cb_, buffering_state_)); 835 base::Bind(buffering_state_cb_, buffering_state_));
838 } 836 }
839 837
840 } // namespace media 838 } // namespace media
OLDNEW
« no previous file with comments | « media/renderers/audio_renderer_impl.h ('k') | media/renderers/audio_renderer_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698