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

Unified Diff: media/filters/audio_renderer_impl.cc

Issue 11275087: Move OnDecoderInitDone() from decoder to pipeline thread. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix unittest. Created 8 years, 1 month 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
« 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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/filters/audio_renderer_impl.cc
diff --git a/media/filters/audio_renderer_impl.cc b/media/filters/audio_renderer_impl.cc
index 2805ed05837293fa6ea1c6f245393f8f8a35bf8f..2181d48599531c8855e30bb4179a6db4bacee550 100644
--- a/media/filters/audio_renderer_impl.cc
+++ b/media/filters/audio_renderer_impl.cc
@@ -13,38 +13,42 @@
#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/logging.h"
+#include "base/message_loop_proxy.h"
#include "media/audio/audio_util.h"
+#include "media/base/bind_to_loop.h"
#include "media/base/demuxer_stream.h"
#include "media/base/media_switches.h"
namespace media {
AudioRendererImpl::AudioRendererImpl(media::AudioRendererSink* sink)
- : state_(kUninitialized),
+ : sink_(sink),
+ state_(kUninitialized),
pending_read_(false),
received_end_of_stream_(false),
rendered_end_of_stream_(false),
audio_time_buffered_(kNoTimestamp()),
current_time_(kNoTimestamp()),
- bytes_per_frame_(0),
- stopped_(false),
- sink_(sink),
underflow_disabled_(false),
- preroll_aborted_(false) {
+ preroll_aborted_(false),
+ actual_frames_per_buffer_(0) {
+ // We're created on the render thread, but this thread checker is for another.
+ pipeline_thread_checker_.DetachFromThread();
}
void AudioRendererImpl::Play(const base::Closure& callback) {
+ DCHECK(pipeline_thread_checker_.CalledOnValidThread());
+
+ float playback_rate = 0;
{
base::AutoLock auto_lock(lock_);
DCHECK_EQ(kPaused, state_);
state_ = kPlaying;
callback.Run();
+ playback_rate = algorithm_->playback_rate();
}
- if (stopped_)
- return;
-
- if (GetPlaybackRate() != 0.0f) {
+ if (playback_rate != 0.0f) {
DoPlay();
} else {
DoPause();
@@ -52,11 +56,18 @@ void AudioRendererImpl::Play(const base::Closure& callback) {
}
void AudioRendererImpl::DoPlay() {
- earliest_end_time_ = base::Time::Now();
+ DCHECK(pipeline_thread_checker_.CalledOnValidThread());
+ DCHECK(sink_);
+ {
+ base::AutoLock auto_lock(lock_);
+ earliest_end_time_ = base::Time::Now();
+ }
sink_->Play();
}
void AudioRendererImpl::Pause(const base::Closure& callback) {
+ DCHECK(pipeline_thread_checker_.CalledOnValidThread());
+
{
base::AutoLock auto_lock(lock_);
DCHECK(state_ == kPlaying || state_ == kUnderflow ||
@@ -69,30 +80,31 @@ void AudioRendererImpl::Pause(const base::Closure& callback) {
base::ResetAndReturn(&pause_cb_).Run();
}
- if (stopped_)
- return;
-
DoPause();
}
void AudioRendererImpl::DoPause() {
+ DCHECK(pipeline_thread_checker_.CalledOnValidThread());
+ DCHECK(sink_);
sink_->Pause(false);
}
void AudioRendererImpl::Flush(const base::Closure& callback) {
+ DCHECK(pipeline_thread_checker_.CalledOnValidThread());
decoder_->Reset(callback);
}
void AudioRendererImpl::Stop(const base::Closure& callback) {
+ DCHECK(pipeline_thread_checker_.CalledOnValidThread());
DCHECK(!callback.is_null());
+ if (sink_) {
+ sink_->Stop();
+ sink_ = NULL;
+ }
+
{
base::AutoLock auto_lock(lock_);
- if (!stopped_) {
- sink_->Stop();
- stopped_ = true;
- }
-
state_ = kStopped;
algorithm_.reset(NULL);
init_cb_.Reset();
@@ -105,30 +117,32 @@ void AudioRendererImpl::Stop(const base::Closure& callback) {
void AudioRendererImpl::Preroll(base::TimeDelta time,
const PipelineStatusCB& cb) {
- base::AutoLock auto_lock(lock_);
- DCHECK_EQ(kPaused, state_);
- DCHECK(!pending_read_) << "Pending read must complete before seeking";
- DCHECK(pause_cb_.is_null());
- DCHECK(preroll_cb_.is_null());
- state_ = kPrerolling;
- preroll_cb_ = cb;
- preroll_timestamp_ = time;
-
- // Throw away everything and schedule our reads.
- audio_time_buffered_ = kNoTimestamp();
- current_time_ = kNoTimestamp();
- received_end_of_stream_ = false;
- rendered_end_of_stream_ = false;
- preroll_aborted_ = false;
-
- // |algorithm_| will request more reads.
- algorithm_->FlushBuffers();
-
- if (stopped_)
- return;
+ DCHECK(pipeline_thread_checker_.CalledOnValidThread());
+ DCHECK(sink_);
+
+ {
+ base::AutoLock auto_lock(lock_);
+ DCHECK_EQ(kPaused, state_);
+ DCHECK(!pending_read_) << "Pending read must complete before seeking";
+ DCHECK(pause_cb_.is_null());
+ DCHECK(preroll_cb_.is_null());
+ state_ = kPrerolling;
+ preroll_cb_ = cb;
+ preroll_timestamp_ = time;
+
+ // Throw away everything and schedule our reads.
+ audio_time_buffered_ = kNoTimestamp();
+ current_time_ = kNoTimestamp();
+ received_end_of_stream_ = false;
+ rendered_end_of_stream_ = false;
+ preroll_aborted_ = false;
+
+ // |algorithm_| will request more reads.
+ algorithm_->FlushBuffers();
+ earliest_end_time_ = base::Time::Now();
+ }
// Pause and flush the stream when we preroll to a new location.
- earliest_end_time_ = base::Time::Now();
sink_->Pause(true);
}
@@ -141,7 +155,7 @@ void AudioRendererImpl::Initialize(const scoped_refptr<DemuxerStream>& stream,
const base::Closure& ended_cb,
const base::Closure& disabled_cb,
const PipelineStatusCB& error_cb) {
- base::AutoLock auto_lock(lock_);
+ DCHECK(pipeline_thread_checker_.CalledOnValidThread());
DCHECK(stream);
DCHECK(!decoders.empty());
DCHECK_EQ(stream->type(), DemuxerStream::AUDIO);
@@ -153,6 +167,7 @@ void AudioRendererImpl::Initialize(const scoped_refptr<DemuxerStream>& stream,
DCHECK(!disabled_cb.is_null());
DCHECK(!error_cb.is_null());
DCHECK_EQ(kUninitialized, state_);
+ DCHECK(sink_);
init_cb_ = init_cb;
statistics_cb_ = statistics_cb;
@@ -169,7 +184,7 @@ void AudioRendererImpl::Initialize(const scoped_refptr<DemuxerStream>& stream,
void AudioRendererImpl::InitializeNextDecoder(
const scoped_refptr<DemuxerStream>& demuxer_stream,
scoped_ptr<AudioDecoderList> decoders) {
- lock_.AssertAcquired();
+ DCHECK(pipeline_thread_checker_.CalledOnValidThread());
DCHECK(!decoders->empty());
scoped_refptr<AudioDecoder> decoder = decoders->front();
@@ -177,13 +192,10 @@ void AudioRendererImpl::InitializeNextDecoder(
DCHECK(decoder);
decoder_ = decoder;
-
- base::AutoUnlock auto_unlock(lock_);
decoder->Initialize(
- demuxer_stream,
- base::Bind(&AudioRendererImpl::OnDecoderInitDone, this,
- demuxer_stream,
- base::Passed(&decoders)),
+ demuxer_stream, BindToLoop(base::MessageLoopProxy::current(), base::Bind(
+ &AudioRendererImpl::OnDecoderInitDone, this, demuxer_stream,
+ base::Passed(&decoders))),
statistics_cb_);
}
@@ -191,10 +203,10 @@ void AudioRendererImpl::OnDecoderInitDone(
const scoped_refptr<DemuxerStream>& demuxer_stream,
scoped_ptr<AudioDecoderList> decoders,
PipelineStatus status) {
- base::AutoLock auto_lock(lock_);
+ DCHECK(pipeline_thread_checker_.CalledOnValidThread());
if (state_ == kStopped) {
- DCHECK(stopped_);
+ DCHECK(!sink_);
return;
}
@@ -215,8 +227,6 @@ void AudioRendererImpl::OnDecoderInitDone(
int channels = ChannelLayoutToChannelCount(channel_layout);
int bits_per_channel = decoder_->bits_per_channel();
int sample_rate = decoder_->samples_per_second();
- // TODO(vrk): Add method to AudioDecoder to compute bytes per frame.
- bytes_per_frame_ = channels * bits_per_channel / 8;
algorithm_.reset(new AudioRendererAlgorithm());
if (!algorithm_->ValidateConfig(channels, sample_rate, bits_per_channel)) {
@@ -267,14 +277,16 @@ void AudioRendererImpl::OnDecoderInitDone(
audio_parameters_ = AudioParameters(
format, channel_layout, sample_rate, bits_per_channel, buffer_size);
+ state_ = kPaused;
+
sink_->Initialize(audio_parameters_, this);
sink_->Start();
- state_ = kPaused;
base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK);
}
void AudioRendererImpl::ResumeAfterUnderflow(bool buffer_more_audio) {
+ DCHECK(pipeline_thread_checker_.CalledOnValidThread());
base::AutoLock auto_lock(lock_);
if (state_ == kUnderflow) {
// The "&& preroll_aborted_" is a hack. If preroll is aborted, then we
@@ -291,8 +303,8 @@ void AudioRendererImpl::ResumeAfterUnderflow(bool buffer_more_audio) {
}
void AudioRendererImpl::SetVolume(float volume) {
- if (stopped_)
- return;
+ DCHECK(pipeline_thread_checker_.CalledOnValidThread());
+ DCHECK(sink_);
sink_->SetVolume(volume);
}
@@ -376,29 +388,25 @@ void AudioRendererImpl::ScheduleRead_Locked() {
}
void AudioRendererImpl::SetPlaybackRate(float playback_rate) {
+ DCHECK(pipeline_thread_checker_.CalledOnValidThread());
DCHECK_LE(0.0f, playback_rate);
+ DCHECK(sink_);
- if (!stopped_) {
- // We have two cases here:
- // Play: GetPlaybackRate() == 0.0 && playback_rate != 0.0
- // Pause: GetPlaybackRate() != 0.0 && playback_rate == 0.0
- if (GetPlaybackRate() == 0.0f && playback_rate != 0.0f) {
- DoPlay();
- } else if (GetPlaybackRate() != 0.0f && playback_rate == 0.0f) {
- // Pause is easy, we can always pause.
- DoPause();
- }
+ // We have two cases here:
+ // Play: current_playback_rate == 0.0 && playback_rate != 0.0
+ // Pause: current_playback_rate != 0.0 && playback_rate == 0.0
+ float current_playback_rate = algorithm_->playback_rate();
+ if (current_playback_rate == 0.0f && playback_rate != 0.0f) {
+ DoPlay();
+ } else if (current_playback_rate != 0.0f && playback_rate == 0.0f) {
+ // Pause is easy, we can always pause.
+ DoPause();
}
base::AutoLock auto_lock(lock_);
algorithm_->SetPlaybackRate(playback_rate);
}
-float AudioRendererImpl::GetPlaybackRate() {
- base::AutoLock auto_lock(lock_);
- return algorithm_->playback_rate();
-}
-
bool AudioRendererImpl::IsBeforePrerollTime(
const scoped_refptr<Buffer>& buffer) {
return (state_ == kPrerolling) && buffer && !buffer->IsEndOfStream() &&
@@ -407,43 +415,27 @@ bool AudioRendererImpl::IsBeforePrerollTime(
int AudioRendererImpl::Render(AudioBus* audio_bus,
int audio_delay_milliseconds) {
- if (stopped_ || GetPlaybackRate() == 0.0f) {
- // Output silence if stopped.
- audio_bus->Zero();
- return 0;
- }
-
- // Adjust the playback delay.
- base::TimeDelta request_delay =
- base::TimeDelta::FromMilliseconds(audio_delay_milliseconds);
-
- // Finally we need to adjust the delay according to playback rate.
- if (GetPlaybackRate() != 1.0f) {
- request_delay = base::TimeDelta::FromMicroseconds(
- static_cast<int64>(ceil(request_delay.InMicroseconds() *
- GetPlaybackRate())));
+ if (actual_frames_per_buffer_ != audio_bus->frames()) {
+ audio_buffer_.reset(
+ new uint8[audio_bus->frames() * audio_parameters_.GetBytesPerFrame()]);
+ actual_frames_per_buffer_ = audio_bus->frames();
}
- int bytes_per_frame = audio_parameters_.GetBytesPerFrame();
-
- const int buf_size = audio_bus->frames() * bytes_per_frame;
- scoped_array<uint8> buf(new uint8[buf_size]);
-
- int frames_filled = FillBuffer(buf.get(), audio_bus->frames(), request_delay);
- int bytes_filled = frames_filled * bytes_per_frame;
- DCHECK_LE(bytes_filled, buf_size);
- UpdateEarliestEndTime(bytes_filled, request_delay, base::Time::Now());
+ int frames_filled = FillBuffer(
+ audio_buffer_.get(), audio_bus->frames(), audio_delay_milliseconds);
+ DCHECK_LE(frames_filled, actual_frames_per_buffer_);
// Deinterleave audio data into the output bus.
audio_bus->FromInterleaved(
- buf.get(), frames_filled, audio_parameters_.bits_per_sample() / 8);
+ audio_buffer_.get(), frames_filled,
+ audio_parameters_.bits_per_sample() / 8);
return frames_filled;
}
uint32 AudioRendererImpl::FillBuffer(uint8* dest,
uint32 requested_frames,
- const base::TimeDelta& playback_delay) {
+ int audio_delay_milliseconds) {
base::TimeDelta current_time = kNoTimestamp();
base::TimeDelta max_time = kNoTimestamp();
@@ -452,6 +444,22 @@ uint32 AudioRendererImpl::FillBuffer(uint8* dest,
{
base::AutoLock auto_lock(lock_);
+ // Ensure Stop() hasn't destroyed our |algorithm_| on the pipeline thread.
+ if (!algorithm_)
+ return 0;
+
+ float playback_rate = algorithm_->playback_rate();
+ if (playback_rate == 0.0f)
+ return 0;
+
+ // Adjust the delay according to playback rate.
+ base::TimeDelta playback_delay =
+ base::TimeDelta::FromMilliseconds(audio_delay_milliseconds);
+ if (playback_rate != 1.0f) {
+ playback_delay = base::TimeDelta::FromMicroseconds(static_cast<int64>(
+ ceil(playback_delay.InMicroseconds() * playback_rate)));
+ }
+
if (state_ == kRebuffering && algorithm_->IsQueueFull())
state_ = kPlaying;
@@ -464,10 +472,10 @@ uint32 AudioRendererImpl::FillBuffer(uint8* dest,
//
// This should get handled by the subclass http://crbug.com/106600
const uint32 kZeroLength = 8192;
- size_t zeros_to_write =
- std::min(kZeroLength, requested_frames * bytes_per_frame_);
+ size_t zeros_to_write = std::min(
+ kZeroLength, requested_frames * audio_parameters_.GetBytesPerFrame());
memset(dest, 0, zeros_to_write);
- return zeros_to_write / bytes_per_frame_;
+ return zeros_to_write / audio_parameters_.GetBytesPerFrame();
}
// We use the following conditions to determine end of playback:
@@ -533,6 +541,9 @@ uint32 AudioRendererImpl::FillBuffer(uint8* dest,
// buffered audio data. Update the new amount of time buffered.
max_time = algorithm_->GetTime();
audio_time_buffered_ = max_time;
+
+ UpdateEarliestEndTime_Locked(
+ frames_written, playback_rate, playback_delay, base::Time::Now());
}
if (current_time != kNoTimestamp() && max_time != kNoTimestamp()) {
@@ -545,28 +556,25 @@ uint32 AudioRendererImpl::FillBuffer(uint8* dest,
return frames_written;
}
-void AudioRendererImpl::UpdateEarliestEndTime(int bytes_filled,
- base::TimeDelta request_delay,
- base::Time time_now) {
- if (bytes_filled != 0) {
- base::TimeDelta predicted_play_time = ConvertToDuration(bytes_filled);
- float playback_rate = GetPlaybackRate();
- if (playback_rate != 1.0f) {
- predicted_play_time = base::TimeDelta::FromMicroseconds(
- static_cast<int64>(ceil(predicted_play_time.InMicroseconds() *
- playback_rate)));
- }
- earliest_end_time_ =
- std::max(earliest_end_time_,
- time_now + request_delay + predicted_play_time);
+void AudioRendererImpl::UpdateEarliestEndTime_Locked(
+ int frames_filled, float playback_rate, base::TimeDelta playback_delay,
+ base::Time time_now) {
+ if (frames_filled <= 0)
+ return;
+
+ base::TimeDelta predicted_play_time = base::TimeDelta::FromMicroseconds(
+ static_cast<float>(frames_filled) * base::Time::kMicrosecondsPerSecond /
+ audio_parameters_.sample_rate());
+
+ if (playback_rate != 1.0f) {
+ predicted_play_time = base::TimeDelta::FromMicroseconds(
+ static_cast<int64>(ceil(predicted_play_time.InMicroseconds() *
+ playback_rate)));
}
-}
-base::TimeDelta AudioRendererImpl::ConvertToDuration(int bytes) {
- int bytes_per_second = audio_parameters_.GetBytesPerSecond();
- CHECK(bytes_per_second);
- return base::TimeDelta::FromMicroseconds(
- base::Time::kMicrosecondsPerSecond * bytes / bytes_per_second);
+ lock_.AssertAcquired();
+ earliest_end_time_ = std::max(
+ earliest_end_time_, time_now + playback_delay + predicted_play_time);
}
void AudioRendererImpl::OnRenderError() {
« 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