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

Unified 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, 8 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 side-by-side diff with in-line comments
Download patch
Index: media/filters/audio_renderer_impl.cc
diff --git a/media/filters/audio_renderer_impl.cc b/media/filters/audio_renderer_impl.cc
index 4f71d3d81cc9d636e9d28b469ef75ba05d0f746e..b73cb2ac473d05ddec28716d498678fbfad95d07 100644
--- a/media/filters/audio_renderer_impl.cc
+++ b/media/filters/audio_renderer_impl.cc
@@ -20,6 +20,7 @@
#include "media/base/audio_splicer.h"
#include "media/base/bind_to_current_loop.h"
#include "media/base/demuxer_stream.h"
+#include "media/filters/audio_clock.h"
#include "media/filters/decrypting_demuxer_stream.h"
namespace media {
@@ -57,8 +58,6 @@ AudioRendererImpl::AudioRendererImpl(
pending_read_(false),
received_end_of_stream_(false),
rendered_end_of_stream_(false),
- audio_time_buffered_(kNoTimestamp()),
- current_time_(kNoTimestamp()),
underflow_disabled_(false),
preroll_aborted_(false),
weak_factory_(this) {
@@ -169,8 +168,7 @@ void AudioRendererImpl::ResetDecoderDone() {
DCHECK_EQ(state_, kPaused);
DCHECK(!flush_cb_.is_null());
- audio_time_buffered_ = kNoTimestamp();
- current_time_ = kNoTimestamp();
+ 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
received_end_of_stream_ = false;
rendered_end_of_stream_ = false;
preroll_aborted_ = false;
@@ -288,6 +286,8 @@ void AudioRendererImpl::Initialize(DemuxerStream* stream,
hardware_config_->GetHighLatencyBufferSize());
}
+ audio_clock_.reset(new AudioClock(audio_parameters_.sample_rate()));
+
audio_buffer_stream_.Initialize(
stream,
statistics_cb,
@@ -564,27 +564,33 @@ bool AudioRendererImpl::IsBeforePrerollTime(
int AudioRendererImpl::Render(AudioBus* audio_bus,
int audio_delay_milliseconds) {
const int requested_frames = audio_bus->frames();
- base::TimeDelta current_time = kNoTimestamp();
- base::TimeDelta max_time = kNoTimestamp();
base::TimeDelta playback_delay = base::TimeDelta::FromMilliseconds(
audio_delay_milliseconds);
-
+ const int delay_frames = static_cast<int>(playback_delay.InSecondsF() *
+ audio_parameters_.sample_rate());
int frames_written = 0;
+ base::Closure time_cb;
base::Closure underflow_cb;
{
base::AutoLock auto_lock(lock_);
// Ensure Stop() hasn't destroyed our |algorithm_| on the pipeline thread.
- if (!algorithm_)
+ if (!algorithm_) {
+ 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
return 0;
+ }
float playback_rate = algorithm_->playback_rate();
- if (playback_rate == 0)
+ if (playback_rate == 0) {
+ audio_clock_->WroteSilence(requested_frames, delay_frames);
return 0;
+ }
// Mute audio by returning 0 when not playing.
- if (state_ != kPlaying)
+ if (state_ != kPlaying) {
+ audio_clock_->WroteSilence(requested_frames, delay_frames);
return 0;
+ }
// We use the following conditions to determine end of playback:
// 1) Algorithm can not fill the audio callback buffer
@@ -601,8 +607,13 @@ int AudioRendererImpl::Render(AudioBus* audio_bus,
// 3) We are in the kPlaying state
//
// Otherwise the buffer has data we can send to the device.
- const base::TimeDelta time_before_filling = algorithm_->GetTime();
+ const base::TimeDelta media_timestamp_before_filling =
+ audio_clock_->CurrentMediaTimestamp();
frames_written = algorithm_->FillBuffer(audio_bus, requested_frames);
+ audio_clock_->WroteAudio(
+ frames_written, delay_frames, playback_rate, algorithm_->GetTime());
+ audio_clock_->WroteSilence(requested_frames - frames_written, delay_frames);
+
if (frames_written == 0) {
const base::TimeTicks now = now_cb_.Run();
@@ -627,55 +638,36 @@ int AudioRendererImpl::Render(AudioBus* audio_bus,
weak_factory_.GetWeakPtr()));
}
- // Adjust the delay according to playback rate.
- base::TimeDelta adjusted_playback_delay = base::TimeDelta::FromMicroseconds(
- ceil(playback_delay.InMicroseconds() * playback_rate));
-
- // The |audio_time_buffered_| is the ending timestamp of the last frame
- // buffered at the audio device. |playback_delay| is the amount of time
- // buffered at the audio device. The current time can be computed by their
- // difference.
- if (audio_time_buffered_ != kNoTimestamp()) {
- base::TimeDelta previous_time = current_time_;
- current_time_ = audio_time_buffered_ - adjusted_playback_delay;
-
- // Time can change in one of two ways:
- // 1) The time of the audio data at the audio device changed, or
- // 2) The playback delay value has changed
- //
- // We only want to set |current_time| (and thus execute |time_cb_|) if
- // time has progressed and we haven't signaled end of stream yet.
- //
- // Why? The current latency of the system results in getting the last call
- // to FillBuffer() later than we'd like, which delays firing the 'ended'
- // event, which delays the looping/trigging performance of short sound
- // effects.
- //
- // TODO(scherkus): revisit this and switch back to relying on playback
- // delay after we've revamped our audio IPC subsystem.
- if (current_time_ > previous_time && !rendered_end_of_stream_) {
- current_time = current_time_;
- }
- } else if (frames_written > 0) {
- // Nothing has been buffered yet, so use the first buffer's timestamp.
- DCHECK(time_before_filling != kNoTimestamp());
- current_time_ = current_time =
- time_before_filling - adjusted_playback_delay;
+ // Time can change in one of two ways:
+ // 1) The time of the audio data at the audio device changed, or
+ // 2) The playback delay value has changed
+ //
+ // We only want to execute |time_cb_| if time has progressed and we haven't
+ // signaled end of stream yet.
+ //
+ // Why? The current latency of the system results in getting the last call
+ // to FillBuffer() later than we'd like, which delays firing the 'ended'
+ // event, which delays the looping/trigging performance of short sound
+ // effects.
+ //
+ // TODO(scherkus): revisit this and switch back to relying on playback
+ // 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.
+ if (media_timestamp_before_filling !=
+ audio_clock_->CurrentMediaTimestamp() &&
+ !rendered_end_of_stream_) {
+ time_cb = base::Bind(time_cb_,
+ audio_clock_->CurrentMediaTimestamp(),
+ audio_clock_->LastEndpointTimestamp());
}
- // The call to FillBuffer() on |algorithm_| has increased the amount of
- // buffered audio data. Update the new amount of time buffered.
- max_time = algorithm_->GetTime();
- audio_time_buffered_ = max_time;
-
if (frames_written > 0) {
UpdateEarliestEndTime_Locked(
frames_written, playback_delay, now_cb_.Run());
}
}
- if (current_time != kNoTimestamp() && max_time != kNoTimestamp())
- time_cb_.Run(current_time, max_time);
+ if (!time_cb.is_null())
+ time_cb.Run();
if (!underflow_cb.is_null())
underflow_cb.Run();

Powered by Google App Engine
This is Rietveld 408576698