Commit ff625610 authored by scherkus@chromium.org's avatar scherkus@chromium.org

Move AudioRenderer out of Filter heirarchy.

BUG=108341
TEST=none


Review URL: https://chromiumcodereview.appspot.com/10753021

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@147619 0039d316-1c4b-4281-b951-d872f2087c98
parent 35daebe0
...@@ -16,37 +16,78 @@ namespace media { ...@@ -16,37 +16,78 @@ namespace media {
class AudioDecoder; class AudioDecoder;
class MEDIA_EXPORT AudioRenderer : public Filter { class MEDIA_EXPORT AudioRenderer
: public base::RefCountedThreadSafe<AudioRenderer> {
public: public:
// Used to update the pipeline's clock time. The first parameter is the // First parameter is the current time that has been rendered.
// current time, and the second parameter is the time that the clock must not // Second parameter is the maximum time value that the clock cannot exceed.
// exceed.
typedef base::Callback<void(base::TimeDelta, base::TimeDelta)> TimeCB; typedef base::Callback<void(base::TimeDelta, base::TimeDelta)> TimeCB;
// Initialize a AudioRenderer with the given AudioDecoder, executing the // Initialize a AudioRenderer with the given AudioDecoder, executing the
// |init_cb| upon completion. |underflow_cb| is called when the // |init_cb| upon completion.
// renderer runs out of data to pass to the audio card during playback. //
// If the |underflow_cb| is called ResumeAfterUnderflow() must be called // |underflow_cb| is executed when the renderer runs out of data to pass to
// the audio card during playback. ResumeAfterUnderflow() must be called
// to resume playback. Pause(), Seek(), or Stop() cancels the underflow // to resume playback. Pause(), Seek(), or Stop() cancels the underflow
// condition. // condition.
//
// |time_cb| is executed whenever time has advanced by way of audio rendering.
//
// |ended_cb| is executed when audio rendering has reached the end of stream.
//
// |disabled_cb| is executed when audio rendering has been disabled due to
// external factors (i.e., device was removed). |time_cb| will no longer be
// executed.
//
// |error_cb| is executed if an error was encountered.
virtual void Initialize(const scoped_refptr<AudioDecoder>& decoder, virtual void Initialize(const scoped_refptr<AudioDecoder>& decoder,
const PipelineStatusCB& init_cb, const PipelineStatusCB& init_cb,
const base::Closure& underflow_cb, const base::Closure& underflow_cb,
const TimeCB& time_cb) = 0; const TimeCB& time_cb,
const base::Closure& ended_cb,
const base::Closure& disabled_cb,
const PipelineStatusCB& error_cb) = 0;
// Returns true if this filter has received and processed an end-of-stream // Start audio decoding and rendering at the current playback rate, executing
// buffer. // |callback| when playback is underway.
virtual void Play(const base::Closure& callback) = 0;
// Temporarily suspend decoding and rendering audio, executing |callback| when
// playback has been suspended.
virtual void Pause(const base::Closure& callback) = 0;
// Discard any audio data, executing |callback| when completed.
virtual void Flush(const base::Closure& callback) = 0;
// Start prerolling audio data for samples starting at |time|, executing
// |callback| when completed.
//
// Only valid to call after a successful Initialize() or Flush().
//
// TODO(scherkus): rename this to Preroll().
virtual void Seek(base::TimeDelta time, const PipelineStatusCB& callback) = 0;
// Stop all operations in preparation for being deleted, executing |callback|
// when complete.
virtual void Stop(const base::Closure& callback) = 0;
// Updates the current playback rate.
virtual void SetPlaybackRate(float playback_rate) = 0;
// Returns true if all audio data has been played back by the audio device.
virtual bool HasEnded() = 0; virtual bool HasEnded() = 0;
// Sets the output volume. // Sets the output volume.
virtual void SetVolume(float volume) = 0; virtual void SetVolume(float volume) = 0;
// Resumes playback after underflow occurs. // Resumes playback after underflow occurs.
//
// |buffer_more_audio| is set to true if you want to increase the size of the // |buffer_more_audio| is set to true if you want to increase the size of the
// decoded audio buffer. // decoded audio buffer.
virtual void ResumeAfterUnderflow(bool buffer_more_audio) = 0; virtual void ResumeAfterUnderflow(bool buffer_more_audio) = 0;
protected: protected:
friend class base::RefCountedThreadSafe<AudioRenderer>;
virtual ~AudioRenderer() {} virtual ~AudioRenderer() {}
}; };
......
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/base/callback_util.h"
#include "base/bind.h"
#include "base/synchronization/lock.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop.h"
#include "base/message_loop_proxy.h"
namespace media {
// Executes the given closure if and only if the closure returned by
// GetClosure() has been executed exactly |count| times.
//
// |done_cb| will be executed on the same thread that created the CountingCB.
class CountingCB : public base::RefCountedThreadSafe<CountingCB> {
public:
CountingCB(int count, const base::Closure& done_cb)
: message_loop_(base::MessageLoopProxy::current()),
count_(count),
done_cb_(done_cb) {
}
// Returns a closure bound to this object.
base::Closure GetClosure() {
return base::Bind(&CountingCB::OnCallback, this);
}
protected:
friend class base::RefCountedThreadSafe<CountingCB>;
virtual ~CountingCB() {}
private:
void OnCallback() {
{
base::AutoLock l(lock_);
count_--;
DCHECK_GE(count_, 0) << "CountingCB executed too many times";
if (count_ != 0)
return;
}
if (!message_loop_->BelongsToCurrentThread()) {
message_loop_->PostTask(FROM_HERE, done_cb_);
return;
}
done_cb_.Run();
}
scoped_refptr<base::MessageLoopProxy> message_loop_;
base::Lock lock_;
int count_;
base::Closure done_cb_;
DISALLOW_COPY_AND_ASSIGN(CountingCB);
};
static void OnSeriesCallback(
scoped_refptr<base::MessageLoopProxy> message_loop,
scoped_ptr<std::queue<ClosureFunc> > closures,
const base::Closure& done_cb) {
if (!message_loop->BelongsToCurrentThread()) {
message_loop->PostTask(FROM_HERE, base::Bind(
&OnSeriesCallback, message_loop, base::Passed(&closures), done_cb));
return;
}
if (closures->empty()) {
done_cb.Run();
return;
}
ClosureFunc cb = closures->front();
closures->pop();
cb.Run(base::Bind(
&OnSeriesCallback, message_loop, base::Passed(&closures), done_cb));
}
void RunInSeries(scoped_ptr<std::queue<ClosureFunc> > closures,
const base::Closure& done_cb) {
OnSeriesCallback(base::MessageLoopProxy::current(),
closures.Pass(), done_cb);
}
static void OnStatusCallback(
scoped_refptr<base::MessageLoopProxy> message_loop,
scoped_ptr<std::queue<PipelineStatusCBFunc> > status_cbs,
const PipelineStatusCB& done_cb,
PipelineStatus last_status) {
if (!message_loop->BelongsToCurrentThread()) {
message_loop->PostTask(FROM_HERE, base::Bind(
&OnStatusCallback, message_loop, base::Passed(&status_cbs), done_cb,
last_status));
return;
}
if (status_cbs->empty() || last_status != PIPELINE_OK) {
done_cb.Run(last_status);
return;
}
PipelineStatusCBFunc status_cb = status_cbs->front();
status_cbs->pop();
status_cb.Run(base::Bind(
&OnStatusCallback, message_loop, base::Passed(&status_cbs), done_cb));
}
void RunInSeriesWithStatus(
scoped_ptr<std::queue<PipelineStatusCBFunc> > status_cbs,
const PipelineStatusCB& done_cb) {
OnStatusCallback(base::MessageLoopProxy::current(),
status_cbs.Pass(), done_cb, PIPELINE_OK);
}
void RunInParallel(scoped_ptr<std::queue<ClosureFunc> > closures,
const base::Closure& done_cb) {
if (closures->empty()) {
done_cb.Run();
return;
}
scoped_refptr<CountingCB> counting_cb =
new CountingCB(closures->size(), done_cb);
while (!closures->empty()) {
closures->front().Run(counting_cb->GetClosure());
closures->pop();
}
}
} // namespace media
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MEDIA_BASE_CALLBACK_UTIL_H_
#define MEDIA_BASE_CALLBACK_UTIL_H_
#include <queue>
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "media/base/pipeline_status.h"
namespace media {
typedef base::Callback<void(const base::Closure&)> ClosureFunc;
typedef base::Callback<void(const PipelineStatusCB&)> PipelineStatusCBFunc;
// Executes the closures in FIFO order, executing |done_cb| when the last
// closure has completed running.
//
// All closures (including |done_cb|) are executed on same thread as the
// calling thread.
void RunInSeries(scoped_ptr<std::queue<ClosureFunc> > closures,
const base::Closure& done_cb);
// Executes the closures in FIFO order, executing |done_cb| when the last
// closure has completed running, reporting the final status code.
//
// Closures will stop being executed if a previous closure in the series
// returned an error status and |done_cb| will be executed prematurely.
//
// All closures (including |done_cb|) are executed on same thread as the
// calling thread.
void RunInSeriesWithStatus(
scoped_ptr<std::queue<PipelineStatusCBFunc> > status_cbs,
const PipelineStatusCB& done_cb);
// Executes the closures in parallel, executing |done_cb| when all closures have
// completed running.
//
// No attempt is made to parallelize execution of the closures. In other words,
// this method will run all closures in FIFO order if said closures execute
// synchronously on the same call stack.
//
// All closures (including |done_cb|) are executed on same thread as the
// calling thread.
void RunInParallel(scoped_ptr<std::queue<ClosureFunc> > closures,
const base::Closure& done_cb);
} // namespace media
#endif // MEDIA_BASE_CALLBACK_UTIL_H_
...@@ -25,7 +25,6 @@ class CompositeFilter::FilterHostImpl : public FilterHost { ...@@ -25,7 +25,6 @@ class CompositeFilter::FilterHostImpl : public FilterHost {
virtual base::TimeDelta GetDuration() const OVERRIDE; virtual base::TimeDelta GetDuration() const OVERRIDE;
virtual void SetNaturalVideoSize(const gfx::Size& size) OVERRIDE; virtual void SetNaturalVideoSize(const gfx::Size& size) OVERRIDE;
virtual void NotifyEnded() OVERRIDE; virtual void NotifyEnded() OVERRIDE;
virtual void DisableAudioRenderer() OVERRIDE;
private: private:
CompositeFilter* parent_; CompositeFilter* parent_;
...@@ -469,8 +468,4 @@ void CompositeFilter::FilterHostImpl::NotifyEnded() { ...@@ -469,8 +468,4 @@ void CompositeFilter::FilterHostImpl::NotifyEnded() {
host_->NotifyEnded(); host_->NotifyEnded();
} }
void CompositeFilter::FilterHostImpl::DisableAudioRenderer() {
host_->DisableAudioRenderer();
}
} // namespace media } // namespace media
...@@ -43,10 +43,6 @@ class MEDIA_EXPORT FilterHost { ...@@ -43,10 +43,6 @@ class MEDIA_EXPORT FilterHost {
// endpoints such as renderers. // endpoints such as renderers.
virtual void NotifyEnded() = 0; virtual void NotifyEnded() = 0;
// Disable audio renderer by calling OnAudioRendererDisabled() on all
// filters.
virtual void DisableAudioRenderer() = 0;
protected: protected:
virtual ~FilterHost() {} virtual ~FilterHost() {}
}; };
......
...@@ -85,29 +85,6 @@ scoped_ptr<FilterCollection> MockFilterCollection::Create() { ...@@ -85,29 +85,6 @@ scoped_ptr<FilterCollection> MockFilterCollection::Create() {
return collection.Pass(); return collection.Pass();
} }
void RunPipelineStatusCB(const PipelineStatusCB& status_cb) {
status_cb.Run(PIPELINE_OK);
}
void RunPipelineStatusCB2(::testing::Unused,
const PipelineStatusCB& status_cb) {
status_cb.Run(PIPELINE_OK);
}
void RunPipelineStatusCB3(::testing::Unused, const PipelineStatusCB& status_cb,
::testing::Unused) {
status_cb.Run(PIPELINE_OK);
}
void RunPipelineStatusCB4(::testing::Unused, const PipelineStatusCB& status_cb,
::testing::Unused, ::testing::Unused) {
status_cb.Run(PIPELINE_OK);
}
void RunClosure(const base::Closure& closure) {
closure.Run();
}
MockFilter::MockFilter() : host_(NULL) {} MockFilter::MockFilter() : host_(NULL) {}
MockFilter::~MockFilter() {} MockFilter::~MockFilter() {}
......
...@@ -199,23 +199,22 @@ class MockAudioRenderer : public AudioRenderer { ...@@ -199,23 +199,22 @@ class MockAudioRenderer : public AudioRenderer {
public: public:
MockAudioRenderer(); MockAudioRenderer();
// Filter implementation. // AudioRenderer implementation.
MOCK_METHOD1(SetHost, void(FilterHost* host)); MOCK_METHOD7(Initialize, void(const scoped_refptr<AudioDecoder>& decoder,
const PipelineStatusCB& init_cb,
const base::Closure& underflow_cb,
const TimeCB& time_cb,
const base::Closure& ended_cb,
const base::Closure& disabled_cb,
const PipelineStatusCB& error_cb));
MOCK_METHOD1(Play, void(const base::Closure& callback)); MOCK_METHOD1(Play, void(const base::Closure& callback));
MOCK_METHOD1(Pause, void(const base::Closure& callback)); MOCK_METHOD1(Pause, void(const base::Closure& callback));
MOCK_METHOD1(Flush, void(const base::Closure& callback)); MOCK_METHOD1(Flush, void(const base::Closure& callback));
MOCK_METHOD1(Stop, void(const base::Closure& callback)); MOCK_METHOD1(Stop, void(const base::Closure& callback));
MOCK_METHOD1(SetPlaybackRate, void(float playback_rate)); MOCK_METHOD1(SetPlaybackRate, void(float playback_rate));
MOCK_METHOD2(Seek, void(base::TimeDelta time, const PipelineStatusCB& cb)); MOCK_METHOD2(Seek, void(base::TimeDelta time, const PipelineStatusCB& cb));
// AudioRenderer implementation.
MOCK_METHOD4(Initialize, void(const scoped_refptr<AudioDecoder>& decoder,
const PipelineStatusCB& init_cb,
const base::Closure& underflow_cb,
const TimeCB& time_cb));
MOCK_METHOD0(HasEnded, bool()); MOCK_METHOD0(HasEnded, bool());
MOCK_METHOD1(SetVolume, void(float volume)); MOCK_METHOD1(SetVolume, void(float volume));
MOCK_METHOD1(ResumeAfterUnderflow, void(bool buffer_more_audio)); MOCK_METHOD1(ResumeAfterUnderflow, void(bool buffer_more_audio));
protected: protected:
...@@ -310,19 +309,6 @@ class MockFilterCollection { ...@@ -310,19 +309,6 @@ class MockFilterCollection {
DISALLOW_COPY_AND_ASSIGN(MockFilterCollection); DISALLOW_COPY_AND_ASSIGN(MockFilterCollection);
}; };
// Helper gmock functions that immediately executes and destroys the
// Closure on behalf of the provided filter. Can be used when mocking
// the Initialize() and Seek() methods.
void RunPipelineStatusCB(const PipelineStatusCB& status_cb);
void RunPipelineStatusCB2(::testing::Unused, const PipelineStatusCB& status_cb);
void RunPipelineStatusCB3(::testing::Unused, const PipelineStatusCB& status_cb,
::testing::Unused);
void RunPipelineStatusCB4(::testing::Unused, const PipelineStatusCB& status_cb,
::testing::Unused, ::testing::Unused);
// Helper gmock function that immediately executes the Closure on behalf of the
// provided filter. Can be used when mocking the Stop() method.
void RunClosure(const base::Closure& closure);
// Helper gmock action that calls SetError() on behalf of the provided filter. // Helper gmock action that calls SetError() on behalf of the provided filter.
ACTION_P2(SetError, filter, error) { ACTION_P2(SetError, filter, error) {
filter->host()->SetError(error); filter->host()->SetError(error);
...@@ -334,6 +320,10 @@ ACTION_P2(SetDuration, filter, duration) { ...@@ -334,6 +320,10 @@ ACTION_P2(SetDuration, filter, duration) {
filter->host()->SetDuration(duration); filter->host()->SetDuration(duration);
} }
ACTION(RunClosure) {
arg0.Run();
}
// Helper mock statistics callback. // Helper mock statistics callback.
class MockStatisticsCB { class MockStatisticsCB {
public: public:
......
This diff is collapsed.
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "base/gtest_prod_util.h" #include "base/gtest_prod_util.h"
#include "base/synchronization/condition_variable.h" #include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h" #include "base/synchronization/lock.h"
#include "media/base/audio_renderer.h"
#include "media/base/demuxer.h" #include "media/base/demuxer.h"
#include "media/base/filter_host.h" #include "media/base/filter_host.h"
#include "media/base/media_export.h" #include "media/base/media_export.h"
...@@ -27,7 +28,6 @@ class TimeDelta; ...@@ -27,7 +28,6 @@ class TimeDelta;
namespace media { namespace media {
class AudioDecoder; class AudioDecoder;
class AudioRenderer;
class Clock; class Clock;
class Filter; class Filter;
class FilterCollection; class FilterCollection;
...@@ -225,6 +225,7 @@ class MEDIA_EXPORT Pipeline ...@@ -225,6 +225,7 @@ class MEDIA_EXPORT Pipeline
private: private:
FRIEND_TEST_ALL_PREFIXES(PipelineTest, GetBufferedTimeRanges); FRIEND_TEST_ALL_PREFIXES(PipelineTest, GetBufferedTimeRanges);
FRIEND_TEST_ALL_PREFIXES(PipelineTest, DisableAudioRenderer);
friend class MediaLog; friend class MediaLog;
// Only allow ourselves to be deleted by reference counting. // Only allow ourselves to be deleted by reference counting.
...@@ -301,7 +302,6 @@ class MEDIA_EXPORT Pipeline ...@@ -301,7 +302,6 @@ class MEDIA_EXPORT Pipeline
virtual base::TimeDelta GetDuration() const OVERRIDE; virtual base::TimeDelta GetDuration() const OVERRIDE;
virtual void SetNaturalVideoSize(const gfx::Size& size) OVERRIDE; virtual void SetNaturalVideoSize(const gfx::Size& size) OVERRIDE;
virtual void NotifyEnded() OVERRIDE; virtual void NotifyEnded() OVERRIDE;
virtual void DisableAudioRenderer() OVERRIDE;
// Callbacks executed by filters upon completing initialization. // Callbacks executed by filters upon completing initialization.
void OnFilterInitialize(PipelineStatus status); void OnFilterInitialize(PipelineStatus status);
...@@ -318,6 +318,9 @@ class MEDIA_EXPORT Pipeline ...@@ -318,6 +318,9 @@ class MEDIA_EXPORT Pipeline
// Callback executed by filters to update statistics. // Callback executed by filters to update statistics.
void OnUpdateStatistics(const PipelineStatistics& stats); void OnUpdateStatistics(const PipelineStatistics& stats);
// Callback executed by audio renderer when it has been disabled.
void OnAudioDisabled();
// Callback executed by audio renderer to update clock time. // Callback executed by audio renderer to update clock time.
void OnAudioTimeUpdate(base::TimeDelta time, base::TimeDelta max_time); void OnAudioTimeUpdate(base::TimeDelta time, base::TimeDelta max_time);
...@@ -359,7 +362,7 @@ class MEDIA_EXPORT Pipeline ...@@ -359,7 +362,7 @@ class MEDIA_EXPORT Pipeline
void NotifyEndedTask(); void NotifyEndedTask();
// Carries out disabling the audio renderer. // Carries out disabling the audio renderer.
void DisableAudioRendererTask(); void AudioDisabledTask();
// Carries out advancing to the next filter during Play()/Pause()/Seek(). // Carries out advancing to the next filter during Play()/Pause()/Seek().
void FilterStateTransitionTask(); void FilterStateTransitionTask();
...@@ -410,21 +413,22 @@ class MEDIA_EXPORT Pipeline ...@@ -410,21 +413,22 @@ class MEDIA_EXPORT Pipeline
// Compute the time corresponding to a byte offset. // Compute the time corresponding to a byte offset.
base::TimeDelta TimeForByteOffset_Locked(int64 byte_offset) const; base::TimeDelta TimeForByteOffset_Locked(int64 byte_offset) const;
// Initiates a Stop() on |demuxer_| & |pipeline_filter_|. |callback| // Initiates an asynchronous Pause/Seek/Play/Stop() call sequence executing
// is called once both objects have been stopped. // |done_cb| when completed.
void DoStop(const base::Closure& callback); void DoPause(const base::Closure& done_cb);
void DoFlush(const base::Closure& done_cb);
// Called when |demuxer_| has stopped. This method calls Stop() void DoPlay(const base::Closure& done_cb);
// on |pipeline_filter_|. void DoStop(const base::Closure& done_cb);
void OnDemuxerStopDone(const base::Closure& callback);
// Initiates a Seek() on the |demuxer_| & |pipeline_filter_|.
void DoSeek(base::TimeDelta seek_timestamp);
// Called when |demuxer_| finishes seeking. If seeking was successful, // Initiates an asynchronous Seek() and preroll call sequence executing
// then Seek() is called on |pipeline_filter_|. // |done_cb| with the final status when completed. If |skip_demuxer_seek| is
void OnDemuxerSeekDone(base::TimeDelta seek_timestamp, // true then only renderers will attempt to preroll.
PipelineStatus status); //
// TODO(scherkus): Prerolling should be separate from seeking so we can report
// finer grained ready states (HAVE_CURRENT_DATA vs. HAVE_FUTURE_DATA)
// indepentent from seeking.
void DoSeek(base::TimeDelta seek_timestamp, bool skip_demuxer_seek,
const PipelineStatusCB& done_cb);
void OnAudioUnderflow(); void OnAudioUnderflow();
...@@ -533,6 +537,10 @@ class MEDIA_EXPORT Pipeline ...@@ -533,6 +537,10 @@ class MEDIA_EXPORT Pipeline
PipelineStatusCB error_cb_; PipelineStatusCB error_cb_;
// Reference to the filter(s) that constitute the pipeline. // Reference to the filter(s) that constitute the pipeline.
//
// TODO(scherkus): At this point in time this is a CompositeFilter that
// contains |video_renderer_|. Remove when CompositeFilter is gone, see
// http://crbug.com/126069
scoped_refptr<Filter> pipeline_filter_; scoped_refptr<Filter> pipeline_filter_;
// Decoder reference used for signalling imminent shutdown. // Decoder reference used for signalling imminent shutdown.
......
This diff is collapsed.
...@@ -16,8 +16,7 @@ ...@@ -16,8 +16,7 @@
namespace media { namespace media {
AudioRendererImpl::AudioRendererImpl(media::AudioRendererSink* sink) AudioRendererImpl::AudioRendererImpl(media::AudioRendererSink* sink)
: host_(NULL), : state_(kUninitialized),
state_(kUninitialized),
pending_read_(false), pending_read_(false),
received_end_of_stream_(false), received_end_of_stream_(false),
rendered_end_of_stream_(false), rendered_end_of_stream_(false),
...@@ -33,12 +32,6 @@ AudioRendererImpl::AudioRendererImpl(media::AudioRendererSink* sink) ...@@ -33,12 +32,6 @@ AudioRendererImpl::AudioRendererImpl(media::AudioRendererSink* sink)
base::Unretained(this))) { base::Unretained(this))) {
} }
void AudioRendererImpl::SetHost(FilterHost* host) {
DCHECK(host);
DCHECK(!host_);
host_ = host;
}
void AudioRendererImpl::Play(const base::Closure& callback) { void AudioRendererImpl::Play(const base::Closure& callback) {
{ {
base::AutoLock auto_lock(lock_); base::AutoLock auto_lock(lock_);
...@@ -145,15 +138,24 @@ void AudioRendererImpl::DoSeek() { ...@@ -145,15 +138,24 @@ void AudioRendererImpl::DoSeek() {
void AudioRendererImpl::Initialize(const scoped_refptr<AudioDecoder>& decoder, void AudioRendererImpl::Initialize(const scoped_refptr<AudioDecoder>& decoder,
const PipelineStatusCB& init_cb, const PipelineStatusCB& init_cb,
const base::Closure& underflow_cb, const base::Closure& underflow_cb,
const TimeCB& time_cb) { const TimeCB& time_cb,
const base::Closure& ended_cb,
const base::Closure& disabled_cb,
const PipelineStatusCB& error_cb) {
DCHECK(decoder); DCHECK(decoder);
DCHECK(!init_cb.is_null()); DCHECK(!init_cb.is_null());
DCHECK(!underflow_cb.is_null()); DCHECK(!underflow_cb.is_null());
DCHECK(!time_cb.is_null()); DCHECK(!time_cb.is_null());
DCHECK(!ended_cb.is_null());
DCHECK(!disabled_cb.is_null());
DCHECK(!error_cb.is_null());
DCHECK_EQ(kUninitialized, state_); DCHECK_EQ(kUninitialized, state_);
decoder_ = decoder; decoder_ = decoder;
underflow_cb_ = underflow_cb; underflow_cb_ = underflow_cb;
time_cb_ = time_cb; time_cb_ = time_cb;
ended_cb_ = ended_cb;
disabled_cb_ = disabled_cb;
error_cb_ = error_cb;
// Create a callback so our algorithm can request more reads. // Create a callback so our algorithm can request more reads.
base::Closure cb = base::Bind(&AudioRendererImpl::ScheduleRead_Locked, this); base::Closure cb = base::Bind(&AudioRendererImpl::ScheduleRead_Locked, this);
...@@ -436,7 +438,7 @@ uint32 AudioRendererImpl::FillBuffer(uint8* dest, ...@@ -436,7 +438,7 @@ uint32 AudioRendererImpl::FillBuffer(uint8* dest,
if (!algorithm_->CanFillBuffer() && received_end_of_stream_ && if (!algorithm_->CanFillBuffer() && received_end_of_stream_ &&
!rendered_end_of_stream_ && base::Time::Now() >= earliest_end_time_) { !rendered_end_of_stream_ && base::Time::Now() >= earliest_end_time_) {
rendered_end_of_stream_ = true; rendered_end_of_stream_ = true;
host_->NotifyEnded(); ended_cb_.Run();
} else if (!algorithm_->CanFillBuffer() && !received_end_of_stream_ && } else if (!algorithm_->CanFillBuffer() && !received_end_of_stream_ &&
state_ == kPlaying && !underflow_disabled_) { state_ == kPlaying && !underflow_disabled_) {
state_ = kUnderflow; state_ = kUnderflow;
...@@ -519,7 +521,7 @@ base::TimeDelta AudioRendererImpl::ConvertToDuration(int bytes) { ...@@ -519,7 +521,7 @@ base::TimeDelta AudioRendererImpl::ConvertToDuration(int bytes) {
} }
void AudioRendererImpl::OnRenderError() { void AudioRendererImpl::OnRenderError() {
host_->DisableAudioRenderer(); disabled_cb_.Run();
} }
void AudioRendererImpl::DisableUnderflowForTesting() { void AudioRendererImpl::DisableUnderflowForTesting() {
...@@ -535,7 +537,7 @@ void AudioRendererImpl::HandleAbortedReadOrDecodeError(bool is_decode_error) { ...@@ -535,7 +537,7 @@ void AudioRendererImpl::HandleAbortedReadOrDecodeError(bool is_decode_error) {
return; return;
case kPaused: case kPaused:
if (status != PIPELINE_OK) if (status != PIPELINE_OK)
host_->SetError(status); error_cb_.Run(status);
base::ResetAndReturn(&pause_cb_).Run(); base::ResetAndReturn(&pause_cb_).Run();
return; return;
case kSeeking: case kSeeking:
...@@ -547,7 +549,7 @@ void AudioRendererImpl::HandleAbortedReadOrDecodeError(bool is_decode_error) { ...@@ -547,7 +549,7 @@ void AudioRendererImpl::HandleAbortedReadOrDecodeError(bool is_decode_error) {
case kRebuffering: case kRebuffering:
case kStopped: case kStopped:
if (status != PIPELINE_OK) if (status != PIPELINE_OK)
host_->SetError(status); error_cb_.Run(status);
return; return;
} }
} }
......
...@@ -40,20 +40,20 @@ class MEDIA_EXPORT AudioRendererImpl ...@@ -40,20 +40,20 @@ class MEDIA_EXPORT AudioRendererImpl
explicit AudioRendererImpl(media::AudioRendererSink* sink); explicit AudioRendererImpl(media::AudioRendererSink* sink);
// Methods called on pipeline thread ---------------------------------------- // Methods called on pipeline thread ----------------------------------------
// Filter implementation. // AudioRenderer implementation.
virtual void SetHost(FilterHost* host) OVERRIDE; virtual void Initialize(const scoped_refptr<AudioDecoder>& decoder,
const PipelineStatusCB& init_cb,
const base::Closure& underflow_cb,
const TimeCB& time_cb,
const base::Closure& ended_cb,
const base::Closure& disabled_cb,
const PipelineStatusCB& error_cb) OVERRIDE;
virtual void Play(const base::Closure& callback) OVERRIDE; virtual void Play(const base::Closure& callback) OVERRIDE;
virtual void Pause(const base::Closure& callback) OVERRIDE; virtual void Pause(const base::Closure& callback) OVERRIDE;
virtual void Flush(const base::Closure& callback) OVERRIDE; virtual void Flush(const base::Closure& callback) OVERRIDE;
virtual void Stop(const base::Closure& callback) OVERRIDE; virtual void Stop(const base::Closure& callback) OVERRIDE;
virtual void SetPlaybackRate(float rate) OVERRIDE; virtual void SetPlaybackRate(float rate) OVERRIDE;
virtual void Seek(base::TimeDelta time, const PipelineStatusCB& cb) OVERRIDE; virtual void Seek(base::TimeDelta time, const PipelineStatusCB& cb) OVERRIDE;
// AudioRenderer implementation.
virtual void Initialize(const scoped_refptr<AudioDecoder>& decoder,
const PipelineStatusCB& init_cb,
const base::Closure& underflow_cb,
const TimeCB& time_cb) OVERRIDE;
virtual bool HasEnded() OVERRIDE; virtual bool HasEnded() OVERRIDE;
virtual void ResumeAfterUnderflow(bool buffer_more_audio) OVERRIDE; virtual void ResumeAfterUnderflow(bool buffer_more_audio) OVERRIDE;
virtual void SetVolume(float volume) OVERRIDE; virtual void SetVolume(float volume) OVERRIDE;
...@@ -136,8 +136,6 @@ class MEDIA_EXPORT AudioRendererImpl ...@@ -136,8 +136,6 @@ class MEDIA_EXPORT AudioRendererImpl
// in the kSeeking state. // in the kSeeking state.
bool IsBeforeSeekTime(const scoped_refptr<Buffer>& buffer); bool IsBeforeSeekTime(const scoped_refptr<Buffer>& buffer);
FilterHost* host_;
// Audio decoder. // Audio decoder.
scoped_refptr<AudioDecoder> decoder_; scoped_refptr<AudioDecoder> decoder_;
...@@ -175,8 +173,10 @@ class MEDIA_EXPORT AudioRendererImpl ...@@ -175,8 +173,10 @@ class MEDIA_EXPORT AudioRendererImpl
PipelineStatusCB seek_cb_; PipelineStatusCB seek_cb_;
base::Closure underflow_cb_; base::Closure underflow_cb_;
TimeCB time_cb_; TimeCB time_cb_;
base::Closure ended_cb_;
base::Closure disabled_cb_;
PipelineStatusCB error_cb_;
base::TimeDelta seek_timestamp_; base::TimeDelta seek_timestamp_;
......
...@@ -34,7 +34,6 @@ class AudioRendererImplTest : public ::testing::Test { ...@@ -34,7 +34,6 @@ class AudioRendererImplTest : public ::testing::Test {
AudioRendererImplTest() AudioRendererImplTest()
: renderer_(new AudioRendererImpl(new NiceMock<MockAudioRendererSink>())), : renderer_(new AudioRendererImpl(new NiceMock<MockAudioRendererSink>())),
decoder_(new MockAudioDecoder()) { decoder_(new MockAudioDecoder()) {
renderer_->SetHost(&host_);
// Queue all reads from the decoder by default. // Queue all reads from the decoder by default.
ON_CALL(*decoder_, Read(_)) ON_CALL(*decoder_, Read(_))
...@@ -48,28 +47,12 @@ class AudioRendererImplTest : public ::testing::Test { ...@@ -48,28 +47,12 @@ class AudioRendererImplTest : public ::testing::Test {
.Times(AnyNumber()); .Times(AnyNumber());
EXPECT_CALL(*decoder_, samples_per_second()) EXPECT_CALL(*decoder_, samples_per_second())
.Times(AnyNumber()); .Times(AnyNumber());
// We'll pretend time never advances.
EXPECT_CALL(host_, GetTime())
.WillRepeatedly(Return(base::TimeDelta()));
} }
virtual ~AudioRendererImplTest() { virtual ~AudioRendererImplTest() {
renderer_->Stop(NewExpectedClosure()); renderer_->Stop(NewExpectedClosure());
} }
MOCK_METHOD1(OnSeekComplete, void(PipelineStatus));
PipelineStatusCB NewSeekCB() {
return base::Bind(&AudioRendererImplTest::OnSeekComplete,
base::Unretained(this));
}
MOCK_METHOD0(OnUnderflow, void());
base::Closure NewUnderflowClosure() {
return base::Bind(&AudioRendererImplTest::OnUnderflow,
base::Unretained(this));
}
void SetSupportedAudioDecoderProperties() { void SetSupportedAudioDecoderProperties() {
ON_CALL(*decoder_, bits_per_channel()) ON_CALL(*decoder_, bits_per_channel())
.WillByDefault(Return(16)); .WillByDefault(Return(16));
...@@ -88,20 +71,39 @@ class AudioRendererImplTest : public ::testing::Test { ...@@ -88,20 +71,39 @@ class AudioRendererImplTest : public ::testing::Test {
.WillByDefault(Return(0)); .WillByDefault(Return(0));
} }
MOCK_METHOD1(OnSeekComplete, void(PipelineStatus));
PipelineStatusCB NewSeekCB() {
return base::Bind(&AudioRendererImplTest::OnSeekComplete,
base::Unretained(this));
}
MOCK_METHOD0(OnUnderflow, void());
MOCK_METHOD0(OnEnded, void());
MOCK_METHOD0(OnDisabled, void());
MOCK_METHOD1(OnError, void(PipelineStatus));
void OnAudioTimeCallback( void OnAudioTimeCallback(
base::TimeDelta current_time, base::TimeDelta max_time) { base::TimeDelta current_time, base::TimeDelta max_time) {
CHECK(current_time <= max_time); CHECK(current_time <= max_time);
} }
AudioRenderer::TimeCB NewAudioTimeClosure() { void Initialize() {
return base::Bind(&AudioRendererImplTest::OnAudioTimeCallback, InitializeWithStatus(PIPELINE_OK);
base::Unretained(this));
} }
void Initialize() { void InitializeWithStatus(PipelineStatus expected) {
renderer_->Initialize( renderer_->Initialize(
decoder_, NewExpectedStatusCB(PIPELINE_OK), NewUnderflowClosure(), decoder_, NewExpectedStatusCB(expected),
NewAudioTimeClosure()); base::Bind(&AudioRendererImplTest::OnUnderflow,
base::Unretained(this)),
base::Bind(&AudioRendererImplTest::OnAudioTimeCallback,
base::Unretained(this)),
base::Bind(&AudioRendererImplTest::OnEnded,
base::Unretained(this)),
base::Bind(&AudioRendererImplTest::OnDisabled,
base::Unretained(this)),
base::Bind(&AudioRendererImplTest::OnError,
base::Unretained(this)));
} }
void Preroll() { void Preroll() {
...@@ -211,7 +213,6 @@ class AudioRendererImplTest : public ::testing::Test { ...@@ -211,7 +213,6 @@ class AudioRendererImplTest : public ::testing::Test {
// Fixture members. // Fixture members.
scoped_refptr<AudioRendererImpl> renderer_; scoped_refptr<AudioRendererImpl> renderer_;
scoped_refptr<MockAudioDecoder> decoder_; scoped_refptr<MockAudioDecoder> decoder_;
StrictMock<MockFilterHost> host_;
AudioDecoder::ReadCB read_cb_; AudioDecoder::ReadCB read_cb_;
base::TimeDelta next_timestamp_; base::TimeDelta next_timestamp_;
...@@ -226,18 +227,14 @@ class AudioRendererImplTest : public ::testing::Test { ...@@ -226,18 +227,14 @@ class AudioRendererImplTest : public ::testing::Test {
TEST_F(AudioRendererImplTest, Initialize_Failed) { TEST_F(AudioRendererImplTest, Initialize_Failed) {
SetUnsupportedAudioDecoderProperties(); SetUnsupportedAudioDecoderProperties();
renderer_->Initialize( InitializeWithStatus(PIPELINE_ERROR_INITIALIZATION_FAILED);
decoder_,
NewExpectedStatusCB(PIPELINE_ERROR_INITIALIZATION_FAILED),
NewUnderflowClosure(), NewAudioTimeClosure());
// We should have no reads. // We should have no reads.
EXPECT_TRUE(read_cb_.is_null()); EXPECT_TRUE(read_cb_.is_null());
} }
TEST_F(AudioRendererImplTest, Initialize_Successful) { TEST_F(AudioRendererImplTest, Initialize_Successful) {
renderer_->Initialize(decoder_, NewExpectedStatusCB(PIPELINE_OK), Initialize();
NewUnderflowClosure(), NewAudioTimeClosure());
// We should have no reads. // We should have no reads.
EXPECT_TRUE(read_cb_.is_null()); EXPECT_TRUE(read_cb_.is_null());
...@@ -273,7 +270,7 @@ TEST_F(AudioRendererImplTest, EndOfStream) { ...@@ -273,7 +270,7 @@ TEST_F(AudioRendererImplTest, EndOfStream) {
EXPECT_FALSE(renderer_->HasEnded()); EXPECT_FALSE(renderer_->HasEnded());
// Drain internal buffer, now we should report ended. // Drain internal buffer, now we should report ended.
EXPECT_CALL(host_, NotifyEnded()); EXPECT_CALL(*this, OnEnded());
EXPECT_TRUE(ConsumeBufferedData(bytes_buffered(), NULL)); EXPECT_TRUE(ConsumeBufferedData(bytes_buffered(), NULL));
EXPECT_TRUE(renderer_->HasEnded()); EXPECT_TRUE(renderer_->HasEnded());
} }
...@@ -351,9 +348,9 @@ TEST_F(AudioRendererImplTest, Underflow_EndOfStream) { ...@@ -351,9 +348,9 @@ TEST_F(AudioRendererImplTest, Underflow_EndOfStream) {
// //
// TODO(scherkus): fix AudioRendererImpl and AudioRendererAlgorithmBase to // TODO(scherkus): fix AudioRendererImpl and AudioRendererAlgorithmBase to
// stop reading after receiving an end of stream buffer. It should have also // stop reading after receiving an end of stream buffer. It should have also
// called NotifyEnded() http://crbug.com/106641 // fired the ended callback http://crbug.com/106641
DeliverEndOfStream(); DeliverEndOfStream();
EXPECT_CALL(host_, NotifyEnded()); EXPECT_CALL(*this, OnEnded());
EXPECT_FALSE(ConsumeBufferedData(kDataSize, &muted)); EXPECT_FALSE(ConsumeBufferedData(kDataSize, &muted));
EXPECT_FALSE(muted); EXPECT_FALSE(muted);
......
...@@ -61,7 +61,7 @@ class VideoRendererBaseTest : public ::testing::Test { ...@@ -61,7 +61,7 @@ class VideoRendererBaseTest : public ::testing::Test {
EXPECT_CALL(*this, SetOpaqueCBWasCalled(_)) EXPECT_CALL(*this, SetOpaqueCBWasCalled(_))
.WillRepeatedly(::testing::Return()); .WillRepeatedly(::testing::Return());
EXPECT_CALL(*decoder_, Stop(_)) EXPECT_CALL(*decoder_, Stop(_))
.WillRepeatedly(Invoke(RunClosure)); .WillRepeatedly(RunClosure());
EXPECT_CALL(*this, TimeCBWasCalled(_)) EXPECT_CALL(*this, TimeCBWasCalled(_))
.WillRepeatedly(::testing::Return()); .WillRepeatedly(::testing::Return());
} }
......
...@@ -142,6 +142,8 @@ ...@@ -142,6 +142,8 @@
'base/buffers.h', 'base/buffers.h',
'base/byte_queue.cc', 'base/byte_queue.cc',
'base/byte_queue.h', 'base/byte_queue.h',
'base/callback_util.cc',
'base/callback_util.h',
'base/channel_layout.cc', 'base/channel_layout.cc',
'base/channel_layout.h', 'base/channel_layout.h',
'base/clock.cc', 'base/clock.cc',
......
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