diff options
-rw-r--r-- | media/audio/fake_audio_consumer.cc | 67 | ||||
-rw-r--r-- | media/audio/fake_audio_consumer.h | 61 | ||||
-rw-r--r-- | media/audio/fake_audio_consumer_unittest.cc (renamed from media/audio/fake_audio_output_stream_unittest.cc) | 93 | ||||
-rw-r--r-- | media/audio/fake_audio_output_stream.cc | 34 | ||||
-rw-r--r-- | media/audio/fake_audio_output_stream.h | 17 | ||||
-rw-r--r-- | media/audio/null_audio_sink.cc | 129 | ||||
-rw-r--r-- | media/audio/null_audio_sink.h | 42 | ||||
-rw-r--r-- | media/filters/pipeline_integration_test_base.cc | 2 | ||||
-rw-r--r-- | media/media.gyp | 7 | ||||
-rw-r--r-- | media/tools/player_x11/player_x11.cc | 2 | ||||
-rw-r--r-- | webkit/media/webmediaplayer_impl.cc | 2 |
11 files changed, 258 insertions, 198 deletions
diff --git a/media/audio/fake_audio_consumer.cc b/media/audio/fake_audio_consumer.cc new file mode 100644 index 0000000..95db9cd --- /dev/null +++ b/media/audio/fake_audio_consumer.cc @@ -0,0 +1,67 @@ +// Copyright (c) 2013 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/audio/fake_audio_consumer.h" + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/logging.h" +#include "base/message_loop.h" +#include "base/message_loop_proxy.h" +#include "media/base/audio_bus.h" + +namespace media { + +FakeAudioConsumer::FakeAudioConsumer( + const scoped_refptr<base::MessageLoopProxy>& message_loop, + const AudioParameters& params) + : message_loop_(message_loop), + audio_bus_(AudioBus::Create(params)), + buffer_duration_(base::TimeDelta::FromMicroseconds( + params.frames_per_buffer() * base::Time::kMicrosecondsPerSecond / + static_cast<float>(params.sample_rate()))) { + audio_bus_->Zero(); +} + +FakeAudioConsumer::~FakeAudioConsumer() { + DCHECK(read_cb_.is_null()); +} + +void FakeAudioConsumer::Start(const ReadCB& read_cb) { + DCHECK(message_loop_->BelongsToCurrentThread()); + DCHECK(read_cb_.is_null()); + DCHECK(!read_cb.is_null()); + read_cb_ = read_cb; + next_read_time_ = base::Time::Now(); + read_task_cb_.Reset(base::Bind( + &FakeAudioConsumer::DoRead, base::Unretained(this))); + message_loop_->PostTask(FROM_HERE, read_task_cb_.callback()); +} + +void FakeAudioConsumer::Stop() { + DCHECK(message_loop_->BelongsToCurrentThread()); + read_cb_.Reset(); + read_task_cb_.Cancel(); +} + +void FakeAudioConsumer::DoRead() { + DCHECK(message_loop_->BelongsToCurrentThread()); + DCHECK(!read_cb_.is_null()); + + read_cb_.Run(audio_bus_.get()); + + // Need to account for time spent here due to the cost of |read_cb_| as well + // as the imprecision of PostDelayedTask(). + base::Time now = base::Time::Now(); + base::TimeDelta delay = next_read_time_ + buffer_duration_ - now; + + // If we're behind, find the next nearest ontime interval. + if (delay < base::TimeDelta()) + delay += buffer_duration_ * (-delay / buffer_duration_ + 1); + next_read_time_ = now + delay; + + message_loop_->PostDelayedTask(FROM_HERE, read_task_cb_.callback(), delay); +} + +} // namespace media diff --git a/media/audio/fake_audio_consumer.h b/media/audio/fake_audio_consumer.h new file mode 100644 index 0000000..793e553 --- /dev/null +++ b/media/audio/fake_audio_consumer.h @@ -0,0 +1,61 @@ +// Copyright (c) 2013 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_AUDIO_FAKE_AUDIO_CONSUMER_H_ +#define MEDIA_AUDIO_FAKE_AUDIO_CONSUMER_H_ + +#include "base/cancelable_callback.h" +#include "base/memory/scoped_ptr.h" +#include "base/time.h" +#include "media/audio/audio_parameters.h" + +namespace base { +class MessageLoopProxy; +} + +namespace media { +class AudioBus; + +// A fake audio consumer. Using a provided message loop, FakeAudioConsumer will +// simulate a real time consumer of audio data. +class MEDIA_EXPORT FakeAudioConsumer { + public: + // |message_loop| is the loop on which the ReadCB provided to Start() will be + // executed on. |params| is used to determine the frequency of callbacks. + FakeAudioConsumer(const scoped_refptr<base::MessageLoopProxy>& message_loop, + const AudioParameters& params); + ~FakeAudioConsumer(); + + // Start executing |read_cb| at a regular interval. Must be called on the + // message loop provided during construction. Stop() must be called before + // destroying FakeAudioConsumer. + typedef base::Callback<void(AudioBus* audio_bus)> ReadCB; + void Start(const ReadCB& read_cb); + + // Stop executing the ReadCB provided to Start(). Cancels any outstanding + // callbacks. Safe to call multiple times. Must be called on the message + // loop provided during construction. + void Stop(); + + private: + // Task that regularly calls |read_cb_| according to the playback rate as + // determined by the audio parameters given during construction. Runs on + // |message_loop_|. + void DoRead(); + + scoped_refptr<base::MessageLoopProxy> message_loop_; + ReadCB read_cb_; + scoped_ptr<AudioBus> audio_bus_; + base::TimeDelta buffer_duration_; + base::Time next_read_time_; + + // Used to post delayed tasks to the AudioThread that we can cancel. + base::CancelableClosure read_task_cb_; + + DISALLOW_COPY_AND_ASSIGN(FakeAudioConsumer); +}; + +} // namespace media + +#endif // MEDIA_AUDIO_FAKE_AUDIO_CONSUMER_H_ diff --git a/media/audio/fake_audio_output_stream_unittest.cc b/media/audio/fake_audio_consumer_unittest.cc index 6599b76..66077d5 100644 --- a/media/audio/fake_audio_output_stream_unittest.cc +++ b/media/audio/fake_audio_consumer_unittest.cc @@ -4,10 +4,9 @@ #include "base/bind.h" #include "base/message_loop.h" -#include "base/synchronization/waitable_event.h" #include "base/time.h" -#include "media/audio/fake_audio_output_stream.h" -#include "media/audio/audio_manager.h" +#include "media/audio/audio_buffers_state.h" +#include "media/audio/fake_audio_consumer.h" #include "media/audio/simple_sources.h" #include "testing/gtest/include/gtest/gtest.h" @@ -15,47 +14,47 @@ namespace media { static const int kTestCallbacks = 5; -class FakeAudioOutputStreamTest : public testing::Test { +class FakeAudioConsumerTest : public testing::Test { public: - FakeAudioOutputStreamTest() - : audio_manager_(AudioManager::Create()), - params_( + FakeAudioConsumerTest() + : params_( AudioParameters::AUDIO_FAKE, CHANNEL_LAYOUT_STEREO, 44100, 8, 128), - source_(params_.channels(), 200.0, params_.sample_rate()), - done_(false, false) { - stream_ = audio_manager_->MakeAudioOutputStream(AudioParameters(params_)); - CHECK(stream_); - + fake_consumer_(message_loop_.message_loop_proxy(), params_), + source_(params_.channels(), 200.0, params_.sample_rate()) { time_between_callbacks_ = base::TimeDelta::FromMicroseconds( params_.frames_per_buffer() * base::Time::kMicrosecondsPerSecond / static_cast<float>(params_.sample_rate())); } - virtual ~FakeAudioOutputStreamTest() {} + virtual ~FakeAudioConsumerTest() {} + + void ConsumeData(AudioBus* audio_bus) { + source_.OnMoreData(audio_bus, AudioBuffersState()); + } void RunOnAudioThread() { - ASSERT_TRUE(audio_manager_->GetMessageLoop()->BelongsToCurrentThread()); - ASSERT_TRUE(stream_->Open()); - stream_->Start(&source_); + ASSERT_TRUE(message_loop_.message_loop_proxy()->BelongsToCurrentThread()); + fake_consumer_.Start(base::Bind( + &FakeAudioConsumerTest::ConsumeData, base::Unretained(this))); } void RunOnceOnAudioThread() { - ASSERT_TRUE(audio_manager_->GetMessageLoop()->BelongsToCurrentThread()); + ASSERT_TRUE(message_loop_.message_loop_proxy()->BelongsToCurrentThread()); RunOnAudioThread(); // Start() should immediately post a task to run the source callback, so we // should end up with only a single callback being run. - audio_manager_->GetMessageLoop()->PostTask(FROM_HERE, base::Bind( - &FakeAudioOutputStreamTest::EndTest, base::Unretained(this), 1)); + message_loop_.PostTask(FROM_HERE, base::Bind( + &FakeAudioConsumerTest::EndTest, base::Unretained(this), 1)); } void StopStartOnAudioThread() { - ASSERT_TRUE(audio_manager_->GetMessageLoop()->BelongsToCurrentThread()); - stream_->Stop(); - stream_->Start(&source_); + ASSERT_TRUE(message_loop_.message_loop_proxy()->BelongsToCurrentThread()); + fake_consumer_.Stop(); + RunOnAudioThread(); } void TimeCallbacksOnAudioThread(int callbacks) { - ASSERT_TRUE(audio_manager_->GetMessageLoop()->BelongsToCurrentThread()); + ASSERT_TRUE(message_loop_.message_loop_proxy()->BelongsToCurrentThread()); if (source_.callbacks() == 0) { RunOnAudioThread(); @@ -64,8 +63,8 @@ class FakeAudioOutputStreamTest : public testing::Test { // Keep going until we've seen the requested number of callbacks. if (source_.callbacks() < callbacks) { - audio_manager_->GetMessageLoop()->PostDelayedTask(FROM_HERE, base::Bind( - &FakeAudioOutputStreamTest::TimeCallbacksOnAudioThread, + message_loop_.PostDelayedTask(FROM_HERE, base::Bind( + &FakeAudioConsumerTest::TimeCallbacksOnAudioThread, base::Unretained(this), callbacks), time_between_callbacks_ / 2); } else { end_time_ = base::Time::Now(); @@ -74,44 +73,40 @@ class FakeAudioOutputStreamTest : public testing::Test { } void EndTest(int callbacks) { - ASSERT_TRUE(audio_manager_->GetMessageLoop()->BelongsToCurrentThread()); - stream_->Stop(); - stream_->Close(); + ASSERT_TRUE(message_loop_.message_loop_proxy()->BelongsToCurrentThread()); + fake_consumer_.Stop(); EXPECT_LE(callbacks, source_.callbacks()); - EXPECT_EQ(0, source_.errors()); - done_.Signal(); + message_loop_.PostTask(FROM_HERE, MessageLoop::QuitClosure()); } protected: - scoped_ptr<AudioManager> audio_manager_; + MessageLoop message_loop_; AudioParameters params_; - AudioOutputStream* stream_; + FakeAudioConsumer fake_consumer_; SineWaveAudioSource source_; - base::WaitableEvent done_; base::Time start_time_; base::Time end_time_; base::TimeDelta time_between_callbacks_; private: - DISALLOW_COPY_AND_ASSIGN(FakeAudioOutputStreamTest); + DISALLOW_COPY_AND_ASSIGN(FakeAudioConsumerTest); }; // Ensure the fake audio stream runs on the audio thread and handles fires // callbacks to the AudioSourceCallback. -TEST_F(FakeAudioOutputStreamTest, FakeStreamBasicCallback) { - audio_manager_->GetMessageLoop()->PostTask(FROM_HERE, base::Bind( - &FakeAudioOutputStreamTest::RunOnceOnAudioThread, +TEST_F(FakeAudioConsumerTest, FakeStreamBasicCallback) { + message_loop_.PostTask(FROM_HERE, base::Bind( + &FakeAudioConsumerTest::RunOnceOnAudioThread, base::Unretained(this))); - done_.Wait(); + message_loop_.Run(); } // Ensure the time between callbacks is sane. -TEST_F(FakeAudioOutputStreamTest, TimeBetweenCallbacks) { - audio_manager_->GetMessageLoop()->PostTask(FROM_HERE, base::Bind( - &FakeAudioOutputStreamTest::TimeCallbacksOnAudioThread, +TEST_F(FakeAudioConsumerTest, TimeBetweenCallbacks) { + message_loop_.PostTask(FROM_HERE, base::Bind( + &FakeAudioConsumerTest::TimeCallbacksOnAudioThread, base::Unretained(this), kTestCallbacks)); - - done_.Wait(); + message_loop_.Run(); // There are only (kTestCallbacks - 1) intervals between kTestCallbacks. base::TimeDelta actual_time_between_callbacks = @@ -129,19 +124,19 @@ TEST_F(FakeAudioOutputStreamTest, TimeBetweenCallbacks) { // Ensure Start()/Stop() on the stream doesn't generate too many callbacks. See // http://crbug.com/159049 -TEST_F(FakeAudioOutputStreamTest, StartStopClearsCallbacks) { - audio_manager_->GetMessageLoop()->PostTask(FROM_HERE, base::Bind( - &FakeAudioOutputStreamTest::TimeCallbacksOnAudioThread, +TEST_F(FakeAudioConsumerTest, StartStopClearsCallbacks) { + message_loop_.PostTask(FROM_HERE, base::Bind( + &FakeAudioConsumerTest::TimeCallbacksOnAudioThread, base::Unretained(this), kTestCallbacks)); // Issue a Stop() / Start() in between expected callbacks to maximize the // chance of catching the FakeAudioOutputStream doing the wrong thing. - audio_manager_->GetMessageLoop()->PostDelayedTask(FROM_HERE, base::Bind( - &FakeAudioOutputStreamTest::StopStartOnAudioThread, + message_loop_.PostDelayedTask(FROM_HERE, base::Bind( + &FakeAudioConsumerTest::StopStartOnAudioThread, base::Unretained(this)), time_between_callbacks_ / 2); // EndTest() will ensure the proper number of callbacks have occurred. - done_.Wait(); + message_loop_.Run(); } } // namespace media diff --git a/media/audio/fake_audio_output_stream.cc b/media/audio/fake_audio_output_stream.cc index 8db548c..7b85eb0 100644 --- a/media/audio/fake_audio_output_stream.cc +++ b/media/audio/fake_audio_output_stream.cc @@ -22,11 +22,7 @@ FakeAudioOutputStream::FakeAudioOutputStream(AudioManagerBase* manager, const AudioParameters& params) : audio_manager_(manager), callback_(NULL), - audio_bus_(AudioBus::Create(params)), - buffer_duration_(base::TimeDelta::FromMicroseconds( - params.frames_per_buffer() * base::Time::kMicrosecondsPerSecond / - static_cast<float>(params.sample_rate()))) { - audio_bus_->Zero(); + fake_consumer_(manager->GetMessageLoop(), params) { } FakeAudioOutputStream::~FakeAudioOutputStream() { @@ -41,17 +37,14 @@ bool FakeAudioOutputStream::Open() { void FakeAudioOutputStream::Start(AudioSourceCallback* callback) { DCHECK(audio_manager_->GetMessageLoop()->BelongsToCurrentThread()); callback_ = callback; - next_read_time_ = base::Time::Now(); - on_more_data_cb_.Reset(base::Bind( - &FakeAudioOutputStream::OnMoreDataTask, base::Unretained(this))); - audio_manager_->GetMessageLoop()->PostTask( - FROM_HERE, on_more_data_cb_.callback()); + fake_consumer_.Start(base::Bind( + &FakeAudioOutputStream::CallOnMoreData, base::Unretained(this))); } void FakeAudioOutputStream::Stop() { DCHECK(audio_manager_->GetMessageLoop()->BelongsToCurrentThread()); + fake_consumer_.Stop(); callback_ = NULL; - on_more_data_cb_.Cancel(); } void FakeAudioOutputStream::Close() { @@ -66,24 +59,9 @@ void FakeAudioOutputStream::GetVolume(double* volume) { *volume = 0; }; -void FakeAudioOutputStream::OnMoreDataTask() { +void FakeAudioOutputStream::CallOnMoreData(AudioBus* audio_bus) { DCHECK(audio_manager_->GetMessageLoop()->BelongsToCurrentThread()); - DCHECK(callback_); - - callback_->OnMoreData(audio_bus_.get(), AudioBuffersState()); - - // Need to account for time spent here due to the cost of OnMoreData() as well - // as the imprecision of PostDelayedTask(). - base::Time now = base::Time::Now(); - base::TimeDelta delay = next_read_time_ + buffer_duration_ - now; - - // If we're behind, find the next nearest ontime interval. - if (delay < base::TimeDelta()) - delay += buffer_duration_ * (-delay / buffer_duration_ + 1); - next_read_time_ = now + delay; - - audio_manager_->GetMessageLoop()->PostDelayedTask( - FROM_HERE, on_more_data_cb_.callback(), delay); + callback_->OnMoreData(audio_bus, AudioBuffersState()); } } // namespace media diff --git a/media/audio/fake_audio_output_stream.h b/media/audio/fake_audio_output_stream.h index ec3a592..399d72b 100644 --- a/media/audio/fake_audio_output_stream.h +++ b/media/audio/fake_audio_output_stream.h @@ -5,11 +5,10 @@ #ifndef MEDIA_AUDIO_FAKE_AUDIO_OUTPUT_STREAM_H_ #define MEDIA_AUDIO_FAKE_AUDIO_OUTOUT_STREAM_H_ -#include "base/cancelable_callback.h" #include "base/memory/scoped_ptr.h" -#include "base/time.h" #include "media/audio/audio_io.h" #include "media/audio/audio_parameters.h" +#include "media/audio/fake_audio_consumer.h" namespace media { @@ -17,6 +16,7 @@ class AudioManagerBase; // A fake implementation of AudioOutputStream. Used for testing and when a real // audio output device is unavailable or refusing output (e.g. remote desktop). +// Callbacks are driven on the AudioManager's message loop. class MEDIA_EXPORT FakeAudioOutputStream : public AudioOutputStream { public: static AudioOutputStream* MakeFakeStream(AudioManagerBase* manager, @@ -35,19 +35,12 @@ class MEDIA_EXPORT FakeAudioOutputStream : public AudioOutputStream { const AudioParameters& params); virtual ~FakeAudioOutputStream(); - // Task that regularly calls |callback_->OnMoreData()| according to the - // playback rate as determined by the audio parameters given during - // construction. Runs on AudioManager's message loop. - void OnMoreDataTask(); + // Task that periodically calls OnMoreData() to consume audio data. + void CallOnMoreData(AudioBus* audio_bus); AudioManagerBase* audio_manager_; AudioSourceCallback* callback_; - scoped_ptr<AudioBus> audio_bus_; - base::TimeDelta buffer_duration_; - base::Time next_read_time_; - - // Used to post delayed tasks to the AudioThread that we can cancel. - base::CancelableClosure on_more_data_cb_; + FakeAudioConsumer fake_consumer_; DISALLOW_COPY_AND_ASSIGN(FakeAudioOutputStream); }; diff --git a/media/audio/null_audio_sink.cc b/media/audio/null_audio_sink.cc index c93ceb1..37d3ce0 100644 --- a/media/audio/null_audio_sink.cc +++ b/media/audio/null_audio_sink.cc @@ -5,30 +5,34 @@ #include "media/audio/null_audio_sink.h" #include "base/bind.h" +#include "base/message_loop_proxy.h" #include "base/stringprintf.h" #include "base/sys_byteorder.h" -#include "base/threading/platform_thread.h" +#include "media/audio/fake_audio_consumer.h" namespace media { -NullAudioSink::NullAudioSink() +NullAudioSink::NullAudioSink( + const scoped_refptr<base::MessageLoopProxy>& message_loop) : initialized_(false), - playing_(false), callback_(NULL), - thread_("NullAudioThread"), - hash_audio_for_testing_(false) { + hash_audio_for_testing_(false), + channels_(0), + message_loop_(message_loop) { } +NullAudioSink::~NullAudioSink() {} + void NullAudioSink::Initialize(const AudioParameters& params, RenderCallback* callback) { DCHECK(!initialized_); - params_ = params; - audio_bus_ = AudioBus::Create(params_); + fake_consumer_.reset(new FakeAudioConsumer(message_loop_, params)); if (hash_audio_for_testing_) { - md5_channel_contexts_.reset(new base::MD5Context[params_.channels()]); - for (int i = 0; i < params_.channels(); i++) + channels_ = params.channels(); + md5_channel_contexts_.reset(new base::MD5Context[params.channels()]); + for (int i = 0; i < params.channels(); i++) base::MD5Init(&md5_channel_contexts_[i]); } @@ -37,24 +41,27 @@ void NullAudioSink::Initialize(const AudioParameters& params, } void NullAudioSink::Start() { - if (!thread_.Start()) - return; - - thread_.message_loop()->PostTask(FROM_HERE, base::Bind( - &NullAudioSink::FillBufferTask, this)); + DCHECK(message_loop_->BelongsToCurrentThread()); } void NullAudioSink::Stop() { - SetPlaying(false); - thread_.Stop(); + DCHECK(message_loop_->BelongsToCurrentThread()); + + // Stop may be called at any time, so we have to check before stopping. + if (fake_consumer_) + fake_consumer_->Stop(); } void NullAudioSink::Play() { - SetPlaying(true); + DCHECK(message_loop_->BelongsToCurrentThread()); + DCHECK(initialized_); + fake_consumer_->Start(base::Bind( + &NullAudioSink::CallRender, base::Unretained(this))); } void NullAudioSink::Pause(bool /* flush */) { - SetPlaying(false); + DCHECK(message_loop_->BelongsToCurrentThread()); + fake_consumer_->Stop(); } bool NullAudioSink::SetVolume(double volume) { @@ -62,54 +69,24 @@ bool NullAudioSink::SetVolume(double volume) { return volume == 0.0; } -void NullAudioSink::SetPlaying(bool is_playing) { - base::AutoLock auto_lock(lock_); - playing_ = is_playing; -} +void NullAudioSink::CallRender(AudioBus* audio_bus) { + DCHECK(message_loop_->BelongsToCurrentThread()); -NullAudioSink::~NullAudioSink() { - DCHECK(!thread_.IsRunning()); -} + int frames_received = callback_->Render(audio_bus, 0); + if (!hash_audio_for_testing_ || frames_received <= 0) + return; -void NullAudioSink::FillBufferTask() { - base::AutoLock auto_lock(lock_); - - base::TimeDelta delay; - // Only consume buffers when actually playing. - if (playing_) { - int frames_received = callback_->Render(audio_bus_.get(), 0); - int frames_per_millisecond = - params_.sample_rate() / base::Time::kMillisecondsPerSecond; - - if (hash_audio_for_testing_ && frames_received > 0) { - DCHECK_EQ(sizeof(float), sizeof(uint32)); - int channels = audio_bus_->channels(); - for (int channel_idx = 0; channel_idx < channels; ++channel_idx) { - float* channel = audio_bus_->channel(channel_idx); - for (int frame_idx = 0; frame_idx < frames_received; frame_idx++) { - // Convert float to uint32 w/o conversion loss. - uint32 frame = base::ByteSwapToLE32( - bit_cast<uint32>(channel[frame_idx])); - base::MD5Update( - &md5_channel_contexts_[channel_idx], base::StringPiece( - reinterpret_cast<char*>(&frame), sizeof(frame))); - } - } + DCHECK_EQ(sizeof(float), sizeof(uint32)); + int channels = audio_bus->channels(); + for (int channel_idx = 0; channel_idx < channels; ++channel_idx) { + float* channel = audio_bus->channel(channel_idx); + for (int frame_idx = 0; frame_idx < frames_received; frame_idx++) { + // Convert float to uint32 w/o conversion loss. + uint32 frame = base::ByteSwapToLE32(bit_cast<uint32>(channel[frame_idx])); + base::MD5Update(&md5_channel_contexts_[channel_idx], base::StringPiece( + reinterpret_cast<char*>(&frame), sizeof(frame))); } - - // Calculate our sleep duration. - delay = base::TimeDelta::FromMilliseconds( - frames_received / frames_per_millisecond); - } else { - // If paused, sleep for 10 milliseconds before polling again. - delay = base::TimeDelta::FromMilliseconds(10); } - - // Sleep for at least one millisecond so we don't spin the CPU. - MessageLoop::current()->PostDelayedTask( - FROM_HERE, - base::Bind(&NullAudioSink::FillBufferTask, this), - std::max(delay, base::TimeDelta::FromMilliseconds(1))); } void NullAudioSink::StartAudioHashForTesting() { @@ -120,24 +97,22 @@ void NullAudioSink::StartAudioHashForTesting() { std::string NullAudioSink::GetAudioHashForTesting() { DCHECK(hash_audio_for_testing_); - // If initialize failed or was never called, ensure we return an empty hash. - int channels = 1; - if (!initialized_) { - md5_channel_contexts_.reset(new base::MD5Context[1]); - base::MD5Init(&md5_channel_contexts_[0]); - } else { - channels = audio_bus_->channels(); - } - - // Hash all channels into the first channel. base::MD5Digest digest; - for (int i = 1; i < channels; i++) { - base::MD5Final(&digest, &md5_channel_contexts_[i]); - base::MD5Update(&md5_channel_contexts_[0], base::StringPiece( - reinterpret_cast<char*>(&digest), sizeof(base::MD5Digest))); + if (channels_ == 0) { + // If initialize failed or was never called, ensure we return an empty hash. + base::MD5Context context; + base::MD5Init(&context); + base::MD5Final(&digest, &context); + } else { + // Hash all channels into the first channel. + for (int i = 1; i < channels_; i++) { + base::MD5Final(&digest, &md5_channel_contexts_[i]); + base::MD5Update(&md5_channel_contexts_[0], base::StringPiece( + reinterpret_cast<char*>(&digest), sizeof(base::MD5Digest))); + } + base::MD5Final(&digest, &md5_channel_contexts_[0]); } - base::MD5Final(&digest, &md5_channel_contexts_[0]); return base::MD5DigestToBase16(digest); } diff --git a/media/audio/null_audio_sink.h b/media/audio/null_audio_sink.h index c528473..f892ab4 100644 --- a/media/audio/null_audio_sink.h +++ b/media/audio/null_audio_sink.h @@ -2,29 +2,25 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef MEDIA_FILTERS_NULL_AUDIO_RENDERER_H_ -#define MEDIA_FILTERS_NULL_AUDIO_RENDERER_H_ - -// NullAudioSink effectively uses an extra thread to "throw away" the -// audio data at a rate resembling normal playback speed. It's just like -// decoding to /dev/null! -// -// NullAudioSink can also be used in situations where the client has no -// audio device or we haven't written an audio implementation for a particular -// platform yet. +#ifndef MEDIA_AUDIO_NULL_AUDIO_SINK_H_ +#define MEDIA_AUDIO_NULL_AUDIO_SINK_H_ #include "base/md5.h" #include "base/memory/scoped_ptr.h" -#include "base/threading/thread.h" #include "media/base/audio_renderer_sink.h" +namespace base { +class MessageLoopProxy; +} + namespace media { class AudioBus; +class FakeAudioConsumer; class MEDIA_EXPORT NullAudioSink : NON_EXPORTED_BASE(public AudioRendererSink) { public: - NullAudioSink(); + NullAudioSink(const scoped_refptr<base::MessageLoopProxy>& message_loop); // AudioRendererSink implementation. virtual void Initialize(const AudioParameters& params, @@ -46,31 +42,23 @@ class MEDIA_EXPORT NullAudioSink virtual ~NullAudioSink(); private: - // Audio thread task that periodically calls FillBuffer() to consume - // audio data. - void FillBufferTask(); - - void SetPlaying(bool is_playing); + // Task that periodically calls Render() to consume audio data. + void CallRender(AudioBus* audio_bus); - // A buffer passed to FillBuffer to advance playback. - scoped_ptr<AudioBus> audio_bus_; - - AudioParameters params_; bool initialized_; - bool playing_; RenderCallback* callback_; - // Separate thread used to throw away data. - base::Thread thread_; - base::Lock lock_; - // Controls whether or not a running MD5 hash is computed for audio frames. bool hash_audio_for_testing_; + int channels_; scoped_array<base::MD5Context> md5_channel_contexts_; + scoped_refptr<base::MessageLoopProxy> message_loop_; + scoped_ptr<FakeAudioConsumer> fake_consumer_; + DISALLOW_COPY_AND_ASSIGN(NullAudioSink); }; } // namespace media -#endif // MEDIA_FILTERS_NULL_AUDIO_RENDERER_H_ +#endif // MEDIA_AUDIO_NULL_AUDIO_SINK_H_ diff --git a/media/filters/pipeline_integration_test_base.cc b/media/filters/pipeline_integration_test_base.cc index ed47c41..f5d0c40 100644 --- a/media/filters/pipeline_integration_test_base.cc +++ b/media/filters/pipeline_integration_test_base.cc @@ -246,7 +246,7 @@ PipelineIntegrationTestBase::CreateFilterCollection( !hashing_enabled_)); collection->SetVideoRenderer(renderer.Pass()); - audio_sink_ = new NullAudioSink(); + audio_sink_ = new NullAudioSink(message_loop_.message_loop_proxy()); AudioRendererImpl* audio_renderer_impl = new AudioRendererImpl( message_loop_.message_loop_proxy(), audio_sink_, diff --git a/media/media.gyp b/media/media.gyp index 2b64447..d36628c 100644 --- a/media/media.gyp +++ b/media/media.gyp @@ -105,6 +105,8 @@ 'audio/cross_process_notification.h', 'audio/cross_process_notification_posix.cc', 'audio/cross_process_notification_win.cc', + 'audio/fake_audio_consumer.cc', + 'audio/fake_audio_consumer.h', 'audio/fake_audio_input_stream.cc', 'audio/fake_audio_input_stream.h', 'audio/fake_audio_output_stream.cc', @@ -526,6 +528,7 @@ ['include', '^audio/audio_manager\\.'], ['include', '^audio/audio_manager_base\\.'], ['include', '^audio/audio_parameters\\.'], + ['include', '^audio/fake_audio_consumer\\.'], ['include', '^audio/fake_audio_input_stream\\.'], ['include', '^audio/fake_audio_output_stream\\.'], ['include', '^base/audio_bus\\.'], @@ -686,7 +689,7 @@ 'message': 'Generating Pulse stubs for dynamic loading.', }, ], - 'conditions': [ + 'conditions': [ # Linux/Solaris need libdl for dlopen() and friends. ['OS == "linux" or OS == "solaris"', { 'link_settings': { @@ -850,7 +853,7 @@ 'audio/audio_parameters_unittest.cc', 'audio/audio_util_unittest.cc', 'audio/cross_process_notification_unittest.cc', - 'audio/fake_audio_output_stream_unittest.cc', + 'audio/fake_audio_consumer_unittest.cc', 'audio/ios/audio_manager_ios_unittest.cc', 'audio/linux/alsa_output_unittest.cc', 'audio/mac/audio_device_listener_mac_unittest.cc', diff --git a/media/tools/player_x11/player_x11.cc b/media/tools/player_x11/player_x11.cc index 6fc4e47..7b6e5c5 100644 --- a/media/tools/player_x11/player_x11.cc +++ b/media/tools/player_x11/player_x11.cc @@ -128,7 +128,7 @@ bool InitPipeline(const scoped_refptr<base::MessageLoopProxy>& message_loop, scoped_ptr<media::AudioRenderer> audio_renderer(new media::AudioRendererImpl( message_loop, - new media::NullAudioSink(), + new media::NullAudioSink(message_loop), media::SetDecryptorReadyCB())); collection->SetAudioRenderer(audio_renderer.Pass()); diff --git a/webkit/media/webmediaplayer_impl.cc b/webkit/media/webmediaplayer_impl.cc index 981ed30..f4e3456 100644 --- a/webkit/media/webmediaplayer_impl.cc +++ b/webkit/media/webmediaplayer_impl.cc @@ -201,7 +201,7 @@ WebMediaPlayerImpl::WebMediaPlayerImpl( // Create default audio renderer using the null sink if no sink was provided. audio_source_provider_ = new WebAudioSourceProviderImpl( params.audio_renderer_sink() ? params.audio_renderer_sink() : - new media::NullAudioSink()); + new media::NullAudioSink(media_thread_.message_loop_proxy())); scoped_ptr<media::AudioRenderer> audio_renderer( new media::AudioRendererImpl( media_thread_.message_loop_proxy(), |