blob: 25dd7e616fe00dc000eed67c1283f0e43c4887c7 [file] [log] [blame]
// Copyright (c) 2006-2008 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 <windows.h>
#include "base/basictypes.h"
#include "base/logging.h"
#include "media/audio/audio_output.h"
#include "media/audio/simple_sources.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
// This class allows to find out if the callbacks are occurring as
// expected and if any error has been reported.
class TestSourceBasic : public AudioOutputStream::AudioSourceCallback {
public:
explicit TestSourceBasic()
: callback_count_(0),
had_error_(0),
was_closed_(0) {
}
// AudioSourceCallback::OnMoreData implementation:
virtual size_t OnMoreData(AudioOutputStream* stream,
void* dest, size_t max_size) {
++callback_count_;
// Touch the first byte to make sure memory is good.
if (max_size)
reinterpret_cast<char*>(dest)[0] = 1;
return max_size;
}
// AudioSourceCallback::OnClose implementation:
virtual void OnClose(AudioOutputStream* stream) {
++was_closed_;
}
// AudioSourceCallback::OnError implementation:
virtual void OnError(AudioOutputStream* stream, int code) {
++had_error_;
}
// Returns how many times OnMoreData() has been called.
int callback_count() const {
return callback_count_;
}
// Returns how many times the OnError callback was called.
int had_error() const {
return had_error_;
}
void set_error(bool error) {
had_error_ += error ? 1 : 0;
}
// Returns how many times the OnClose callback was called.
int was_closed() const {
return was_closed_;
}
private:
int callback_count_;
int had_error_;
int was_closed_;
};
bool IsRunningHeadless() {
return (0 != ::GetEnvironmentVariableW(L"CHROME_HEADLESS", NULL, 0));
}
} // namespace.
// Specializes TestSourceBasic to detect that the AudioStream is using
// double buffering correctly.
class TestSourceDoubleBuffer : public TestSourceBasic {
public:
TestSourceDoubleBuffer() {
buffer_address_[0] = NULL;
buffer_address_[1] = NULL;
}
// Override of TestSourceBasic::OnMoreData.
virtual size_t OnMoreData(AudioOutputStream* stream,
void* dest, size_t max_size) {
// Call the base, which increments the callback_count_.
TestSourceBasic::OnMoreData(stream, dest, max_size);
if (callback_count() % 2) {
set_error(!CompareExistingIfNotNULL(1, dest));
} else {
set_error(!CompareExistingIfNotNULL(0, dest));
}
if (callback_count() > 2) {
set_error(buffer_address_[0] == buffer_address_[1]);
}
return max_size;
}
private:
bool CompareExistingIfNotNULL(size_t index, void* address) {
void*& entry = buffer_address_[index];
if (!entry)
entry = address;
return (entry == address);
}
void* buffer_address_[2];
};
// ============================================================================
// Validate that the AudioManager::AUDIO_MOCK callbacks work.
TEST(WinAudioTest, MockStreamBasicCallbacks) {
AudioManager* audio_man = AudioManager::GetAudioManager();
ASSERT_TRUE(NULL != audio_man);
AudioOutputStream* oas =
audio_man->MakeAudioStream(AudioManager::AUDIO_MOCK, 2, 8000, 8);
ASSERT_TRUE(NULL != oas);
EXPECT_TRUE(oas->Open(256));
TestSourceBasic source;
oas->Start(&source);
EXPECT_GT(source.callback_count(), 0);
oas->Stop();
oas->Close();
EXPECT_EQ(0, source.had_error());
EXPECT_EQ(1, source.was_closed());
}
// Validate that the SineWaveAudioSource writes the expected values for
// the FORMAT_16BIT_MONO. The values are carefully selected so rounding issues
// do not affect the result. We also test that AudioManager::GetLastMockBuffer
// works.
TEST(WinAudioTest, SineWaveAudio16MonoTest) {
const size_t samples = 1024;
const size_t bytes_per_sample = 2;
const int freq = 200;
SineWaveAudioSource source(SineWaveAudioSource::FORMAT_16BIT_LINEAR_PCM, 1,
freq, AudioManager::kTelephoneSampleRate);
AudioManager* audio_man = AudioManager::GetAudioManager();
ASSERT_TRUE(NULL != audio_man);
AudioOutputStream* oas =
audio_man->MakeAudioStream(AudioManager::AUDIO_MOCK, 1,
AudioManager::kTelephoneSampleRate,
bytes_per_sample * 2);
ASSERT_TRUE(NULL != oas);
EXPECT_TRUE(oas->Open(samples * bytes_per_sample));
oas->Start(&source);
oas->Stop();
oas->Close();
const int16* last_buffer =
reinterpret_cast<const int16*>(audio_man->GetLastMockBuffer());
ASSERT_TRUE(NULL != last_buffer);
size_t half_period = AudioManager::kTelephoneSampleRate / (freq * 2);
// Spot test positive incursion of sine wave.
EXPECT_EQ(0, last_buffer[0]);
EXPECT_EQ(5126, last_buffer[1]);
EXPECT_TRUE(last_buffer[1] < last_buffer[2]);
EXPECT_TRUE(last_buffer[2] < last_buffer[3]);
// Spot test negative incursion of sine wave.
EXPECT_EQ(0, last_buffer[half_period]);
EXPECT_EQ(-5126, last_buffer[half_period + 1]);
EXPECT_TRUE(last_buffer[half_period + 1] > last_buffer[half_period + 2]);
EXPECT_TRUE(last_buffer[half_period + 2] > last_buffer[half_period + 3]);
}
// ===========================================================================
// Validation of AudioManager::AUDIO_PCM_LINEAR
//
// The tests tend to fail in the build bots when somebody connects to them via
// via remote-desktop because it installs an audio device that fails to open
// at some point, possibly when the connection goes idle. So that is why we
// skipped them in headless mode.
// Test that can it be created and closed.
TEST(WinAudioTest, PCMWaveStreamGetAndClose) {
if (IsRunningHeadless())
return;
AudioManager* audio_man = AudioManager::GetAudioManager();
ASSERT_TRUE(NULL != audio_man);
if (!audio_man->HasAudioDevices())
return;
AudioOutputStream* oas =
audio_man->MakeAudioStream(AudioManager::AUDIO_PCM_LINEAR, 2, 8000, 16);
ASSERT_TRUE(NULL != oas);
oas->Close();
}
// Test that it can be opened and closed.
TEST(WinAudioTest, PCMWaveStreamOpenAndClose) {
if (IsRunningHeadless())
return;
AudioManager* audio_man = AudioManager::GetAudioManager();
ASSERT_TRUE(NULL != audio_man);
if (!audio_man->HasAudioDevices())
return;
AudioOutputStream* oas =
audio_man->MakeAudioStream(AudioManager::AUDIO_PCM_LINEAR, 2, 8000, 16);
ASSERT_TRUE(NULL != oas);
EXPECT_TRUE(oas->Open(1024));
oas->Close();
}
// Test that it uses the double buffers correctly. Because it uses the actual
// audio device, you might hear a short pop noise for a short time.
TEST(WinAudioTest, PCMWaveStreamDoubleBuffer) {
if (IsRunningHeadless())
return;
AudioManager* audio_man = AudioManager::GetAudioManager();
ASSERT_TRUE(NULL != audio_man);
if (!audio_man->HasAudioDevices())
return;
AudioOutputStream* oas =
audio_man->MakeAudioStream(AudioManager::AUDIO_PCM_LINEAR, 1, 16000, 16);
ASSERT_TRUE(NULL != oas);
TestSourceDoubleBuffer test_double_buffer;
EXPECT_TRUE(oas->Open(512));
oas->Start(&test_double_buffer);
::Sleep(300);
EXPECT_GT(test_double_buffer.callback_count(), 2);
EXPECT_FALSE(test_double_buffer.had_error());
oas->Stop();
::Sleep(1000);
oas->Close();
}
// This test produces actual audio for 1.5 seconds on the default wave
// device at 44.1K s/sec. Parameters have been chosen carefully so you should
// not hear pops or noises while the sound is playing.
TEST(WinAudioTest, PCMWaveStreamPlay200HzTone44Kss) {
if (IsRunningHeadless())
return;
AudioManager* audio_man = AudioManager::GetAudioManager();
ASSERT_TRUE(NULL != audio_man);
if (!audio_man->HasAudioDevices())
return;
AudioOutputStream* oas =
audio_man->MakeAudioStream(AudioManager::AUDIO_PCM_LINEAR, 1,
AudioManager::kAudioCDSampleRate, 16);
ASSERT_TRUE(NULL != oas);
SineWaveAudioSource source(SineWaveAudioSource::FORMAT_16BIT_LINEAR_PCM, 1,
200.0, AudioManager::kAudioCDSampleRate);
size_t bytes_100_ms = (AudioManager::kAudioCDSampleRate / 10) * 2;
EXPECT_TRUE(oas->Open(bytes_100_ms));
oas->Start(&source);
::Sleep(1500);
oas->Stop();
oas->Close();
}
// This test produces actual audio for for 1.5 seconds on the default wave
// device at 22K s/sec. Parameters have been chosen carefully so you should
// not hear pops or noises while the sound is playing.
TEST(WinAudioTest, PCMWaveStreamPlay200HzTone22Kss) {
if (IsRunningHeadless())
return;
AudioManager* audio_man = AudioManager::GetAudioManager();
ASSERT_TRUE(NULL != audio_man);
if (!audio_man->HasAudioDevices())
return;
AudioOutputStream* oas =
audio_man->MakeAudioStream(AudioManager::AUDIO_PCM_LINEAR, 1,
AudioManager::kAudioCDSampleRate/2, 16);
ASSERT_TRUE(NULL != oas);
SineWaveAudioSource source(SineWaveAudioSource::FORMAT_16BIT_LINEAR_PCM, 1,
200.0, AudioManager::kAudioCDSampleRate/2);
size_t bytes_100_ms = (AudioManager::kAudioCDSampleRate / 20) * 2;
EXPECT_TRUE(oas->Open(bytes_100_ms));
oas->Start(&source);
::Sleep(1500);
oas->Stop();
oas->Close();
}