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

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

Issue 382633005: Use AudioClock to determine when audio playback has ended. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 5 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 | Annotate | Revision Log
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
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
90 } 90 }
91 91
92 void AudioRendererImpl::StartRendering_Locked() { 92 void AudioRendererImpl::StartRendering_Locked() {
93 DVLOG(1) << __FUNCTION__; 93 DVLOG(1) << __FUNCTION__;
94 DCHECK(task_runner_->BelongsToCurrentThread()); 94 DCHECK(task_runner_->BelongsToCurrentThread());
95 DCHECK_EQ(state_, kPlaying); 95 DCHECK_EQ(state_, kPlaying);
96 DCHECK(!sink_playing_); 96 DCHECK(!sink_playing_);
97 DCHECK_NE(algorithm_->playback_rate(), 0); 97 DCHECK_NE(algorithm_->playback_rate(), 0);
98 lock_.AssertAcquired(); 98 lock_.AssertAcquired();
99 99
100 earliest_end_time_ = now_cb_.Run();
101 sink_playing_ = true; 100 sink_playing_ = true;
102 101
103 base::AutoUnlock auto_unlock(lock_); 102 base::AutoUnlock auto_unlock(lock_);
104 sink_->Play(); 103 sink_->Play();
105 } 104 }
106 105
107 void AudioRendererImpl::StopRendering() { 106 void AudioRendererImpl::StopRendering() {
108 DVLOG(1) << __FUNCTION__; 107 DVLOG(1) << __FUNCTION__;
109 DCHECK(task_runner_->BelongsToCurrentThread()); 108 DCHECK(task_runner_->BelongsToCurrentThread());
110 DCHECK(rendering_); 109 DCHECK(rendering_);
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
172 DCHECK(!flush_cb_.is_null()); 171 DCHECK(!flush_cb_.is_null());
173 172
174 audio_clock_.reset(new AudioClock(audio_parameters_.sample_rate())); 173 audio_clock_.reset(new AudioClock(audio_parameters_.sample_rate()));
175 received_end_of_stream_ = false; 174 received_end_of_stream_ = false;
176 rendered_end_of_stream_ = false; 175 rendered_end_of_stream_ = false;
177 176
178 // Flush() may have been called while underflowed/not fully buffered. 177 // Flush() may have been called while underflowed/not fully buffered.
179 if (buffering_state_ != BUFFERING_HAVE_NOTHING) 178 if (buffering_state_ != BUFFERING_HAVE_NOTHING)
180 SetBufferingState_Locked(BUFFERING_HAVE_NOTHING); 179 SetBufferingState_Locked(BUFFERING_HAVE_NOTHING);
181 180
182 earliest_end_time_ = now_cb_.Run();
183 splicer_->Reset(); 181 splicer_->Reset();
184 if (buffer_converter_) 182 if (buffer_converter_)
185 buffer_converter_->Reset(); 183 buffer_converter_->Reset();
186 algorithm_->FlushBuffers(); 184 algorithm_->FlushBuffers();
187 } 185 }
188 186
189 // Changes in buffering state are always posted. Flush callback must only be 187 // Changes in buffering state are always posted. Flush callback must only be
190 // run after buffering state has been set back to nothing. 188 // run after buffering state has been set back to nothing.
191 task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&flush_cb_)); 189 task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&flush_cb_));
192 } 190 }
(...skipping 381 matching lines...) Expand 10 before | Expand all | Expand 10 after
574 // Mute audio by returning 0 when not playing. 572 // Mute audio by returning 0 when not playing.
575 if (state_ != kPlaying) { 573 if (state_ != kPlaying) {
576 audio_clock_->WroteSilence(requested_frames, delay_frames); 574 audio_clock_->WroteSilence(requested_frames, delay_frames);
577 return 0; 575 return 0;
578 } 576 }
579 577
580 // We use the following conditions to determine end of playback: 578 // We use the following conditions to determine end of playback:
581 // 1) Algorithm can not fill the audio callback buffer 579 // 1) Algorithm can not fill the audio callback buffer
582 // 2) We received an end of stream buffer 580 // 2) We received an end of stream buffer
583 // 3) We haven't already signalled that we've ended 581 // 3) We haven't already signalled that we've ended
584 // 4) Our estimated earliest end time has expired 582 // 4) We've played all known audio data sent to hardware
585 //
586 // TODO(enal): we should replace (4) with a check that the browser has no
587 // more audio data or at least use a delayed callback.
588 // 583 //
589 // We use the following conditions to determine underflow: 584 // We use the following conditions to determine underflow:
590 // 1) Algorithm can not fill the audio callback buffer 585 // 1) Algorithm can not fill the audio callback buffer
591 // 2) We have NOT received an end of stream buffer 586 // 2) We have NOT received an end of stream buffer
592 // 3) We are in the kPlaying state 587 // 3) We are in the kPlaying state
593 // 588 //
594 // Otherwise the buffer has data we can send to the device. 589 // Otherwise the buffer has data we can send to the device.
595 const base::TimeDelta media_timestamp_before_filling = 590 const base::TimeDelta media_timestamp_before_filling =
596 audio_clock_->CurrentMediaTimestamp(); 591 audio_clock_->CurrentMediaTimestamp();
597 if (algorithm_->frames_buffered() > 0) { 592 if (algorithm_->frames_buffered() > 0) {
598 frames_written = algorithm_->FillBuffer(audio_bus, requested_frames); 593 frames_written = algorithm_->FillBuffer(audio_bus, requested_frames);
599 audio_clock_->WroteAudio( 594 audio_clock_->WroteAudio(
600 frames_written, delay_frames, playback_rate, algorithm_->GetTime()); 595 frames_written, delay_frames, playback_rate, algorithm_->GetTime());
601 } 596 }
602 audio_clock_->WroteSilence(requested_frames - frames_written, delay_frames); 597 audio_clock_->WroteSilence(requested_frames - frames_written, delay_frames);
603 598
604 if (frames_written == 0) { 599 if (frames_written == 0) {
605 const base::TimeTicks now = now_cb_.Run();
606
607 if (received_end_of_stream_ && !rendered_end_of_stream_ && 600 if (received_end_of_stream_ && !rendered_end_of_stream_ &&
608 now >= earliest_end_time_) { 601 audio_clock_->CurrentMediaTimestamp() ==
602 audio_clock_->last_endpoint_timestamp()) {
609 rendered_end_of_stream_ = true; 603 rendered_end_of_stream_ = true;
610 ended_cb_.Run(); 604 ended_cb_.Run();
611 } else if (!received_end_of_stream_ && state_ == kPlaying) { 605 } else if (!received_end_of_stream_ && state_ == kPlaying) {
612 if (buffering_state_ != BUFFERING_HAVE_NOTHING) { 606 if (buffering_state_ != BUFFERING_HAVE_NOTHING) {
613 algorithm_->IncreaseQueueCapacity(); 607 algorithm_->IncreaseQueueCapacity();
614 SetBufferingState_Locked(BUFFERING_HAVE_NOTHING); 608 SetBufferingState_Locked(BUFFERING_HAVE_NOTHING);
615 } 609 }
616 } else {
617 // We can't write any data this cycle. For example, we may have
618 // sent all available data to the audio device while not reaching
619 // |earliest_end_time_|.
620 } 610 }
621 } 611 }
622 612
623 if (CanRead_Locked()) { 613 if (CanRead_Locked()) {
624 task_runner_->PostTask(FROM_HERE, 614 task_runner_->PostTask(FROM_HERE,
625 base::Bind(&AudioRendererImpl::AttemptRead, 615 base::Bind(&AudioRendererImpl::AttemptRead,
626 weak_factory_.GetWeakPtr())); 616 weak_factory_.GetWeakPtr()));
627 } 617 }
628 618
629 // We only want to execute |time_cb_| if time has progressed and we haven't 619 // We only want to execute |time_cb_| if time has progressed and we haven't
630 // signaled end of stream yet. 620 // signaled end of stream yet.
631 if (media_timestamp_before_filling != 621 if (media_timestamp_before_filling !=
632 audio_clock_->CurrentMediaTimestamp() && 622 audio_clock_->CurrentMediaTimestamp() &&
633 !rendered_end_of_stream_) { 623 !rendered_end_of_stream_) {
634 time_cb = base::Bind(time_cb_, 624 time_cb = base::Bind(time_cb_,
635 audio_clock_->CurrentMediaTimestamp(), 625 audio_clock_->CurrentMediaTimestamp(),
636 audio_clock_->last_endpoint_timestamp()); 626 audio_clock_->last_endpoint_timestamp());
637 } 627 }
638
639 if (frames_written > 0) {
640 UpdateEarliestEndTime_Locked(
641 frames_written, playback_delay, now_cb_.Run());
642 }
643 } 628 }
644 629
645 if (!time_cb.is_null()) 630 if (!time_cb.is_null())
646 task_runner_->PostTask(FROM_HERE, time_cb); 631 task_runner_->PostTask(FROM_HERE, time_cb);
647 632
648 DCHECK_LE(frames_written, requested_frames); 633 DCHECK_LE(frames_written, requested_frames);
649 return frames_written; 634 return frames_written;
650 } 635 }
651 636
652 void AudioRendererImpl::UpdateEarliestEndTime_Locked(
653 int frames_filled, const base::TimeDelta& playback_delay,
654 const base::TimeTicks& time_now) {
655 DCHECK_GT(frames_filled, 0);
656
657 base::TimeDelta predicted_play_time = base::TimeDelta::FromMicroseconds(
658 static_cast<float>(frames_filled) * base::Time::kMicrosecondsPerSecond /
659 audio_parameters_.sample_rate());
660
661 lock_.AssertAcquired();
662 earliest_end_time_ = std::max(
663 earliest_end_time_, time_now + playback_delay + predicted_play_time);
664 }
665
666 void AudioRendererImpl::OnRenderError() { 637 void AudioRendererImpl::OnRenderError() {
667 // UMA data tells us this happens ~0.01% of the time. Trigger an error instead 638 // UMA data tells us this happens ~0.01% of the time. Trigger an error instead
668 // of trying to gracefully fall back to a fake sink. It's very likely 639 // of trying to gracefully fall back to a fake sink. It's very likely
669 // OnRenderError() should be removed and the audio stack handle errors without 640 // OnRenderError() should be removed and the audio stack handle errors without
670 // notifying clients. See http://crbug.com/234708 for details. 641 // notifying clients. See http://crbug.com/234708 for details.
671 HistogramRendererEvent(RENDER_ERROR); 642 HistogramRendererEvent(RENDER_ERROR);
672 error_cb_.Run(PIPELINE_ERROR_DECODE); 643 error_cb_.Run(PIPELINE_ERROR_DECODE);
673 } 644 }
674 645
675 void AudioRendererImpl::HandleAbortedReadOrDecodeError(bool is_decode_error) { 646 void AudioRendererImpl::HandleAbortedReadOrDecodeError(bool is_decode_error) {
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
729 << buffering_state; 700 << buffering_state;
730 DCHECK_NE(buffering_state_, buffering_state); 701 DCHECK_NE(buffering_state_, buffering_state);
731 lock_.AssertAcquired(); 702 lock_.AssertAcquired();
732 buffering_state_ = buffering_state; 703 buffering_state_ = buffering_state;
733 704
734 task_runner_->PostTask(FROM_HERE, 705 task_runner_->PostTask(FROM_HERE,
735 base::Bind(buffering_state_cb_, buffering_state_)); 706 base::Bind(buffering_state_cb_, buffering_state_));
736 } 707 }
737 708
738 } // namespace media 709 } // namespace media
OLDNEW
« media/filters/audio_renderer_impl.h ('K') | « media/filters/audio_renderer_impl.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698