blob: 23c85e5918c6ae5737de1738078d49d3cf63229a [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 <windows.h>
#include <mmsystem.h>
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include "base/base_paths.h"
#include "base/memory/aligned_memory.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/sync_socket.h"
#include "base/time/time.h"
#include "base/win/scoped_com_initializer.h"
#include "base/win/windows_version.h"
#include "media/audio/audio_io.h"
#include "media/audio/audio_manager.h"
#include "media/audio/audio_unittest_util.h"
#include "media/audio/mock_audio_source_callback.h"
#include "media/audio/simple_sources.h"
#include "media/base/limits.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::_;
using ::testing::AnyNumber;
using ::testing::DoAll;
using ::testing::Field;
using ::testing::Invoke;
using ::testing::InSequence;
using ::testing::NiceMock;
using ::testing::NotNull;
using ::testing::Return;
namespace media {
static int ClearData(base::TimeDelta /* delay */,
base::TimeTicks /* delay_timestamp */,
int /* prior_frames_skipped */,
AudioBus* dest) {
dest->Zero();
return dest->frames();
}
// 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:
TestSourceBasic()
: callback_count_(0),
had_error_(0) {
}
// AudioSourceCallback::OnMoreData implementation:
int OnMoreData(base::TimeDelta /* delay */,
base::TimeTicks /* delay_timestamp */,
int /* prior_frames_skipped */,
AudioBus* dest) override {
++callback_count_;
// Touch the channel memory value to make sure memory is good.
dest->Zero();
return dest->frames();
}
// AudioSourceCallback::OnError implementation:
void OnError(AudioOutputStream* stream) override { ++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;
}
private:
int callback_count_;
int had_error_;
};
const int kMaxNumBuffers = 3;
// Specializes TestSourceBasic to simulate a source that blocks for some time
// in the OnMoreData callback.
class TestSourceLaggy : public TestSourceBasic {
public:
explicit TestSourceLaggy(int lag_in_ms)
: lag_in_ms_(lag_in_ms) {
}
int OnMoreData(base::TimeDelta delay,
base::TimeTicks delay_timestamp,
int prior_frames_skipped,
AudioBus* dest) override {
// Call the base, which increments the callback_count_.
TestSourceBasic::OnMoreData(delay, delay_timestamp, prior_frames_skipped,
dest);
if (callback_count() > kMaxNumBuffers) {
::Sleep(lag_in_ms_);
}
return dest->frames();
}
private:
int lag_in_ms_;
};
// Helper class to memory map an entire file. The mapping is read-only. Don't
// use for gigabyte-sized files. Attempts to write to this memory generate
// memory access violations.
class ReadOnlyMappedFile {
public:
explicit ReadOnlyMappedFile(const wchar_t* file_name)
: fmap_(NULL), start_(NULL), size_(0) {
HANDLE file = ::CreateFileW(file_name, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE == file)
return;
fmap_ = ::CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
::CloseHandle(file);
if (!fmap_)
return;
start_ = reinterpret_cast<char*>(::MapViewOfFile(fmap_, FILE_MAP_READ,
0, 0, 0));
if (!start_)
return;
MEMORY_BASIC_INFORMATION mbi = {0};
::VirtualQuery(start_, &mbi, sizeof(mbi));
size_ = mbi.RegionSize;
}
~ReadOnlyMappedFile() {
if (start_) {
::UnmapViewOfFile(start_);
::CloseHandle(fmap_);
}
}
// Returns true if the file was successfully mapped.
bool is_valid() const { return (start_ && (size_ > 0)); }
// Returns the size in bytes of the mapped memory.
uint32_t size() const { return size_; }
// Returns the memory backing the file.
const void* GetChunkAt(uint32_t offset) { return &start_[offset]; }
private:
HANDLE fmap_;
char* start_;
uint32_t size_;
};
class WinAudioTest : public ::testing::Test {
public:
WinAudioTest() {
audio_manager_ =
AudioManager::CreateForTesting(message_loop_.task_runner());
base::RunLoop().RunUntilIdle();
}
~WinAudioTest() override {
audio_manager_.reset();
base::RunLoop().RunUntilIdle();
}
protected:
base::MessageLoop message_loop_;
ScopedAudioManagerPtr audio_manager_;
};
// ===========================================================================
// Validation of AudioManager::AUDIO_PCM_LINEAR
//
// NOTE:
// The tests can fail on the build bots when somebody connects to them via
// remote-desktop and the rdp client installs an audio device that fails to open
// at some point, possibly when the connection goes idle.
// Test that can it be created and closed.
TEST_F(WinAudioTest, PCMWaveStreamGetAndClose) {
ABORT_AUDIO_TEST_IF_NOT(audio_manager_->HasAudioOutputDevices());
AudioOutputStream* oas = audio_manager_->MakeAudioOutputStream(
AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO,
8000, 16, 256),
std::string(), AudioManager::LogCallback());
ASSERT_TRUE(NULL != oas);
oas->Close();
}
// Test that can it be cannot be created with invalid parameters.
TEST_F(WinAudioTest, SanityOnMakeParams) {
ABORT_AUDIO_TEST_IF_NOT(audio_manager_->HasAudioOutputDevices());
AudioParameters::Format fmt = AudioParameters::AUDIO_PCM_LINEAR;
EXPECT_TRUE(
NULL ==
audio_manager_->MakeAudioOutputStream(
AudioParameters(fmt, CHANNEL_LAYOUT_UNSUPPORTED, 8000, 16, 256),
std::string(), AudioManager::LogCallback()));
EXPECT_TRUE(
NULL ==
audio_manager_->MakeAudioOutputStream(
AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 1024 * 1024, 16, 256),
std::string(), AudioManager::LogCallback()));
EXPECT_TRUE(NULL ==
audio_manager_->MakeAudioOutputStream(
AudioParameters(fmt, CHANNEL_LAYOUT_STEREO, 8000, 80, 256),
std::string(), AudioManager::LogCallback()));
EXPECT_TRUE(
NULL ==
audio_manager_->MakeAudioOutputStream(
AudioParameters(fmt, CHANNEL_LAYOUT_UNSUPPORTED, 8000, 16, 256),
std::string(), AudioManager::LogCallback()));
EXPECT_TRUE(NULL ==
audio_manager_->MakeAudioOutputStream(
AudioParameters(fmt, CHANNEL_LAYOUT_STEREO, -8000, 16, 256),
std::string(), AudioManager::LogCallback()));
EXPECT_TRUE(NULL ==
audio_manager_->MakeAudioOutputStream(
AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 8000, 16, -100),
std::string(), AudioManager::LogCallback()));
EXPECT_TRUE(NULL ==
audio_manager_->MakeAudioOutputStream(
AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 8000, 16, 0),
std::string(), AudioManager::LogCallback()));
EXPECT_TRUE(NULL ==
audio_manager_->MakeAudioOutputStream(
AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 8000, 16,
media::limits::kMaxSamplesPerPacket + 1),
std::string(), AudioManager::LogCallback()));
}
// Test that it can be opened and closed.
TEST_F(WinAudioTest, PCMWaveStreamOpenAndClose) {
ABORT_AUDIO_TEST_IF_NOT(audio_manager_->HasAudioOutputDevices());
AudioOutputStream* oas = audio_manager_->MakeAudioOutputStream(
AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO,
8000, 16, 256),
std::string(), AudioManager::LogCallback());
ASSERT_TRUE(NULL != oas);
EXPECT_TRUE(oas->Open());
oas->Close();
}
// Test that it has a maximum packet size.
TEST_F(WinAudioTest, PCMWaveStreamOpenLimit) {
ABORT_AUDIO_TEST_IF_NOT(audio_manager_->HasAudioOutputDevices());
AudioOutputStream* oas = audio_manager_->MakeAudioOutputStream(
AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO,
8000, 16, 1024 * 1024 * 1024),
std::string(), AudioManager::LogCallback());
EXPECT_TRUE(NULL == oas);
if (oas)
oas->Close();
}
// Test potential deadlock situation if the source is slow or blocks for some
// time. The actual EXPECT_GT are mostly meaningless and the real test is that
// the test completes in reasonable time.
TEST_F(WinAudioTest, PCMWaveSlowSource) {
ABORT_AUDIO_TEST_IF_NOT(audio_manager_->HasAudioOutputDevices());
AudioOutputStream* oas = audio_manager_->MakeAudioOutputStream(
AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
16000, 16, 256),
std::string(), AudioManager::LogCallback());
ASSERT_TRUE(NULL != oas);
TestSourceLaggy test_laggy(90);
EXPECT_TRUE(oas->Open());
// The test parameters cause a callback every 32 ms and the source is
// sleeping for 90 ms, so it is guaranteed that we run out of ready buffers.
oas->Start(&test_laggy);
::Sleep(500);
EXPECT_GT(test_laggy.callback_count(), 2);
EXPECT_FALSE(test_laggy.had_error());
oas->Stop();
::Sleep(500);
oas->Close();
}
// Test another potential deadlock situation if the thread that calls Start()
// gets paused. This test is best when run over RDP with audio enabled. See
// bug 19276 for more details.
TEST_F(WinAudioTest, PCMWaveStreamPlaySlowLoop) {
ABORT_AUDIO_TEST_IF_NOT(audio_manager_->HasAudioOutputDevices());
uint32_t samples_100_ms = AudioParameters::kAudioCDSampleRate / 10;
AudioOutputStream* oas = audio_manager_->MakeAudioOutputStream(
AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
AudioParameters::kAudioCDSampleRate, 16, samples_100_ms),
std::string(), AudioManager::LogCallback());
ASSERT_TRUE(NULL != oas);
SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate);
EXPECT_TRUE(oas->Open());
oas->SetVolume(1.0);
for (int ix = 0; ix != 5; ++ix) {
oas->Start(&source);
::Sleep(10);
oas->Stop();
}
oas->Close();
}
// This test produces actual audio for .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_F(WinAudioTest, PCMWaveStreamPlay200HzTone44Kss) {
if (!audio_manager_->HasAudioOutputDevices()) {
LOG(WARNING) << "No output device detected.";
return;
}
uint32_t samples_100_ms = AudioParameters::kAudioCDSampleRate / 10;
AudioOutputStream* oas = audio_manager_->MakeAudioOutputStream(
AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
AudioParameters::kAudioCDSampleRate, 16, samples_100_ms),
std::string(), AudioManager::LogCallback());
ASSERT_TRUE(NULL != oas);
SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate);
EXPECT_TRUE(oas->Open());
oas->SetVolume(1.0);
oas->Start(&source);
::Sleep(500);
oas->Stop();
oas->Close();
}
// This test produces actual audio for for .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. The audio also should
// sound with a lower volume than PCMWaveStreamPlay200HzTone44Kss.
TEST_F(WinAudioTest, PCMWaveStreamPlay200HzTone22Kss) {
ABORT_AUDIO_TEST_IF_NOT(audio_manager_->HasAudioOutputDevices());
uint32_t samples_100_ms = AudioParameters::kAudioCDSampleRate / 20;
AudioOutputStream* oas = audio_manager_->MakeAudioOutputStream(
AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
AudioParameters::kAudioCDSampleRate / 2, 16,
samples_100_ms),
std::string(), AudioManager::LogCallback());
ASSERT_TRUE(NULL != oas);
SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate/2);
EXPECT_TRUE(oas->Open());
oas->SetVolume(0.5);
oas->Start(&source);
::Sleep(500);
// Test that the volume is within the set limits.
double volume = 0.0;
oas->GetVolume(&volume);
EXPECT_LT(volume, 0.51);
EXPECT_GT(volume, 0.49);
oas->Stop();
oas->Close();
}
// Uses a restricted source to play ~2 seconds of audio for about 5 seconds. We
// try hard to generate situation where the two threads are accessing the
// object roughly at the same time.
TEST_F(WinAudioTest, PushSourceFile16KHz) {
ABORT_AUDIO_TEST_IF_NOT(audio_manager_->HasAudioOutputDevices());
static const int kSampleRate = 16000;
SineWaveAudioSource source(1, 200.0, kSampleRate);
// Compute buffer size for 100ms of audio.
const uint32_t kSamples100ms = (kSampleRate / 1000) * 100;
// Restrict SineWaveAudioSource to 100ms of samples.
source.CapSamples(kSamples100ms);
AudioOutputStream* oas = audio_manager_->MakeAudioOutputStream(
AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
kSampleRate, 16, kSamples100ms),
std::string(), AudioManager::LogCallback());
ASSERT_TRUE(NULL != oas);
EXPECT_TRUE(oas->Open());
oas->SetVolume(1.0);
oas->Start(&source);
// We buffer and play at the same time, buffering happens every ~10ms and the
// consuming of the buffer happens every ~100ms. We do 100 buffers which
// effectively wrap around the file more than once.
for (uint32_t ix = 0; ix != 100; ++ix) {
::Sleep(10);
source.Reset();
}
// Play a little bit more of the file.
::Sleep(500);
oas->Stop();
oas->Close();
}
// This test is to make sure an AudioOutputStream can be started after it was
// stopped. You will here two .5 seconds wave signal separated by 0.5 seconds
// of silence.
TEST_F(WinAudioTest, PCMWaveStreamPlayTwice200HzTone44Kss) {
ABORT_AUDIO_TEST_IF_NOT(audio_manager_->HasAudioOutputDevices());
uint32_t samples_100_ms = AudioParameters::kAudioCDSampleRate / 10;
AudioOutputStream* oas = audio_manager_->MakeAudioOutputStream(
AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
AudioParameters::kAudioCDSampleRate, 16, samples_100_ms),
std::string(), AudioManager::LogCallback());
ASSERT_TRUE(NULL != oas);
SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate);
EXPECT_TRUE(oas->Open());
oas->SetVolume(1.0);
// Play the wave for .5 seconds.
oas->Start(&source);
::Sleep(500);
oas->Stop();
// Sleep to give silence after stopping the AudioOutputStream.
::Sleep(250);
// Start again and play for .5 seconds.
oas->Start(&source);
::Sleep(500);
oas->Stop();
oas->Close();
}
// With the low latency mode, WASAPI is utilized by default for Vista and
// higher and Wave is used for XP and lower. It is possible to utilize a
// smaller buffer size for WASAPI than for Wave.
TEST_F(WinAudioTest, PCMWaveStreamPlay200HzToneLowLatency) {
ABORT_AUDIO_TEST_IF_NOT(audio_manager_->HasAudioOutputDevices());
// Use 10 ms buffer size for WASAPI and 50 ms buffer size for Wave.
// Take the existing native sample rate into account.
const AudioParameters params =
audio_manager_->GetDefaultOutputStreamParameters();
int sample_rate = params.sample_rate();
uint32_t samples_10_ms = sample_rate / 100;
int n = 1;
(base::win::GetVersion() <= base::win::VERSION_XP) ? n = 5 : n = 1;
AudioOutputStream* oas = audio_manager_->MakeAudioOutputStream(
AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY,
CHANNEL_LAYOUT_MONO, sample_rate, 16, n * samples_10_ms),
std::string(), AudioManager::LogCallback());
ASSERT_TRUE(NULL != oas);
SineWaveAudioSource source(1, 200, sample_rate);
bool opened = oas->Open();
if (!opened) {
// It was not possible to open this audio device in mono.
// No point in continuing the test so let's break here.
LOG(WARNING) << "Mono is not supported. Skipping test.";
oas->Close();
return;
}
oas->SetVolume(1.0);
// Play the wave for .8 seconds.
oas->Start(&source);
::Sleep(800);
oas->Stop();
oas->Close();
}
// Check that the pending bytes value is correct what the stream starts.
TEST_F(WinAudioTest, PCMWaveStreamPendingBytes) {
ABORT_AUDIO_TEST_IF_NOT(audio_manager_->HasAudioOutputDevices());
uint32_t samples_100_ms = AudioParameters::kAudioCDSampleRate / 10;
AudioOutputStream* oas = audio_manager_->MakeAudioOutputStream(
AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
AudioParameters::kAudioCDSampleRate, 16, samples_100_ms),
std::string(), AudioManager::LogCallback());
ASSERT_TRUE(NULL != oas);
NiceMock<MockAudioSourceCallback> source;
EXPECT_TRUE(oas->Open());
const base::TimeDelta delay_100_ms = base::TimeDelta::FromMilliseconds(100);
const base::TimeDelta delay_200_ms = base::TimeDelta::FromMilliseconds(200);
// Audio output stream has either a double or triple buffer scheme. We expect
// the delay to reach up to 200 ms depending on the number of buffers used.
// From that it would decrease as we are playing the data but not providing
// new one. And then we will try to provide zero data so the amount of
// pending bytes will go down and eventually read zero.
InSequence s;
EXPECT_CALL(source, OnMoreData(base::TimeDelta(), _, 0, NotNull()))
.WillOnce(Invoke(ClearData));
// Note: If AudioManagerWin::NumberOfWaveOutBuffers() ever changes, or if this
// test is run on Vista, these expectations will fail.
EXPECT_CALL(source, OnMoreData(delay_100_ms, _, 0, NotNull()))
.WillOnce(Invoke(ClearData));
EXPECT_CALL(source, OnMoreData(delay_200_ms, _, 0, NotNull()))
.WillOnce(Invoke(ClearData));
EXPECT_CALL(source, OnMoreData(delay_200_ms, _, 0, NotNull()))
.Times(AnyNumber())
.WillRepeatedly(Return(0));
EXPECT_CALL(source, OnMoreData(delay_100_ms, _, 0, NotNull()))
.Times(AnyNumber())
.WillRepeatedly(Return(0));
EXPECT_CALL(source, OnMoreData(base::TimeDelta(), _, 0, NotNull()))
.Times(AnyNumber())
.WillRepeatedly(Return(0));
oas->Start(&source);
::Sleep(500);
oas->Stop();
oas->Close();
}
// Simple source that uses a SyncSocket to retrieve the audio data
// from a potentially remote thread.
class SyncSocketSource : public AudioOutputStream::AudioSourceCallback {
public:
SyncSocketSource(base::SyncSocket* socket, const AudioParameters& params)
: socket_(socket), params_(params) {
// Setup AudioBus wrapping data we'll receive over the sync socket.
packet_size_ = AudioBus::CalculateMemorySize(params);
data_.reset(static_cast<float*>(
base::AlignedAlloc(packet_size_ + sizeof(AudioOutputBufferParameters),
AudioBus::kChannelAlignment)));
audio_bus_ = AudioBus::WrapMemory(params, output_buffer()->audio);
}
~SyncSocketSource() override {}
// AudioSourceCallback::OnMoreData implementation:
int OnMoreData(base::TimeDelta delay,
base::TimeTicks delay_timestamp,
int /* prior_frames_skipped */,
AudioBus* dest) override {
uint32_t control_signal = 0;
socket_->Send(&control_signal, sizeof(control_signal));
output_buffer()->params.delay = delay.InMicroseconds();
output_buffer()->params.delay_timestamp =
(delay_timestamp - base::TimeTicks()).InMicroseconds();
uint32_t size = socket_->Receive(data_.get(), packet_size_);
DCHECK_EQ(static_cast<size_t>(size) % sizeof(*audio_bus_->channel(0)), 0U);
audio_bus_->CopyTo(dest);
return audio_bus_->frames();
}
int packet_size() const { return packet_size_; }
AudioOutputBuffer* output_buffer() const {
return reinterpret_cast<AudioOutputBuffer*>(data_.get());
}
// AudioSourceCallback::OnError implementation:
void OnError(AudioOutputStream* stream) override {}
private:
base::SyncSocket* socket_;
const AudioParameters params_;
int packet_size_;
std::unique_ptr<float, base::AlignedFreeDeleter> data_;
std::unique_ptr<AudioBus> audio_bus_;
};
struct SyncThreadContext {
base::SyncSocket* socket;
int sample_rate;
int channels;
int frames;
double sine_freq;
uint32_t packet_size_bytes;
AudioOutputBuffer* buffer;
};
// This thread provides the data that the SyncSocketSource above needs
// using the other end of a SyncSocket. The protocol is as follows:
//
// SyncSocketSource ---send 4 bytes ------------> SyncSocketThread
// <--- audio packet ----------
//
DWORD __stdcall SyncSocketThread(void* context) {
SyncThreadContext& ctx = *(reinterpret_cast<SyncThreadContext*>(context));
// Setup AudioBus wrapping data we'll pass over the sync socket.
std::unique_ptr<float, base::AlignedFreeDeleter> data(static_cast<float*>(
base::AlignedAlloc(ctx.packet_size_bytes, AudioBus::kChannelAlignment)));
std::unique_ptr<AudioBus> audio_bus =
AudioBus::WrapMemory(ctx.channels, ctx.frames, data.get());
SineWaveAudioSource sine(1, ctx.sine_freq, ctx.sample_rate);
const int kTwoSecFrames = ctx.sample_rate * 2;
uint32_t control_signal = 0;
for (int ix = 0; ix < kTwoSecFrames; ix += ctx.frames) {
if (ctx.socket->Receive(&control_signal, sizeof(control_signal)) == 0)
break;
base::TimeDelta delay =
base::TimeDelta::FromMicroseconds(ctx.buffer->params.delay);
base::TimeTicks delay_timestamp =
base::TimeTicks() +
base::TimeDelta::FromMicroseconds(ctx.buffer->params.delay_timestamp);
sine.OnMoreData(delay, delay_timestamp, 0, audio_bus.get());
ctx.socket->Send(data.get(), ctx.packet_size_bytes);
}
return 0;
}
// Test the basic operation of AudioOutputStream used with a SyncSocket.
// The emphasis is to verify that it is possible to feed data to the audio
// layer using a source based on SyncSocket. In a real situation we would
// go for the low-latency version in combination with SyncSocket, but to keep
// the test more simple, AUDIO_PCM_LINEAR is utilized instead. The main
// principle of the test still remains and we avoid the additional complexity
// related to the two different audio-layers for AUDIO_PCM_LOW_LATENCY.
// In this test you should hear a continuous 200Hz tone for 2 seconds.
TEST_F(WinAudioTest, SyncSocketBasic) {
ABORT_AUDIO_TEST_IF_NOT(audio_manager_->HasAudioOutputDevices());
static const int sample_rate = AudioParameters::kAudioCDSampleRate;
static const uint32_t kSamples20ms = sample_rate / 50;
AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
CHANNEL_LAYOUT_MONO, sample_rate, 16, kSamples20ms);
AudioOutputStream* oas = audio_manager_->MakeAudioOutputStream(
params, std::string(), AudioManager::LogCallback());
ASSERT_TRUE(NULL != oas);
ASSERT_TRUE(oas->Open());
base::SyncSocket sockets[2];
ASSERT_TRUE(base::SyncSocket::CreatePair(&sockets[0], &sockets[1]));
SyncSocketSource source(&sockets[0], params);
SyncThreadContext thread_context;
thread_context.sample_rate = params.sample_rate();
thread_context.sine_freq = 200.0;
thread_context.packet_size_bytes = source.packet_size();
thread_context.frames = params.frames_per_buffer();
thread_context.channels = params.channels();
thread_context.socket = &sockets[1];
thread_context.buffer = source.output_buffer();
HANDLE thread = ::CreateThread(NULL, 0, SyncSocketThread,
&thread_context, 0, NULL);
oas->Start(&source);
::WaitForSingleObject(thread, INFINITE);
::CloseHandle(thread);
oas->Stop();
oas->Close();
}
} // namespace media