summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--media/audio/fake_audio_consumer.cc67
-rw-r--r--media/audio/fake_audio_consumer.h61
-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.cc34
-rw-r--r--media/audio/fake_audio_output_stream.h17
-rw-r--r--media/audio/null_audio_sink.cc129
-rw-r--r--media/audio/null_audio_sink.h42
-rw-r--r--media/filters/pipeline_integration_test_base.cc2
-rw-r--r--media/media.gyp7
-rw-r--r--media/tools/player_x11/player_x11.cc2
-rw-r--r--webkit/media/webmediaplayer_impl.cc2
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(),