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

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: fix eos 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
« no previous file with comments | « media/filters/audio_renderer_impl.h ('k') | media/filters/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/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()));
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 false, 293 false,
294 statistics_cb, 294 statistics_cb,
295 base::Bind(&AudioRendererImpl::OnAudioBufferStreamInitialized, 295 base::Bind(&AudioRendererImpl::OnAudioBufferStreamInitialized,
296 weak_factory_.GetWeakPtr())); 296 weak_factory_.GetWeakPtr()));
297 } 297 }
298 298
299 void AudioRendererImpl::OnAudioBufferStreamInitialized(bool success) { 299 void AudioRendererImpl::OnAudioBufferStreamInitialized(bool success) {
300 DCHECK(task_runner_->BelongsToCurrentThread()); 300 DCHECK(task_runner_->BelongsToCurrentThread());
(...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after
558 bool AudioRendererImpl::IsBeforePrerollTime( 558 bool AudioRendererImpl::IsBeforePrerollTime(
559 const scoped_refptr<AudioBuffer>& buffer) { 559 const scoped_refptr<AudioBuffer>& buffer) {
560 DCHECK_EQ(state_, kPrerolling); 560 DCHECK_EQ(state_, kPrerolling);
561 return buffer && !buffer->end_of_stream() && 561 return buffer && !buffer->end_of_stream() &&
562 (buffer->timestamp() + buffer->duration()) < preroll_timestamp_; 562 (buffer->timestamp() + buffer->duration()) < preroll_timestamp_;
563 } 563 }
564 564
565 int AudioRendererImpl::Render(AudioBus* audio_bus, 565 int AudioRendererImpl::Render(AudioBus* audio_bus,
566 int audio_delay_milliseconds) { 566 int audio_delay_milliseconds) {
567 const int requested_frames = audio_bus->frames(); 567 const int requested_frames = audio_bus->frames();
568 base::TimeDelta current_time = kNoTimestamp();
569 base::TimeDelta max_time = kNoTimestamp();
570 base::TimeDelta playback_delay = base::TimeDelta::FromMilliseconds( 568 base::TimeDelta playback_delay = base::TimeDelta::FromMilliseconds(
571 audio_delay_milliseconds); 569 audio_delay_milliseconds);
572 570 const int delay_frames = static_cast<int>(playback_delay.InSecondsF() *
571 audio_parameters_.sample_rate());
573 int frames_written = 0; 572 int frames_written = 0;
573 base::Closure time_cb;
574 base::Closure underflow_cb; 574 base::Closure underflow_cb;
575 { 575 {
576 base::AutoLock auto_lock(lock_); 576 base::AutoLock auto_lock(lock_);
577 577
578 // Ensure Stop() hasn't destroyed our |algorithm_| on the pipeline thread. 578 // Ensure Stop() hasn't destroyed our |algorithm_| on the pipeline thread.
579 if (!algorithm_) 579 if (!algorithm_) {
580 audio_clock_->WroteSilence(requested_frames, delay_frames);
580 return 0; 581 return 0;
582 }
581 583
582 float playback_rate = algorithm_->playback_rate(); 584 float playback_rate = algorithm_->playback_rate();
583 if (playback_rate == 0) 585 if (playback_rate == 0) {
586 audio_clock_->WroteSilence(requested_frames, delay_frames);
584 return 0; 587 return 0;
588 }
585 589
586 // Mute audio by returning 0 when not playing. 590 // Mute audio by returning 0 when not playing.
587 if (state_ != kPlaying) 591 if (state_ != kPlaying) {
592 audio_clock_->WroteSilence(requested_frames, delay_frames);
588 return 0; 593 return 0;
594 }
589 595
590 // We use the following conditions to determine end of playback: 596 // We use the following conditions to determine end of playback:
591 // 1) Algorithm can not fill the audio callback buffer 597 // 1) Algorithm can not fill the audio callback buffer
592 // 2) We received an end of stream buffer 598 // 2) We received an end of stream buffer
593 // 3) We haven't already signalled that we've ended 599 // 3) We haven't already signalled that we've ended
594 // 4) Our estimated earliest end time has expired 600 // 4) Our estimated earliest end time has expired
595 // 601 //
596 // TODO(enal): we should replace (4) with a check that the browser has no 602 // TODO(enal): we should replace (4) with a check that the browser has no
597 // more audio data or at least use a delayed callback. 603 // more audio data or at least use a delayed callback.
598 // 604 //
599 // We use the following conditions to determine underflow: 605 // We use the following conditions to determine underflow:
600 // 1) Algorithm can not fill the audio callback buffer 606 // 1) Algorithm can not fill the audio callback buffer
601 // 2) We have NOT received an end of stream buffer 607 // 2) We have NOT received an end of stream buffer
602 // 3) We are in the kPlaying state 608 // 3) We are in the kPlaying state
603 // 609 //
604 // Otherwise the buffer has data we can send to the device. 610 // Otherwise the buffer has data we can send to the device.
605 const base::TimeDelta time_before_filling = algorithm_->GetTime(); 611 const base::TimeDelta media_timestamp_before_filling =
606 frames_written = algorithm_->FillBuffer(audio_bus, requested_frames); 612 audio_clock_->CurrentMediaTimestamp();
613 if (algorithm_->frames_buffered() > 0) {
614 frames_written = algorithm_->FillBuffer(audio_bus, requested_frames);
615 audio_clock_->WroteAudio(
616 frames_written, delay_frames, playback_rate, algorithm_->GetTime());
617 }
618 audio_clock_->WroteSilence(requested_frames - frames_written, delay_frames);
619
607 if (frames_written == 0) { 620 if (frames_written == 0) {
608 const base::TimeTicks now = now_cb_.Run(); 621 const base::TimeTicks now = now_cb_.Run();
609 622
610 if (received_end_of_stream_ && !rendered_end_of_stream_ && 623 if (received_end_of_stream_ && !rendered_end_of_stream_ &&
611 now >= earliest_end_time_) { 624 now >= earliest_end_time_) {
612 rendered_end_of_stream_ = true; 625 rendered_end_of_stream_ = true;
613 ended_cb_.Run(); 626 ended_cb_.Run();
614 } else if (!received_end_of_stream_ && state_ == kPlaying && 627 } else if (!received_end_of_stream_ && state_ == kPlaying &&
615 !underflow_disabled_) { 628 !underflow_disabled_) {
616 ChangeState_Locked(kUnderflow); 629 ChangeState_Locked(kUnderflow);
617 underflow_cb = underflow_cb_; 630 underflow_cb = underflow_cb_;
618 } else { 631 } else {
619 // We can't write any data this cycle. For example, we may have 632 // We can't write any data this cycle. For example, we may have
620 // sent all available data to the audio device while not reaching 633 // sent all available data to the audio device while not reaching
621 // |earliest_end_time_|. 634 // |earliest_end_time_|.
622 } 635 }
623 } 636 }
624 637
625 if (CanRead_Locked()) { 638 if (CanRead_Locked()) {
626 task_runner_->PostTask(FROM_HERE, 639 task_runner_->PostTask(FROM_HERE,
627 base::Bind(&AudioRendererImpl::AttemptRead, 640 base::Bind(&AudioRendererImpl::AttemptRead,
628 weak_factory_.GetWeakPtr())); 641 weak_factory_.GetWeakPtr()));
629 } 642 }
630 643
631 // Adjust the delay according to playback rate. 644 // We only want to execute |time_cb_| if time has progressed and we haven't
632 base::TimeDelta adjusted_playback_delay = base::TimeDelta::FromMicroseconds( 645 // signaled end of stream yet.
633 ceil(playback_delay.InMicroseconds() * playback_rate)); 646 if (media_timestamp_before_filling !=
634 647 audio_clock_->CurrentMediaTimestamp() &&
635 // The |audio_time_buffered_| is the ending timestamp of the last frame 648 !rendered_end_of_stream_) {
636 // buffered at the audio device. |playback_delay| is the amount of time 649 time_cb = base::Bind(time_cb_,
637 // buffered at the audio device. The current time can be computed by their 650 audio_clock_->CurrentMediaTimestamp(),
638 // difference. 651 audio_clock_->last_endpoint_timestamp());
639 if (audio_time_buffered_ != kNoTimestamp()) {
640 base::TimeDelta previous_time = current_time_;
641 current_time_ = audio_time_buffered_ - adjusted_playback_delay;
642
643 // Time can change in one of two ways:
644 // 1) The time of the audio data at the audio device changed, or
645 // 2) The playback delay value has changed
646 //
647 // We only want to set |current_time| (and thus execute |time_cb_|) if
648 // time has progressed and we haven't signaled end of stream yet.
649 //
650 // Why? The current latency of the system results in getting the last call
651 // to FillBuffer() later than we'd like, which delays firing the 'ended'
652 // event, which delays the looping/trigging performance of short sound
653 // effects.
654 //
655 // TODO(scherkus): revisit this and switch back to relying on playback
656 // delay after we've revamped our audio IPC subsystem.
657 if (current_time_ > previous_time && !rendered_end_of_stream_) {
658 current_time = current_time_;
659 }
660 } else if (frames_written > 0) {
661 // Nothing has been buffered yet, so use the first buffer's timestamp.
662 DCHECK(time_before_filling != kNoTimestamp());
663 current_time_ = current_time =
664 time_before_filling - adjusted_playback_delay;
665 } 652 }
666 653
667 // The call to FillBuffer() on |algorithm_| has increased the amount of
668 // buffered audio data. Update the new amount of time buffered.
669 max_time = algorithm_->GetTime();
670 audio_time_buffered_ = max_time;
671
672 if (frames_written > 0) { 654 if (frames_written > 0) {
673 UpdateEarliestEndTime_Locked( 655 UpdateEarliestEndTime_Locked(
674 frames_written, playback_delay, now_cb_.Run()); 656 frames_written, playback_delay, now_cb_.Run());
675 } 657 }
676 } 658 }
677 659
678 if (current_time != kNoTimestamp() && max_time != kNoTimestamp()) 660 if (!time_cb.is_null())
679 time_cb_.Run(current_time, max_time); 661 time_cb.Run();
680 662
681 if (!underflow_cb.is_null()) 663 if (!underflow_cb.is_null())
682 underflow_cb.Run(); 664 underflow_cb.Run();
683 665
684 DCHECK_LE(frames_written, requested_frames); 666 DCHECK_LE(frames_written, requested_frames);
685 return frames_written; 667 return frames_written;
686 } 668 }
687 669
688 void AudioRendererImpl::UpdateEarliestEndTime_Locked( 670 void AudioRendererImpl::UpdateEarliestEndTime_Locked(
689 int frames_filled, const base::TimeDelta& playback_delay, 671 int frames_filled, const base::TimeDelta& playback_delay,
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
764 DCHECK(expecting_config_changes_); 746 DCHECK(expecting_config_changes_);
765 buffer_converter_->ResetTimestampState(); 747 buffer_converter_->ResetTimestampState();
766 // Drain flushed buffers from the converter so the AudioSplicer receives all 748 // Drain flushed buffers from the converter so the AudioSplicer receives all
767 // data ahead of any OnNewSpliceBuffer() calls. Since discontinuities should 749 // data ahead of any OnNewSpliceBuffer() calls. Since discontinuities should
768 // only appear after config changes, AddInput() should never fail here. 750 // only appear after config changes, AddInput() should never fail here.
769 while (buffer_converter_->HasNextBuffer()) 751 while (buffer_converter_->HasNextBuffer())
770 CHECK(splicer_->AddInput(buffer_converter_->GetNextBuffer())); 752 CHECK(splicer_->AddInput(buffer_converter_->GetNextBuffer()));
771 } 753 }
772 754
773 } // namespace media 755 } // namespace media
OLDNEW
« no previous file with comments | « media/filters/audio_renderer_impl.h ('k') | media/filters/audio_renderer_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698