| Index: content/renderer/media/audio_renderer_impl.cc
|
| ===================================================================
|
| --- content/renderer/media/audio_renderer_impl.cc (revision 121128)
|
| +++ content/renderer/media/audio_renderer_impl.cc (working copy)
|
| @@ -16,6 +16,8 @@
|
| #include "media/audio/audio_util.h"
|
| #include "media/base/filter_host.h"
|
|
|
| +using base::subtle::AtomicWord;
|
| +
|
| // We define GetBufferSizeForSampleRate() instead of using
|
| // GetAudioHardwareBufferSize() in audio_util because we're using
|
| // the AUDIO_PCM_LINEAR flag, instead of AUDIO_PCM_LOW_LATENCY,
|
| @@ -41,7 +43,10 @@
|
| bytes_per_second_(0),
|
| stopped_(false),
|
| sink_(sink),
|
| - is_initialized_(false) {
|
| + is_initialized_(false),
|
| + ended_event_scheduled_(false),
|
| + io_message_loop_proxy_(ChildProcess::current()->io_message_loop_proxy()),
|
| + stream_id_(0) {
|
| }
|
|
|
| AudioRendererImpl::~AudioRendererImpl() {
|
| @@ -66,9 +71,9 @@
|
| static_cast<int64>(ceil(predicted_play_time.InMicroseconds() *
|
| playback_rate)));
|
| }
|
| - earliest_end_time_ =
|
| + set_earliest_end_time(
|
| std::max(earliest_end_time_,
|
| - time_now + request_delay + predicted_play_time);
|
| + time_now + request_delay + predicted_play_time));
|
| }
|
| }
|
|
|
| @@ -173,18 +178,22 @@
|
| }
|
|
|
| void AudioRendererImpl::DoPlay() {
|
| - earliest_end_time_ = base::Time::Now();
|
| + set_earliest_end_time(base::Time::Now());
|
| + ended_event_scheduled_ = false;
|
| DCHECK(sink_.get());
|
| sink_->Play();
|
| }
|
|
|
| void AudioRendererImpl::DoPause() {
|
| + ++stream_id_;
|
| DCHECK(sink_.get());
|
| sink_->Pause(false);
|
| }
|
|
|
| void AudioRendererImpl::DoSeek() {
|
| - earliest_end_time_ = base::Time::Now();
|
| + set_earliest_end_time(base::Time::Now());
|
| + ended_event_scheduled_ = false;
|
| + ++stream_id_;
|
|
|
| // Pause and flush the stream when we seek to a new location.
|
| DCHECK(sink_.get());
|
| @@ -197,7 +206,7 @@
|
| if (stopped_ || GetPlaybackRate() == 0.0f) {
|
| // Output silence if stopped.
|
| for (size_t i = 0; i < audio_data.size(); ++i)
|
| - memset(audio_data[i], 0, sizeof(float) * number_of_frames);
|
| + memset(audio_data[i], 0, sizeof(audio_data[i][0]) * number_of_frames);
|
| return 0;
|
| }
|
|
|
| @@ -239,7 +248,7 @@
|
| int frames_to_zero = number_of_frames - filled_frames;
|
| memset(audio_data[channel_index] + filled_frames,
|
| 0,
|
| - sizeof(float) * frames_to_zero);
|
| + sizeof(audio_data[channel_index][0]) * frames_to_zero);
|
| }
|
| }
|
| return filled_frames;
|
| @@ -249,8 +258,28 @@
|
| host()->DisableAudioRenderer();
|
| }
|
|
|
| +int64 AudioRendererImpl::OnRenderEndOfStreamDelay() {
|
| + return (earliest_end_time() - base::Time::Now()).InMilliseconds();
|
| +}
|
| +
|
| void AudioRendererImpl::OnRenderEndOfStream() {
|
| - // TODO(enal): schedule callback instead of polling.
|
| - if (base::Time::Now() >= earliest_end_time_)
|
| + if (!ended_event_scheduled_) {
|
| + ended_event_scheduled_ = true;
|
| + int64 delay_ms = OnRenderEndOfStreamDelay();
|
| + if (delay_ms <= 0) {
|
| + DoSignalEndOfStream(stream_id_);
|
| + } else {
|
| + io_message_loop_proxy_->PostDelayedTask(
|
| + FROM_HERE,
|
| + base::Bind(&AudioRendererImpl::DoSignalEndOfStream, this, stream_id_),
|
| + delay_ms);
|
| + }
|
| + }
|
| +}
|
| +
|
| +void AudioRendererImpl::DoSignalEndOfStream(AtomicWord stream_id) {
|
| + // There is no way to cancel delayed task if we paused or seeked after task
|
| + // was scheduled, use stream id to catch such case.
|
| + if (stream_id == stream_id_)
|
| SignalEndOfStream();
|
| }
|
|
|