blob: 74e0e684b374fbfc19a0ee90b8bd16a4e8dc03b6 [file] [log] [blame]
// Copyright (c) 2011 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 "base/bind.h"
#include "base/environment.h"
#include "base/basictypes.h"
#include "base/logging.h"
#include "base/task.h"
#include "base/synchronization/waitable_event.h"
#include "media/audio/audio_output_controller.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::_;
using ::testing::AtLeast;
using ::testing::DoAll;
using ::testing::Exactly;
using ::testing::InvokeWithoutArgs;
using ::testing::NotNull;
using ::testing::Return;
static const int kSampleRate = AudioParameters::kAudioCDSampleRate;
static const int kBitsPerSample = 16;
static const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_STEREO;
static const int kSamplesPerPacket = kSampleRate / 10;
static const int kHardwareBufferSize = kSamplesPerPacket *
ChannelLayoutToChannelCount(kChannelLayout) * kBitsPerSample / 8;
static const int kBufferCapacity = 3 * kHardwareBufferSize;
namespace media {
class MockAudioOutputControllerEventHandler
: public AudioOutputController::EventHandler {
public:
MockAudioOutputControllerEventHandler() {}
MOCK_METHOD1(OnCreated, void(AudioOutputController* controller));
MOCK_METHOD1(OnPlaying, void(AudioOutputController* controller));
MOCK_METHOD1(OnPaused, void(AudioOutputController* controller));
MOCK_METHOD2(OnError, void(AudioOutputController* controller,
int error_code));
MOCK_METHOD2(OnMoreData, void(AudioOutputController* controller,
AudioBuffersState buffers_state));
private:
DISALLOW_COPY_AND_ASSIGN(MockAudioOutputControllerEventHandler);
};
class MockAudioOutputControllerSyncReader
: public AudioOutputController::SyncReader {
public:
MockAudioOutputControllerSyncReader() {}
MOCK_METHOD1(UpdatePendingBytes, void(uint32 bytes));
MOCK_METHOD2(Read, uint32(void* data, uint32 size));
MOCK_METHOD0(Close, void());
MOCK_METHOD0(DataReady, bool());
private:
DISALLOW_COPY_AND_ASSIGN(MockAudioOutputControllerSyncReader);
};
static bool HasAudioOutputDevices() {
AudioManager* audio_man = AudioManager::GetAudioManager();
CHECK(audio_man);
return audio_man->HasAudioOutputDevices();
}
static bool IsRunningHeadless() {
scoped_ptr<base::Environment> env(base::Environment::Create());
if (env->HasVar("CHROME_HEADLESS"))
return true;
return false;
}
ACTION_P(SignalEvent, event) {
event->Signal();
}
// Helper functions used to close audio controller.
static void SignalClosedEvent(base::WaitableEvent* event) {
event->Signal();
}
// Closes AudioOutputController synchronously.
static void CloseAudioController(AudioOutputController* controller) {
base::WaitableEvent closed_event(true, false);
controller->Close(base::Bind(&SignalClosedEvent, &closed_event));
closed_event.Wait();
}
TEST(AudioOutputControllerTest, CreateAndClose) {
if (!HasAudioOutputDevices() || IsRunningHeadless())
return;
MockAudioOutputControllerEventHandler event_handler;
EXPECT_CALL(event_handler, OnCreated(NotNull()))
.Times(1);
EXPECT_CALL(event_handler, OnMoreData(NotNull(), _));
AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout,
kSampleRate, kBitsPerSample, kSamplesPerPacket);
scoped_refptr<AudioOutputController> controller =
AudioOutputController::Create(&event_handler, params, kBufferCapacity);
ASSERT_TRUE(controller.get());
// Close the controller immediately.
CloseAudioController(controller);
}
TEST(AudioOutputControllerTest, PlayAndClose) {
if (!HasAudioOutputDevices() || IsRunningHeadless())
return;
MockAudioOutputControllerEventHandler event_handler;
base::WaitableEvent event(false, false);
// If OnCreated is called then signal the event.
EXPECT_CALL(event_handler, OnCreated(NotNull()))
.WillOnce(SignalEvent(&event));
// OnPlaying() will be called only once.
EXPECT_CALL(event_handler, OnPlaying(NotNull()))
.Times(Exactly(1));
// If OnMoreData is called enough then signal the event.
EXPECT_CALL(event_handler, OnMoreData(NotNull(), _))
.Times(AtLeast(10))
.WillRepeatedly(SignalEvent(&event));
AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout,
kSampleRate, kBitsPerSample, kSamplesPerPacket);
scoped_refptr<AudioOutputController> controller =
AudioOutputController::Create(&event_handler, params, kBufferCapacity);
ASSERT_TRUE(controller.get());
// Wait for OnCreated() to be called.
event.Wait();
controller->Play();
// Wait until the date is requested at least 10 times.
for (int i = 0; i < 10; i++) {
event.Wait();
uint8 buf[1];
controller->EnqueueData(buf, 0);
}
// Now stop the controller.
CloseAudioController(controller);
}
TEST(AudioOutputControllerTest, PlayAndCloseLowLatency) {
if (!HasAudioOutputDevices() || IsRunningHeadless())
return;
MockAudioOutputControllerEventHandler event_handler;
base::WaitableEvent event(false, false);
// If OnCreated is called then signal the event.
EXPECT_CALL(event_handler, OnCreated(NotNull()))
.WillOnce(SignalEvent(&event));
// OnPlaying() will be called only once.
EXPECT_CALL(event_handler, OnPlaying(NotNull()))
.Times(Exactly(1));
MockAudioOutputControllerSyncReader sync_reader;
EXPECT_CALL(sync_reader, UpdatePendingBytes(_))
.Times(AtLeast(10));
EXPECT_CALL(sync_reader, DataReady())
.WillOnce(Return(false))
.WillOnce(Return(false))
.WillRepeatedly(Return(true));
EXPECT_CALL(sync_reader, Read(_, kHardwareBufferSize))
.Times(AtLeast(10))
.WillRepeatedly(DoAll(SignalEvent(&event),
Return(4)));
EXPECT_CALL(sync_reader, Close());
AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout,
kSampleRate, kBitsPerSample, kSamplesPerPacket);
scoped_refptr<AudioOutputController> controller =
AudioOutputController::CreateLowLatency(&event_handler,
params,
&sync_reader);
ASSERT_TRUE(controller.get());
// Wait for OnCreated() to be called.
event.Wait();
controller->Play();
// Wait until the date is requested at least 10 times.
for (int i = 0; i < 10; i++) {
event.Wait();
uint8 buf[1];
controller->EnqueueData(buf, 0);
}
// Now stop the controller.
CloseAudioController(controller);
}
TEST(AudioOutputControllerTest, PlayPauseClose) {
if (!HasAudioOutputDevices() || IsRunningHeadless())
return;
MockAudioOutputControllerEventHandler event_handler;
base::WaitableEvent event(false, false);
base::WaitableEvent pause_event(false, false);
// If OnCreated is called then signal the event.
EXPECT_CALL(event_handler, OnCreated(NotNull()))
.Times(Exactly(1))
.WillOnce(InvokeWithoutArgs(&event, &base::WaitableEvent::Signal));
// OnPlaying() will be called only once.
EXPECT_CALL(event_handler, OnPlaying(NotNull()))
.Times(Exactly(1));
// If OnMoreData is called enough then signal the event.
EXPECT_CALL(event_handler, OnMoreData(NotNull(), _))
.Times(AtLeast(10))
.WillRepeatedly(SignalEvent(&event));
// And then OnPaused() will be called.
EXPECT_CALL(event_handler, OnPaused(NotNull()))
.Times(Exactly(1))
.WillOnce(InvokeWithoutArgs(&pause_event, &base::WaitableEvent::Signal));
AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout,
kSampleRate, kBitsPerSample, kSamplesPerPacket);
scoped_refptr<AudioOutputController> controller =
AudioOutputController::Create(&event_handler, params, kBufferCapacity);
ASSERT_TRUE(controller.get());
// Wait for OnCreated() to be called.
event.Wait();
controller->Play();
// Wait until the date is requested at least 10 times.
for (int i = 0; i < 10; i++) {
event.Wait();
uint8 buf[1];
controller->EnqueueData(buf, 0);
}
// And then wait for pause to complete.
ASSERT_FALSE(pause_event.IsSignaled());
controller->Pause();
pause_event.Wait();
// Now stop the controller.
CloseAudioController(controller);
}
TEST(AudioOutputControllerTest, PlayPauseCloseLowLatency) {
if (!HasAudioOutputDevices() || IsRunningHeadless())
return;
MockAudioOutputControllerEventHandler event_handler;
base::WaitableEvent event(false, false);
base::WaitableEvent pause_event(false, false);
// If OnCreated is called then signal the event.
EXPECT_CALL(event_handler, OnCreated(NotNull()))
.WillOnce(InvokeWithoutArgs(&event, &base::WaitableEvent::Signal));
// OnPlaying() will be called only once.
EXPECT_CALL(event_handler, OnPlaying(NotNull()));
MockAudioOutputControllerSyncReader sync_reader;
EXPECT_CALL(sync_reader, UpdatePendingBytes(_))
.Times(AtLeast(2));
EXPECT_CALL(sync_reader, Read(_, kHardwareBufferSize))
.WillRepeatedly(DoAll(SignalEvent(&event),
Return(4)));
EXPECT_CALL(event_handler, OnPaused(NotNull()))
.WillOnce(InvokeWithoutArgs(&pause_event, &base::WaitableEvent::Signal));
EXPECT_CALL(sync_reader, Close());
AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout,
kSampleRate, kBitsPerSample, kSamplesPerPacket);
scoped_refptr<AudioOutputController> controller =
AudioOutputController::CreateLowLatency(&event_handler,
params,
&sync_reader);
ASSERT_TRUE(controller.get());
// Wait for OnCreated() to be called.
event.Wait();
ASSERT_FALSE(pause_event.IsSignaled());
controller->Play();
controller->Pause();
pause_event.Wait();
// Now stop the controller.
CloseAudioController(controller);
}
TEST(AudioOutputControllerTest, PlayPausePlay) {
if (!HasAudioOutputDevices() || IsRunningHeadless())
return;
MockAudioOutputControllerEventHandler event_handler;
base::WaitableEvent event(false, false);
base::WaitableEvent pause_event(false, false);
// If OnCreated is called then signal the event.
EXPECT_CALL(event_handler, OnCreated(NotNull()))
.Times(Exactly(1))
.WillOnce(InvokeWithoutArgs(&event, &base::WaitableEvent::Signal));
// OnPlaying() will be called only once.
EXPECT_CALL(event_handler, OnPlaying(NotNull()))
.Times(Exactly(1))
.RetiresOnSaturation();
// If OnMoreData() is called enough then signal the event.
EXPECT_CALL(event_handler, OnMoreData(NotNull(), _))
.Times(AtLeast(1))
.WillRepeatedly(SignalEvent(&event));
// And then OnPaused() will be called.
EXPECT_CALL(event_handler, OnPaused(NotNull()))
.Times(Exactly(1))
.WillOnce(InvokeWithoutArgs(&pause_event, &base::WaitableEvent::Signal));
// OnPlaying() will be called only once.
EXPECT_CALL(event_handler, OnPlaying(NotNull()))
.Times(Exactly(1))
.RetiresOnSaturation();
AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout,
kSampleRate, kBitsPerSample, kSamplesPerPacket);
scoped_refptr<AudioOutputController> controller =
AudioOutputController::Create(&event_handler, params, kBufferCapacity);
ASSERT_TRUE(controller.get());
// Wait for OnCreated() to be called.
event.Wait();
controller->Play();
// Wait until the date is requested at least 10 times.
for (int i = 0; i < 10; i++) {
event.Wait();
uint8 buf[1];
controller->EnqueueData(buf, 0);
}
// And then wait for pause to complete.
ASSERT_FALSE(pause_event.IsSignaled());
controller->Pause();
pause_event.Wait();
// Then we play again.
controller->Play();
// Wait until the date is requested at least 10 times.
for (int i = 0; i < 10; i++) {
event.Wait();
uint8 buf[1];
controller->EnqueueData(buf, 0);
}
// Now stop the controller.
CloseAudioController(controller);
}
TEST(AudioOutputControllerTest, HardwareBufferTooLarge) {
if (!HasAudioOutputDevices() || IsRunningHeadless())
return;
// Create an audio device with a very large hardware buffer size.
MockAudioOutputControllerEventHandler event_handler;
AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout,
kSampleRate, kBitsPerSample,
kSamplesPerPacket * 1000);
scoped_refptr<AudioOutputController> controller =
AudioOutputController::Create(&event_handler, params,
kBufferCapacity);
// Use assert because we don't stop the device and assume we can't
// create one.
ASSERT_FALSE(controller);
}
TEST(AudioOutputControllerTest, CloseTwice) {
if (!HasAudioOutputDevices() || IsRunningHeadless())
return;
MockAudioOutputControllerEventHandler event_handler;
base::WaitableEvent event(false, false);
// If OnCreated is called then signal the event.
EXPECT_CALL(event_handler, OnCreated(NotNull()))
.WillOnce(SignalEvent(&event));
// One OnMoreData() is expected.
EXPECT_CALL(event_handler, OnMoreData(NotNull(), _))
.Times(AtLeast(1))
.WillRepeatedly(SignalEvent(&event));
AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout,
kSampleRate, kBitsPerSample, kSamplesPerPacket);
scoped_refptr<AudioOutputController> controller =
AudioOutputController::Create(&event_handler, params, kBufferCapacity);
ASSERT_TRUE(controller.get());
// Wait for OnCreated() to be called.
event.Wait();
// Wait for OnMoreData() to be called.
event.Wait();
base::WaitableEvent closed_event_1(true, false);
controller->Close(base::Bind(&SignalClosedEvent, &closed_event_1));
base::WaitableEvent closed_event_2(true, false);
controller->Close(base::Bind(&SignalClosedEvent, &closed_event_2));
closed_event_1.Wait();
closed_event_2.Wait();
}
} // namespace media