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

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

Issue 256163005: Introduce AudioClock to improve playback delay calculations. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: AudioClock Created 6 years, 7 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
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 "media/base/audio_buffer.h" 17 #include "media/base/audio_buffer.h"
18 #include "media/base/audio_buffer_converter.h" 18 #include "media/base/audio_buffer_converter.h"
19 #include "media/base/audio_hardware_config.h" 19 #include "media/base/audio_hardware_config.h"
20 #include "media/base/audio_splicer.h" 20 #include "media/base/audio_splicer.h"
21 #include "media/base/bind_to_current_loop.h" 21 #include "media/base/bind_to_current_loop.h"
22 #include "media/base/demuxer_stream.h" 22 #include "media/base/demuxer_stream.h"
23 #include "media/filters/audio_clock.h"
23 #include "media/filters/decrypting_demuxer_stream.h" 24 #include "media/filters/decrypting_demuxer_stream.h"
24 25
25 namespace media { 26 namespace media {
26 27
27 namespace { 28 namespace {
28 29
29 enum AudioRendererEvent { 30 enum AudioRendererEvent {
30 INITIALIZED, 31 INITIALIZED,
31 RENDER_ERROR, 32 RENDER_ERROR,
32 RENDER_EVENT_MAX = RENDER_ERROR, 33 RENDER_EVENT_MAX = RENDER_ERROR,
(...skipping 17 matching lines...) Expand all
50 audio_buffer_stream_(task_runner, 51 audio_buffer_stream_(task_runner,
51 decoders.Pass(), 52 decoders.Pass(),
52 set_decryptor_ready_cb), 53 set_decryptor_ready_cb),
53 hardware_config_(hardware_config), 54 hardware_config_(hardware_config),
54 now_cb_(base::Bind(&base::TimeTicks::Now)), 55 now_cb_(base::Bind(&base::TimeTicks::Now)),
55 state_(kUninitialized), 56 state_(kUninitialized),
56 sink_playing_(false), 57 sink_playing_(false),
57 pending_read_(false), 58 pending_read_(false),
58 received_end_of_stream_(false), 59 received_end_of_stream_(false),
59 rendered_end_of_stream_(false), 60 rendered_end_of_stream_(false),
60 audio_time_buffered_(kNoTimestamp()),
61 current_time_(kNoTimestamp()),
62 underflow_disabled_(false), 61 underflow_disabled_(false),
63 preroll_aborted_(false), 62 preroll_aborted_(false),
64 weak_factory_(this) { 63 weak_factory_(this) {
65 audio_buffer_stream_.set_splice_observer(base::Bind( 64 audio_buffer_stream_.set_splice_observer(base::Bind(
66 &AudioRendererImpl::OnNewSpliceBuffer, weak_factory_.GetWeakPtr())); 65 &AudioRendererImpl::OnNewSpliceBuffer, weak_factory_.GetWeakPtr()));
67 audio_buffer_stream_.set_config_change_observer(base::Bind( 66 audio_buffer_stream_.set_config_change_observer(base::Bind(
68 &AudioRendererImpl::OnConfigChange, weak_factory_.GetWeakPtr())); 67 &AudioRendererImpl::OnConfigChange, weak_factory_.GetWeakPtr()));
69 } 68 }
70 69
71 AudioRendererImpl::~AudioRendererImpl() { 70 AudioRendererImpl::~AudioRendererImpl() {
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
162 void AudioRendererImpl::ResetDecoderDone() { 161 void AudioRendererImpl::ResetDecoderDone() {
163 DCHECK(task_runner_->BelongsToCurrentThread()); 162 DCHECK(task_runner_->BelongsToCurrentThread());
164 { 163 {
165 base::AutoLock auto_lock(lock_); 164 base::AutoLock auto_lock(lock_);
166 if (state_ == kStopped) 165 if (state_ == kStopped)
167 return; 166 return;
168 167
169 DCHECK_EQ(state_, kPaused); 168 DCHECK_EQ(state_, kPaused);
170 DCHECK(!flush_cb_.is_null()); 169 DCHECK(!flush_cb_.is_null());
171 170
172 audio_time_buffered_ = kNoTimestamp(); 171 audio_clock_.reset(new AudioClock(audio_parameters_.sample_rate()));
DaleCurtis 2014/04/30 20:36:33 Kind of stinks to allocate a whole new object. You
scherkus (not reviewing) 2014/05/02 19:26:05 Considering the low frequency of this operation I
173 current_time_ = kNoTimestamp();
174 received_end_of_stream_ = false; 172 received_end_of_stream_ = false;
175 rendered_end_of_stream_ = false; 173 rendered_end_of_stream_ = false;
176 preroll_aborted_ = false; 174 preroll_aborted_ = false;
177 175
178 earliest_end_time_ = now_cb_.Run(); 176 earliest_end_time_ = now_cb_.Run();
179 splicer_->Reset(); 177 splicer_->Reset();
180 if (buffer_converter_) 178 if (buffer_converter_)
181 buffer_converter_->Reset(); 179 buffer_converter_->Reset();
182 algorithm_->FlushBuffers(); 180 algorithm_->FlushBuffers();
183 } 181 }
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
281 const AudioParameters& hw_params = hardware_config_->GetOutputConfig(); 279 const AudioParameters& hw_params = hardware_config_->GetOutputConfig();
282 audio_parameters_.Reset(hw_params.format(), 280 audio_parameters_.Reset(hw_params.format(),
283 hw_params.channel_layout(), 281 hw_params.channel_layout(),
284 hw_params.channels(), 282 hw_params.channels(),
285 hw_params.input_channels(), 283 hw_params.input_channels(),
286 hw_params.sample_rate(), 284 hw_params.sample_rate(),
287 hw_params.bits_per_sample(), 285 hw_params.bits_per_sample(),
288 hardware_config_->GetHighLatencyBufferSize()); 286 hardware_config_->GetHighLatencyBufferSize());
289 } 287 }
290 288
289 audio_clock_.reset(new AudioClock(audio_parameters_.sample_rate()));
290
291 audio_buffer_stream_.Initialize( 291 audio_buffer_stream_.Initialize(
292 stream, 292 stream,
293 statistics_cb, 293 statistics_cb,
294 base::Bind(&AudioRendererImpl::OnAudioBufferStreamInitialized, 294 base::Bind(&AudioRendererImpl::OnAudioBufferStreamInitialized,
295 weak_factory_.GetWeakPtr())); 295 weak_factory_.GetWeakPtr()));
296 } 296 }
297 297
298 void AudioRendererImpl::OnAudioBufferStreamInitialized(bool success) { 298 void AudioRendererImpl::OnAudioBufferStreamInitialized(bool success) {
299 DCHECK(task_runner_->BelongsToCurrentThread()); 299 DCHECK(task_runner_->BelongsToCurrentThread());
300 300
(...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after
557 bool AudioRendererImpl::IsBeforePrerollTime( 557 bool AudioRendererImpl::IsBeforePrerollTime(
558 const scoped_refptr<AudioBuffer>& buffer) { 558 const scoped_refptr<AudioBuffer>& buffer) {
559 DCHECK_EQ(state_, kPrerolling); 559 DCHECK_EQ(state_, kPrerolling);
560 return buffer && !buffer->end_of_stream() && 560 return buffer && !buffer->end_of_stream() &&
561 (buffer->timestamp() + buffer->duration()) < preroll_timestamp_; 561 (buffer->timestamp() + buffer->duration()) < preroll_timestamp_;
562 } 562 }
563 563
564 int AudioRendererImpl::Render(AudioBus* audio_bus, 564 int AudioRendererImpl::Render(AudioBus* audio_bus,
565 int audio_delay_milliseconds) { 565 int audio_delay_milliseconds) {
566 const int requested_frames = audio_bus->frames(); 566 const int requested_frames = audio_bus->frames();
567 base::TimeDelta current_time = kNoTimestamp();
568 base::TimeDelta max_time = kNoTimestamp();
569 base::TimeDelta playback_delay = base::TimeDelta::FromMilliseconds( 567 base::TimeDelta playback_delay = base::TimeDelta::FromMilliseconds(
570 audio_delay_milliseconds); 568 audio_delay_milliseconds);
571 569 const int delay_frames = static_cast<int>(playback_delay.InSecondsF() *
570 audio_parameters_.sample_rate());
572 int frames_written = 0; 571 int frames_written = 0;
572 base::Closure time_cb;
573 base::Closure underflow_cb; 573 base::Closure underflow_cb;
574 { 574 {
575 base::AutoLock auto_lock(lock_); 575 base::AutoLock auto_lock(lock_);
576 576
577 // Ensure Stop() hasn't destroyed our |algorithm_| on the pipeline thread. 577 // Ensure Stop() hasn't destroyed our |algorithm_| on the pipeline thread.
578 if (!algorithm_) 578 if (!algorithm_) {
579 audio_clock_->WroteSilence(requested_frames, delay_frames);
DaleCurtis 2014/04/30 20:36:33 This should only be true after Stop() has been cal
scherkus (not reviewing) 2014/05/02 19:26:05 Will leave it in for now ... I suspect this functi
579 return 0; 580 return 0;
581 }
580 582
581 float playback_rate = algorithm_->playback_rate(); 583 float playback_rate = algorithm_->playback_rate();
582 if (playback_rate == 0) 584 if (playback_rate == 0) {
585 audio_clock_->WroteSilence(requested_frames, delay_frames);
583 return 0; 586 return 0;
587 }
584 588
585 // Mute audio by returning 0 when not playing. 589 // Mute audio by returning 0 when not playing.
586 if (state_ != kPlaying) 590 if (state_ != kPlaying) {
591 audio_clock_->WroteSilence(requested_frames, delay_frames);
587 return 0; 592 return 0;
593 }
588 594
589 // We use the following conditions to determine end of playback: 595 // We use the following conditions to determine end of playback:
590 // 1) Algorithm can not fill the audio callback buffer 596 // 1) Algorithm can not fill the audio callback buffer
591 // 2) We received an end of stream buffer 597 // 2) We received an end of stream buffer
592 // 3) We haven't already signalled that we've ended 598 // 3) We haven't already signalled that we've ended
593 // 4) Our estimated earliest end time has expired 599 // 4) Our estimated earliest end time has expired
594 // 600 //
595 // TODO(enal): we should replace (4) with a check that the browser has no 601 // TODO(enal): we should replace (4) with a check that the browser has no
596 // more audio data or at least use a delayed callback. 602 // more audio data or at least use a delayed callback.
597 // 603 //
598 // We use the following conditions to determine underflow: 604 // We use the following conditions to determine underflow:
599 // 1) Algorithm can not fill the audio callback buffer 605 // 1) Algorithm can not fill the audio callback buffer
600 // 2) We have NOT received an end of stream buffer 606 // 2) We have NOT received an end of stream buffer
601 // 3) We are in the kPlaying state 607 // 3) We are in the kPlaying state
602 // 608 //
603 // Otherwise the buffer has data we can send to the device. 609 // Otherwise the buffer has data we can send to the device.
604 const base::TimeDelta time_before_filling = algorithm_->GetTime(); 610 const base::TimeDelta media_timestamp_before_filling =
611 audio_clock_->CurrentMediaTimestamp();
605 frames_written = algorithm_->FillBuffer(audio_bus, requested_frames); 612 frames_written = algorithm_->FillBuffer(audio_bus, requested_frames);
613 audio_clock_->WroteAudio(
614 frames_written, delay_frames, playback_rate, algorithm_->GetTime());
615 audio_clock_->WroteSilence(requested_frames - frames_written, delay_frames);
616
606 if (frames_written == 0) { 617 if (frames_written == 0) {
607 const base::TimeTicks now = now_cb_.Run(); 618 const base::TimeTicks now = now_cb_.Run();
608 619
609 if (received_end_of_stream_ && !rendered_end_of_stream_ && 620 if (received_end_of_stream_ && !rendered_end_of_stream_ &&
610 now >= earliest_end_time_) { 621 now >= earliest_end_time_) {
scherkus (not reviewing) 2014/04/30 19:13:58 I know more of this code can get cleaned up (e.g.,
DaleCurtis 2014/04/30 20:36:33 I agree. Is it possible to get rid of earliest_end
611 rendered_end_of_stream_ = true; 622 rendered_end_of_stream_ = true;
612 ended_cb_.Run(); 623 ended_cb_.Run();
613 } else if (!received_end_of_stream_ && state_ == kPlaying && 624 } else if (!received_end_of_stream_ && state_ == kPlaying &&
614 !underflow_disabled_) { 625 !underflow_disabled_) {
615 ChangeState_Locked(kUnderflow); 626 ChangeState_Locked(kUnderflow);
616 underflow_cb = underflow_cb_; 627 underflow_cb = underflow_cb_;
617 } else { 628 } else {
618 // We can't write any data this cycle. For example, we may have 629 // We can't write any data this cycle. For example, we may have
619 // sent all available data to the audio device while not reaching 630 // sent all available data to the audio device while not reaching
620 // |earliest_end_time_|. 631 // |earliest_end_time_|.
621 } 632 }
622 } 633 }
623 634
624 if (CanRead_Locked()) { 635 if (CanRead_Locked()) {
625 task_runner_->PostTask(FROM_HERE, 636 task_runner_->PostTask(FROM_HERE,
DaleCurtis 2014/04/30 20:36:33 Really this should be TryPostTask() since PostTask
626 base::Bind(&AudioRendererImpl::AttemptRead, 637 base::Bind(&AudioRendererImpl::AttemptRead,
627 weak_factory_.GetWeakPtr())); 638 weak_factory_.GetWeakPtr()));
628 } 639 }
629 640
630 // Adjust the delay according to playback rate. 641 // Time can change in one of two ways:
631 base::TimeDelta adjusted_playback_delay = base::TimeDelta::FromMicroseconds( 642 // 1) The time of the audio data at the audio device changed, or
632 ceil(playback_delay.InMicroseconds() * playback_rate)); 643 // 2) The playback delay value has changed
633 644 //
634 // The |audio_time_buffered_| is the ending timestamp of the last frame 645 // We only want to execute |time_cb_| if time has progressed and we haven't
635 // buffered at the audio device. |playback_delay| is the amount of time 646 // signaled end of stream yet.
636 // buffered at the audio device. The current time can be computed by their 647 //
637 // difference. 648 // Why? The current latency of the system results in getting the last call
638 if (audio_time_buffered_ != kNoTimestamp()) { 649 // to FillBuffer() later than we'd like, which delays firing the 'ended'
639 base::TimeDelta previous_time = current_time_; 650 // event, which delays the looping/trigging performance of short sound
640 current_time_ = audio_time_buffered_ - adjusted_playback_delay; 651 // effects.
641 652 //
642 // Time can change in one of two ways: 653 // TODO(scherkus): revisit this and switch back to relying on playback
643 // 1) The time of the audio data at the audio device changed, or 654 // delay after we've revamped our audio IPC subsystem.
scherkus (not reviewing) 2014/04/30 19:13:58 I'm not sure how much of this whole comment block
DaleCurtis 2014/04/30 20:36:33 Agreed.
scherkus (not reviewing) 2014/05/02 19:26:05 Trimmed it down.
644 // 2) The playback delay value has changed 655 if (media_timestamp_before_filling !=
645 // 656 audio_clock_->CurrentMediaTimestamp() &&
646 // We only want to set |current_time| (and thus execute |time_cb_|) if 657 !rendered_end_of_stream_) {
647 // time has progressed and we haven't signaled end of stream yet. 658 time_cb = base::Bind(time_cb_,
648 // 659 audio_clock_->CurrentMediaTimestamp(),
649 // Why? The current latency of the system results in getting the last call 660 audio_clock_->LastEndpointTimestamp());
650 // to FillBuffer() later than we'd like, which delays firing the 'ended'
651 // event, which delays the looping/trigging performance of short sound
652 // effects.
653 //
654 // TODO(scherkus): revisit this and switch back to relying on playback
655 // delay after we've revamped our audio IPC subsystem.
656 if (current_time_ > previous_time && !rendered_end_of_stream_) {
657 current_time = current_time_;
658 }
659 } else if (frames_written > 0) {
660 // Nothing has been buffered yet, so use the first buffer's timestamp.
661 DCHECK(time_before_filling != kNoTimestamp());
662 current_time_ = current_time =
663 time_before_filling - adjusted_playback_delay;
664 } 661 }
665 662
666 // The call to FillBuffer() on |algorithm_| has increased the amount of
667 // buffered audio data. Update the new amount of time buffered.
668 max_time = algorithm_->GetTime();
669 audio_time_buffered_ = max_time;
670
671 if (frames_written > 0) { 663 if (frames_written > 0) {
672 UpdateEarliestEndTime_Locked( 664 UpdateEarliestEndTime_Locked(
673 frames_written, playback_delay, now_cb_.Run()); 665 frames_written, playback_delay, now_cb_.Run());
674 } 666 }
675 } 667 }
676 668
677 if (current_time != kNoTimestamp() && max_time != kNoTimestamp()) 669 if (!time_cb.is_null())
678 time_cb_.Run(current_time, max_time); 670 time_cb.Run();
679 671
680 if (!underflow_cb.is_null()) 672 if (!underflow_cb.is_null())
681 underflow_cb.Run(); 673 underflow_cb.Run();
682 674
683 DCHECK_LE(frames_written, requested_frames); 675 DCHECK_LE(frames_written, requested_frames);
684 return frames_written; 676 return frames_written;
685 } 677 }
686 678
687 void AudioRendererImpl::UpdateEarliestEndTime_Locked( 679 void AudioRendererImpl::UpdateEarliestEndTime_Locked(
688 int frames_filled, const base::TimeDelta& playback_delay, 680 int frames_filled, const base::TimeDelta& playback_delay,
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
763 DCHECK(expecting_config_changes_); 755 DCHECK(expecting_config_changes_);
764 buffer_converter_->ResetTimestampState(); 756 buffer_converter_->ResetTimestampState();
765 // Drain flushed buffers from the converter so the AudioSplicer receives all 757 // Drain flushed buffers from the converter so the AudioSplicer receives all
766 // data ahead of any OnNewSpliceBuffer() calls. Since discontinuities should 758 // data ahead of any OnNewSpliceBuffer() calls. Since discontinuities should
767 // only appear after config changes, AddInput() should never fail here. 759 // only appear after config changes, AddInput() should never fail here.
768 while (buffer_converter_->HasNextBuffer()) 760 while (buffer_converter_->HasNextBuffer())
769 CHECK(splicer_->AddInput(buffer_converter_->GetNextBuffer())); 761 CHECK(splicer_->AddInput(buffer_converter_->GetNextBuffer()));
770 } 762 }
771 763
772 } // namespace media 764 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698