blob: eb65b9652a799e3cfbe530f0c778fe5cdc8e4e55 [file] [log] [blame]
// 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 <vector>
#include "base/message_loop.h"
#include "base/synchronization/waitable_event.h"
#include "media/audio/audio_manager.h"
#include "media/audio/simple_sources.h"
#include "media/audio/virtual_audio_input_stream.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace media {
class MockInputCallback : public AudioInputStream::AudioInputCallback {
public:
MockInputCallback() {}
virtual void OnData(AudioInputStream* stream, const uint8* data,
uint32 size, uint32 hardware_delay_bytes,
double volume) {}
virtual void OnClose(AudioInputStream* stream) {}
virtual void OnError(AudioInputStream* stream, int code) {}
private:
DISALLOW_COPY_AND_ASSIGN(MockInputCallback);
};
class VirtualAudioInputStreamTest : public testing::Test {
public:
VirtualAudioInputStreamTest()
: audio_manager_(AudioManager::Create()),
params_(
AudioParameters::AUDIO_VIRTUAL,CHANNEL_LAYOUT_MONO, 8000, 8, 128),
output_params_(
AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO, 8000, 8,
128),
stream_(NULL),
source_(CHANNEL_LAYOUT_STEREO, 200.0, 128),
done_(false, false) {
}
void StartStreamAndRunTestsOnAudioThread(int num_output_streams,
int num_callback_iterations,
int num_streams_removed_per_round,
int num_expected_source_callbacks) {
ASSERT_TRUE(audio_manager_->GetMessageLoop()->BelongsToCurrentThread());
stream_->Open();
stream_->Start(&input_callback_);
AddStreamsAndDoCallbacks(num_output_streams,
num_callback_iterations,
num_streams_removed_per_round,
num_expected_source_callbacks);
}
void AddStreamsAndDoCallbacks(int num_output_streams,
int num_callback_iterations,
int num_streams_removed_per_round,
int num_expected_source_callbacks) {
ASSERT_TRUE(audio_manager_->GetMessageLoop()->BelongsToCurrentThread());
for (int i = 0; i < num_output_streams; ++i) {
AudioOutputStream* output_stream =
audio_manager_->MakeAudioOutputStream(output_params_);
DCHECK(output_stream);
output_streams_.push_back(output_stream);
output_stream->Open();
output_stream->Start(&source_);
}
if (num_output_streams == 0 && num_streams_removed_per_round > 0) {
AudioOutputStream* output_stream = output_streams_.back();
output_streams_.pop_back();
output_stream->Stop();
output_stream->Close();
}
if (num_callback_iterations > 0) {
// Force the next callback to be immediate.
stream_->buffer_duration_ms_ = base::TimeDelta();
audio_manager_->GetMessageLoop()->PostTask(
FROM_HERE, base::Bind(
&VirtualAudioInputStreamTest::AddStreamsAndDoCallbacks,
base::Unretained(this),
0,
--num_callback_iterations,
num_streams_removed_per_round,
num_expected_source_callbacks));
} else {
// Finish the test.
EXPECT_EQ(num_expected_source_callbacks, source_.callbacks());
EXPECT_EQ(0, source_.errors());
for (std::vector<AudioOutputStream*>::iterator it =
output_streams_.begin(); it != output_streams_.end(); ++it)
(*it)->Stop();
stream_->Stop();
audio_manager_->GetMessageLoop()->PostTask(
FROM_HERE, base::Bind(&VirtualAudioInputStreamTest::EndTest,
base::Unretained(this)));
}
}
void OpenAndCloseOnAudioThread() {
ASSERT_TRUE(audio_manager_->GetMessageLoop()->BelongsToCurrentThread());
stream_->Open();
// Create 2 output streams, which we just open and close without starting.
const int num_output_stream = 2;
for (int i = 0; i < num_output_stream; ++i) {
AudioOutputStream* output_stream =
audio_manager_->MakeAudioOutputStream(output_params_);
DCHECK(output_stream);
output_streams_.push_back(output_stream);
output_stream->Open();
}
audio_manager_->GetMessageLoop()->PostTask(
FROM_HERE, base::Bind(&VirtualAudioInputStreamTest::EndTest,
base::Unretained(this)));
}
void StartStopOnAudioThread(int num_output_streams,
int num_callback_iterations,
int num_expected_source_callbacks) {
ASSERT_TRUE(audio_manager_->GetMessageLoop()->BelongsToCurrentThread());
stream_->Open();
stream_->Start(&input_callback_);
StartStopCallback(true, num_output_streams, num_callback_iterations,
num_expected_source_callbacks);
}
void StartStopCallback(bool init,
int num_output_streams,
int num_callback_iterations,
int num_expected_source_callbacks) {
ASSERT_TRUE(audio_manager_->GetMessageLoop()->BelongsToCurrentThread());
if (init) {
for (int i = 0; i < num_output_streams; ++i) {
AudioOutputStream* output_stream =
audio_manager_->MakeAudioOutputStream(output_params_);
DCHECK(output_stream);
output_streams_.push_back(output_stream);
output_stream->Open();
output_stream->Start(&source_);
}
// Start with an odd iteration number so we call Stop() first below.
DCHECK_NE(0, num_callback_iterations % 2);
}
// Start or stop half the streams.
for (int i = 0; i < num_output_streams / 2; ++i) {
if (num_callback_iterations % 2 != 0)
output_streams_[i]->Stop();
else
output_streams_[i]->Start(&source_);
}
if (num_callback_iterations > 0) {
// Force the next callback to be immediate.
stream_->buffer_duration_ms_ = base::TimeDelta::FromMilliseconds(0);
audio_manager_->GetMessageLoop()->PostTask(
FROM_HERE, base::Bind(
&VirtualAudioInputStreamTest::StartStopCallback,
base::Unretained(this),
false,
num_output_streams,
--num_callback_iterations,
num_expected_source_callbacks));
} else {
// Finish the test.
EXPECT_EQ(num_expected_source_callbacks, source_.callbacks());
EXPECT_EQ(0, source_.errors());
for (std::vector<AudioOutputStream*>::iterator it =
output_streams_.begin(); it != output_streams_.end(); ++it)
(*it)->Stop();
stream_->Stop();
audio_manager_->GetMessageLoop()->PostTask(FROM_HERE,
base::Bind(&VirtualAudioInputStreamTest::EndTest,
base::Unretained(this)));
}
}
void EndTest() {
for (std::vector<AudioOutputStream*>::iterator it =
output_streams_.begin(); it != output_streams_.end(); ++it)
(*it)->Close();
stream_->Close();
done_.Signal();
}
protected:
scoped_ptr<AudioManager> audio_manager_;
AudioParameters params_;
AudioParameters output_params_;
VirtualAudioInputStream* stream_;
MockInputCallback input_callback_;
std::vector<AudioOutputStream*> output_streams_;
SineWaveAudioSource source_;
base::WaitableEvent done_;
private:
DISALLOW_COPY_AND_ASSIGN(VirtualAudioInputStreamTest);
};
TEST_F(VirtualAudioInputStreamTest, AttachAndDriveSingleStream) {
stream_ = static_cast<VirtualAudioInputStream*>(
audio_manager_->MakeAudioInputStream(params_, "1"));
DCHECK(stream_);
const int num_output_streams = 1;
const int num_callback_iterations = 1;
const int num_streams_removed_per_round = 0;
const int num_expected_source_callbacks = 1;
audio_manager_->GetMessageLoop()->PostTask(
FROM_HERE, base::Bind(
&VirtualAudioInputStreamTest::StartStreamAndRunTestsOnAudioThread,
base::Unretained(this),
num_output_streams,
num_callback_iterations,
num_streams_removed_per_round,
num_expected_source_callbacks));
done_.Wait();
}
TEST_F(VirtualAudioInputStreamTest, AttachAndDriveMultipleStreams) {
stream_ = static_cast<VirtualAudioInputStream*>(
audio_manager_->MakeAudioInputStream(params_, "1"));
DCHECK(stream_);
const int num_output_streams = 5;
const int num_callback_iterations = 5;
const int num_streams_removed_per_round = 0;
const int num_expected_source_callbacks = 25;
audio_manager_->GetMessageLoop()->PostTask(
FROM_HERE, base::Bind(
&VirtualAudioInputStreamTest::StartStreamAndRunTestsOnAudioThread,
base::Unretained(this),
num_output_streams,
num_callback_iterations,
num_streams_removed_per_round,
num_expected_source_callbacks));
done_.Wait();
}
TEST_F(VirtualAudioInputStreamTest, AttachAndRemoveStreams) {
stream_ = static_cast<VirtualAudioInputStream*>(
audio_manager_->MakeAudioInputStream(params_, "1"));
DCHECK(stream_);
const int num_output_streams = 8;
const int num_callback_iterations = 5;
const int num_streams_removed_per_round = 1;
const int num_expected_source_callbacks = 8 + 7 + 6 + 5 + 4;
audio_manager_->GetMessageLoop()->PostTask(
FROM_HERE, base::Bind(
&VirtualAudioInputStreamTest::StartStreamAndRunTestsOnAudioThread,
base::Unretained(this),
num_output_streams,
num_callback_iterations,
num_streams_removed_per_round,
num_expected_source_callbacks));
done_.Wait();
}
// Opens/closes a VirtualAudioInputStream and a number of attached
// VirtualAudioOutputStreams without calling Start()/Stop().
TEST_F(VirtualAudioInputStreamTest, OpenAndClose) {
stream_ = static_cast<VirtualAudioInputStream*>(
audio_manager_->MakeAudioInputStream(params_, "1"));
DCHECK(stream_);
audio_manager_->GetMessageLoop()->PostTask(
FROM_HERE, base::Bind(
&VirtualAudioInputStreamTest::OpenAndCloseOnAudioThread,
base::Unretained(this)));
done_.Wait();
}
// Creates and closes and VirtualAudioInputStream.
TEST_F(VirtualAudioInputStreamTest, CreateAndClose) {
stream_ = static_cast<VirtualAudioInputStream*>(
audio_manager_->MakeAudioInputStream(params_, "1"));
DCHECK(stream_);
audio_manager_->GetMessageLoop()->PostTask(
FROM_HERE, base::Bind(&VirtualAudioInputStreamTest::EndTest,
base::Unretained(this)));
done_.Wait();
}
// Starts and stops VirtualAudioOutputStreams while attached to a
// VirtualAudioInputStream.
TEST_F(VirtualAudioInputStreamTest, AttachAndStartStopStreams) {
stream_ = static_cast<VirtualAudioInputStream*>(
audio_manager_->MakeAudioInputStream(params_, "1"));
DCHECK(stream_);
const int num_output_streams = 4;
const int num_callback_iterations = 5;
const int num_expected_source_callbacks = 2 + 4 + 2 + 4 + 2;
audio_manager_->GetMessageLoop()->PostTask(
FROM_HERE, base::Bind(
&VirtualAudioInputStreamTest::StartStopOnAudioThread,
base::Unretained(this),
num_output_streams,
num_callback_iterations,
num_expected_source_callbacks));
done_.Wait();
}
} // namespace media