Index: media/filters/audio_renderer_impl.cc |
diff --git a/media/filters/audio_renderer_impl.cc b/media/filters/audio_renderer_impl.cc |
index bb80661b3e852d1e01d24cb353e8f82a2b03c7dc..2b821622a2d4a7da2614241b9f9ae683bb17f047 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())); |
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, |
false, |
@@ -565,27 +565,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); |
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 |
@@ -602,8 +608,15 @@ 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(); |
- frames_written = algorithm_->FillBuffer(audio_bus, requested_frames); |
+ const base::TimeDelta media_timestamp_before_filling = |
+ audio_clock_->CurrentMediaTimestamp(); |
+ if (algorithm_->frames_buffered() > 0) { |
+ 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(); |
@@ -628,55 +641,24 @@ 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; |
+ // We only want to execute |time_cb_| if time has progressed and we haven't |
+ // signaled end of stream yet. |
+ if (media_timestamp_before_filling != |
+ audio_clock_->CurrentMediaTimestamp() && |
+ !rendered_end_of_stream_) { |
+ time_cb = base::Bind(time_cb_, |
+ audio_clock_->CurrentMediaTimestamp(), |
+ audio_clock_->last_endpoint_timestamp()); |
} |
- // 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(); |