summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--media/audio/fake_audio_output_stream.cc27
-rw-r--r--media/audio/fake_audio_output_stream.h4
-rw-r--r--media/audio/fake_audio_output_stream_unittest.cc53
3 files changed, 50 insertions, 34 deletions
diff --git a/media/audio/fake_audio_output_stream.cc b/media/audio/fake_audio_output_stream.cc
index c21026d..8db548c 100644
--- a/media/audio/fake_audio_output_stream.cc
+++ b/media/audio/fake_audio_output_stream.cc
@@ -23,9 +23,10 @@ FakeAudioOutputStream::FakeAudioOutputStream(AudioManagerBase* manager,
: audio_manager_(manager),
callback_(NULL),
audio_bus_(AudioBus::Create(params)),
- frames_per_millisecond_(
- params.sample_rate() / static_cast<float>(
- base::Time::kMillisecondsPerSecond)) {
+ buffer_duration_(base::TimeDelta::FromMicroseconds(
+ params.frames_per_buffer() * base::Time::kMicrosecondsPerSecond /
+ static_cast<float>(params.sample_rate()))) {
+ audio_bus_->Zero();
}
FakeAudioOutputStream::~FakeAudioOutputStream() {
@@ -40,6 +41,7 @@ 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(
@@ -68,15 +70,20 @@ void FakeAudioOutputStream::OnMoreDataTask() {
DCHECK(audio_manager_->GetMessageLoop()->BelongsToCurrentThread());
DCHECK(callback_);
- audio_bus_->Zero();
- int frames_received = callback_->OnMoreData(
- audio_bus_.get(), AudioBuffersState());
+ 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;
- // Calculate our sleep duration for simulated playback. Sleep for at least
- // one millisecond so we don't spin the CPU.
audio_manager_->GetMessageLoop()->PostDelayedTask(
- FROM_HERE, on_more_data_cb_.callback(), base::TimeDelta::FromMilliseconds(
- std::max(1.0f, frames_received / frames_per_millisecond_)));
+ FROM_HERE, on_more_data_cb_.callback(), delay);
}
} // namespace media
diff --git a/media/audio/fake_audio_output_stream.h b/media/audio/fake_audio_output_stream.h
index d188b9f..ec3a592 100644
--- a/media/audio/fake_audio_output_stream.h
+++ b/media/audio/fake_audio_output_stream.h
@@ -7,6 +7,7 @@
#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"
@@ -42,7 +43,8 @@ class MEDIA_EXPORT FakeAudioOutputStream : public AudioOutputStream {
AudioManagerBase* audio_manager_;
AudioSourceCallback* callback_;
scoped_ptr<AudioBus> audio_bus_;
- float frames_per_millisecond_;
+ 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_;
diff --git a/media/audio/fake_audio_output_stream_unittest.cc b/media/audio/fake_audio_output_stream_unittest.cc
index 6838e3f..8b37b86 100644
--- a/media/audio/fake_audio_output_stream_unittest.cc
+++ b/media/audio/fake_audio_output_stream_unittest.cc
@@ -13,19 +13,21 @@
namespace media {
+static const int kTestCallbacks = 5;
+
class FakeAudioOutputStreamTest : public testing::Test {
public:
FakeAudioOutputStreamTest()
: audio_manager_(AudioManager::Create()),
params_(
- AudioParameters::AUDIO_FAKE, CHANNEL_LAYOUT_STEREO, 8000, 8, 128),
+ 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_);
- time_between_callbacks_ = base::TimeDelta::FromMilliseconds(
- params_.frames_per_buffer() * base::Time::kMillisecondsPerSecond /
+ time_between_callbacks_ = base::TimeDelta::FromMicroseconds(
+ params_.frames_per_buffer() * base::Time::kMicrosecondsPerSecond /
static_cast<float>(params_.sample_rate()));
}
@@ -64,11 +66,10 @@ class FakeAudioOutputStreamTest : public testing::Test {
if (source_.callbacks() < callbacks) {
audio_manager_->GetMessageLoop()->PostDelayedTask(FROM_HERE, base::Bind(
&FakeAudioOutputStreamTest::TimeCallbacksOnAudioThread,
- base::Unretained(this), callbacks), time_between_callbacks_);
+ base::Unretained(this), callbacks), time_between_callbacks_ / 2);
} else {
- audio_manager_->GetMessageLoop()->PostTask(FROM_HERE, base::Bind(
- &FakeAudioOutputStreamTest::EndTest, base::Unretained(this),
- callbacks));
+ end_time_ = base::Time::Now();
+ EndTest(callbacks);
}
}
@@ -88,6 +89,7 @@ class FakeAudioOutputStreamTest : public testing::Test {
SineWaveAudioSource source_;
base::WaitableEvent done_;
base::Time start_time_;
+ base::Time end_time_;
base::TimeDelta time_between_callbacks_;
private:
@@ -105,36 +107,41 @@ TEST_F(FakeAudioOutputStreamTest, FakeStreamBasicCallback) {
// Ensure the time between callbacks is sane.
TEST_F(FakeAudioOutputStreamTest, TimeBetweenCallbacks) {
- static const int kTestCallbacks = 5;
-
audio_manager_->GetMessageLoop()->PostTask(FROM_HERE, base::Bind(
&FakeAudioOutputStreamTest::TimeCallbacksOnAudioThread,
base::Unretained(this), kTestCallbacks));
- // Let the loop run for a second or two then issue Stop() / Start().
- audio_manager_->GetMessageLoop()->PostDelayedTask(FROM_HERE, base::Bind(
- &FakeAudioOutputStreamTest::StopStartOnAudioThread,
- base::Unretained(this)), time_between_callbacks_);
-
done_.Wait();
- base::TimeDelta elapsed = base::Time::Now() - start_time_;
-
// There are only (kTestCallbacks - 1) intervals between kTestCallbacks.
- float actual_time_between_callbacks_ms =
- elapsed.InMillisecondsF() / (kTestCallbacks - 1);
- float expected_time_between_callbacks_ms =
- time_between_callbacks_.InMillisecondsF();
+ base::TimeDelta actual_time_between_callbacks =
+ (end_time_ - start_time_) / (kTestCallbacks - 1);
// Ensure callback time is no faster than the expected time between callbacks.
- EXPECT_GE(actual_time_between_callbacks_ms,
- expected_time_between_callbacks_ms);
+ EXPECT_TRUE(actual_time_between_callbacks >= time_between_callbacks_);
// Softly check if the callback time is no slower than twice the expected time
// between callbacks. Since this test runs on the bots we can't be too strict
// with the bounds.
- if (actual_time_between_callbacks_ms > 2 * expected_time_between_callbacks_ms)
+ if (actual_time_between_callbacks > 2 * time_between_callbacks_)
LOG(ERROR) << "Time between fake audio callbacks is too large!";
}
+// 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,
+ 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,
+ base::Unretained(this)), time_between_callbacks_ / 2);
+
+ // EndTest() will ensure the proper number of callbacks have occurred.
+ done_.Wait();
+}
+
} // namespace media