Commit 05fbf80a authored by scherkus@chromium.org's avatar scherkus@chromium.org

Use AudioClock to determine when audio playback has ended.

The old mechanism of estimating the wall clock time isn't as accurate as
the frame-level information tracked inside AudioClock. For example,
AudioClock properly handles situations where the playback rate changes
over time.

BUG=370634

Review URL: https://codereview.chromium.org/382633005

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@282376 0039d316-1c4b-4281-b951-d872f2087c98
parent baed932c
......@@ -97,7 +97,6 @@ void AudioRendererImpl::StartRendering_Locked() {
DCHECK_NE(algorithm_->playback_rate(), 0);
lock_.AssertAcquired();
earliest_end_time_ = now_cb_.Run();
sink_playing_ = true;
base::AutoUnlock auto_unlock(lock_);
......@@ -179,7 +178,6 @@ void AudioRendererImpl::ResetDecoderDone() {
if (buffering_state_ != BUFFERING_HAVE_NOTHING)
SetBufferingState_Locked(BUFFERING_HAVE_NOTHING);
earliest_end_time_ = now_cb_.Run();
splicer_->Reset();
if (buffer_converter_)
buffer_converter_->Reset();
......@@ -581,10 +579,7 @@ int AudioRendererImpl::Render(AudioBus* audio_bus,
// 1) Algorithm can not fill the audio callback buffer
// 2) We received an end of stream buffer
// 3) We haven't already signalled that we've ended
// 4) Our estimated earliest end time has expired
//
// TODO(enal): we should replace (4) with a check that the browser has no
// more audio data or at least use a delayed callback.
// 4) We've played all known audio data sent to hardware
//
// We use the following conditions to determine underflow:
// 1) Algorithm can not fill the audio callback buffer
......@@ -602,10 +597,9 @@ int AudioRendererImpl::Render(AudioBus* audio_bus,
audio_clock_->WroteSilence(requested_frames - frames_written, delay_frames);
if (frames_written == 0) {
const base::TimeTicks now = now_cb_.Run();
if (received_end_of_stream_ && !rendered_end_of_stream_ &&
now >= earliest_end_time_) {
audio_clock_->CurrentMediaTimestamp() ==
audio_clock_->last_endpoint_timestamp()) {
rendered_end_of_stream_ = true;
ended_cb_.Run();
} else if (!received_end_of_stream_ && state_ == kPlaying) {
......@@ -613,10 +607,6 @@ int AudioRendererImpl::Render(AudioBus* audio_bus,
algorithm_->IncreaseQueueCapacity();
SetBufferingState_Locked(BUFFERING_HAVE_NOTHING);
}
} else {
// We can't write any data this cycle. For example, we may have
// sent all available data to the audio device while not reaching
// |earliest_end_time_|.
}
}
......@@ -635,11 +625,6 @@ int AudioRendererImpl::Render(AudioBus* audio_bus,
audio_clock_->CurrentMediaTimestamp(),
audio_clock_->last_endpoint_timestamp());
}
if (frames_written > 0) {
UpdateEarliestEndTime_Locked(
frames_written, playback_delay, now_cb_.Run());
}
}
if (!time_cb.is_null())
......@@ -649,20 +634,6 @@ int AudioRendererImpl::Render(AudioBus* audio_bus,
return frames_written;
}
void AudioRendererImpl::UpdateEarliestEndTime_Locked(
int frames_filled, const base::TimeDelta& playback_delay,
const base::TimeTicks& time_now) {
DCHECK_GT(frames_filled, 0);
base::TimeDelta predicted_play_time = base::TimeDelta::FromMicroseconds(
static_cast<float>(frames_filled) * base::Time::kMicrosecondsPerSecond /
audio_parameters_.sample_rate());
lock_.AssertAcquired();
earliest_end_time_ = std::max(
earliest_end_time_, time_now + playback_delay + predicted_play_time);
}
void AudioRendererImpl::OnRenderError() {
// UMA data tells us this happens ~0.01% of the time. Trigger an error instead
// of trying to gracefully fall back to a fake sink. It's very likely
......
......@@ -127,11 +127,6 @@ class MEDIA_EXPORT AudioRendererImpl
// DecodedAudioReady().
void HandleAbortedReadOrDecodeError(bool is_decode_error);
// Estimate earliest time when current buffer can stop playing.
void UpdateEarliestEndTime_Locked(int frames_filled,
const base::TimeDelta& playback_delay,
const base::TimeTicks& time_now);
void StartRendering_Locked();
void StopRendering_Locked();
......@@ -257,23 +252,6 @@ class MEDIA_EXPORT AudioRendererImpl
base::TimeDelta start_timestamp_;
// We're supposed to know amount of audio data OS or hardware buffered, but
// that is not always so -- on my Linux box
// AudioBuffersState::hardware_delay_bytes never reaches 0.
//
// As a result we cannot use it to find when stream ends. If we just ignore
// buffered data we will notify host that stream ended before it is actually
// did so, I've seen it done ~140ms too early when playing ~150ms file.
//
// Instead of trying to invent OS-specific solution for each and every OS we
// are supporting, use simple workaround: every time we fill the buffer we
// remember when it should stop playing, and do not assume that buffer is
// empty till that time. Workaround is not bulletproof, as we don't exactly
// know when that particular data would start playing, but it is much better
// than nothing.
base::TimeTicks earliest_end_time_;
size_t total_frames_filled_;
// End variables which must be accessed under |lock_|. ----------------------
// NOTE: Weak pointers must be invalidated before all other member variables.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment