Skip to content

Commit

Permalink
This patch ensures that the audio_output_win_unittest works for AUDIO…
Browse files Browse the repository at this point in the history
…_PCM_LOW_LATENCY.

It seems like only test which utilized AUDIO_PCM_LOW_LATENCY has been broken for a while.
It was most likely I who broke it when I added support for WASAPI output.

Anyhow, in this patch, I ensure that we can still test using the low-larency flag.
A buffer size of 10ms is used on Vista and higher (<=> WASAPI) and 50ms is used (as before)
in XP.

I have also modified the sinus source since it contained two issues actually.
1) It did not store a valid state between each frame (=> distorsion at end-points).
2) The volume 2^15 was too high and could lead to odd effects for negative numbers.
Both these things are fixed in this CL and all tones now sounds better. The old tones
were all distorted.

BUG=none
TEST=audio_output_win_unittest
Review URL: http://codereview.chromium.org/8678012

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@111890 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
henrika@chromium.org committed Nov 29, 2011
1 parent 9e36ea4 commit 59404dd
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 28 deletions.
18 changes: 12 additions & 6 deletions media/audio/simple_sources.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ SineWaveAudioSource::SineWaveAudioSource(Format format, int channels,
: format_(format),
channels_(channels),
freq_(freq),
sample_freq_(sample_freq) {
sample_freq_(sample_freq),
time_state_(0) {
// TODO(cpu): support other formats.
DCHECK((format_ == FORMAT_16BIT_LINEAR_PCM) && (channels_ == 1));
}
Expand All @@ -31,14 +32,19 @@ SineWaveAudioSource::SineWaveAudioSource(Format format, int channels,
uint32 SineWaveAudioSource::OnMoreData(
AudioOutputStream* stream, uint8* dest, uint32 max_size,
AudioBuffersState audio_buffers) {
const double kTwoPi = 2.0 * 3.141592653589;
const double kTwoPi = 2.0 * 3.141592653589793;
double f = freq_ / sample_freq_;
int16* sin_tbl = reinterpret_cast<int16*>(dest);
uint32 len = max_size / sizeof(int16);
// The table is filled with s(t) = 32768*sin(2PI*f*t).
for (uint32 ix = 0; ix != len; ++ix) {
double th = kTwoPi * ix * f;
sin_tbl[ix] = static_cast<int16>((1 << 15) * sin(th));

// The table is filled with s(t) = kint16max*sin(Theta*t),
// where Theta = 2*PI*fs.
// We store the discrete time value |t| in a member to ensure that the
// next pass starts at a correct state.
for (uint32 n = 0; n < len; ++n) {
double theta = kTwoPi * f;
sin_tbl[n] = static_cast<int16>(kint16max * sin(theta * time_state_));
++time_state_;
}
return max_size;
}
Expand Down
1 change: 1 addition & 0 deletions media/audio/simple_sources.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class MEDIA_EXPORT SineWaveAudioSource
int channels_;
double freq_;
double sample_freq_;
int time_state_;
};

// Defines an interface for pushing audio output. In contrast, the interfaces
Expand Down
59 changes: 37 additions & 22 deletions media/audio/win/audio_output_win_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/sync_socket.h"
#include "base/win/scoped_com_initializer.h"
#include "base/win/windows_version.h"
#include "media/base/limits.h"
#include "media/audio/audio_io.h"
#include "media/audio/audio_util.h"
#include "media/audio/audio_manager.h"
#include "media/audio/simple_sources.h"
#include "testing/gmock/include/gmock/gmock.h"
Expand All @@ -25,6 +29,8 @@ using ::testing::NiceMock;
using ::testing::NotNull;
using ::testing::Return;

using base::win::ScopedCOMInitializer;

static const wchar_t kAudioFile1_16b_m_16K[]
= L"media\\test\\data\\sweep02_16b_mono_16KHz.raw";

Expand Down Expand Up @@ -231,7 +237,7 @@ TEST(WinAudioTest, PCMWaveStreamGetAndClose) {
oas->Close();
}

// Test that can it be cannot be created with crazy parameters
// Test that can it be cannot be created with invalid parameters.
TEST(WinAudioTest, SanityOnMakeParams) {
if (IsRunningHeadless())
return;
Expand All @@ -255,7 +261,8 @@ TEST(WinAudioTest, SanityOnMakeParams) {
EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 8000, 16, 0)));
EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 8000, 16, 100000)));
AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 8000, 16,
media::Limits::kMaxSamplesPerPacket + 1)));
}

// Test that it can be opened and closed.
Expand Down Expand Up @@ -533,27 +540,34 @@ TEST(WinAudioTest, PCMWaveStreamPlayTwice200HzTone44Kss) {
oas->Close();
}

// With the low latency mode, we have two buffers instead of 3 and we
// should be able to handle 20ms buffers at 44KHz. See also the SyncSocketBasic
// test below.
// TODO(cpu): right now the best we can do is 50ms before it sounds choppy.
TEST(WinAudioTest, PCMWaveStreamPlay200HzTone44KssLowLatency) {
// 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(WinAudioTest, PCMWaveStreamPlay200HzToneLowLatency) {
if (IsRunningHeadless())
return;
AudioManager* audio_man = AudioManager::GetAudioManager();
ASSERT_TRUE(NULL != audio_man);
if (!audio_man->HasAudioOutputDevices())
return;

uint32 samples_50_ms = AudioParameters::kAudioCDSampleRate / 20;
// The WASAPI API requires a correct COM environment.
ScopedCOMInitializer com_init(ScopedCOMInitializer::kMTA);

// Use 10 ms buffer size for WASAPI and 50 ms buffer size for Wave.
// Take the existing native sample rate into account.
int sample_rate = static_cast<int>(media::GetAudioHardwareSampleRate());
uint32 samples_10_ms = sample_rate / 100;
int n = 1;
(base::win::GetVersion() <= base::win::VERSION_XP) ? n = 5 : n = 1;
AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY,
CHANNEL_LAYOUT_MONO, AudioParameters::kAudioCDSampleRate,
16, samples_50_ms));
CHANNEL_LAYOUT_MONO, sample_rate,
16, n * samples_10_ms));
ASSERT_TRUE(NULL != oas);

SineWaveAudioSource source(SineWaveAudioSource::FORMAT_16BIT_LINEAR_PCM, 1,
200.0, AudioParameters::kAudioCDSampleRate);
200.0, sample_rate);

EXPECT_TRUE(oas->Open());
oas->SetVolume(1.0);
Expand Down Expand Up @@ -651,7 +665,7 @@ struct SyncThreadContext {
base::SyncSocket* socket;
int sample_rate;
double sine_freq;
uint32 packet_size;
uint32 packet_size_bytes;
};

// This thread provides the data that the SyncSocketSource above needs
Expand All @@ -672,11 +686,11 @@ DWORD __stdcall SyncSocketThread(void* context) {

AudioBuffersState buffers_state;
int times = 0;
for (int ix = 0; ix < kTwoSecBytes; ix += ctx.packet_size) {
for (int ix = 0; ix < kTwoSecBytes; ix += ctx.packet_size_bytes) {
if (ctx.socket->Receive(&buffers_state, sizeof(buffers_state)) == 0)
break;
if ((times > 0) && (buffers_state.pending_bytes < 1000)) __debugbreak();
ctx.socket->Send(&buffer[ix], ctx.packet_size);
ctx.socket->Send(&buffer[ix], ctx.packet_size_bytes);
++times;
}

Expand All @@ -685,11 +699,13 @@ DWORD __stdcall SyncSocketThread(void* context) {
}

// Test the basic operation of AudioOutputStream used with a SyncSocket.
// The emphasis is to test low-latency with buffers less than 100ms. With
// the waveout api it seems not possible to go below 50ms. In this test
// you should hear a continous 200Hz tone.
//
// TODO(cpu): This actually sounds choppy most of the time. Fix it.
// 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(WinAudioTest, SyncSocketBasic) {
if (IsRunningHeadless())
return;
Expand All @@ -702,11 +718,10 @@ TEST(WinAudioTest, SyncSocketBasic) {
int sample_rate = AudioParameters::kAudioCDSampleRate;
const uint32 kSamples20ms = sample_rate / 50;
AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY,
AudioParameters(AudioParameters::AUDIO_PCM_LINEAR,
CHANNEL_LAYOUT_MONO, sample_rate, 16, kSamples20ms));
ASSERT_TRUE(NULL != oas);

// compute buffer size for 20ms of audio, 882 samples (mono).
ASSERT_TRUE(oas->Open());

base::SyncSocket* sockets[2];
Expand All @@ -717,7 +732,7 @@ TEST(WinAudioTest, SyncSocketBasic) {
SyncThreadContext thread_context;
thread_context.sample_rate = sample_rate;
thread_context.sine_freq = 200.0;
thread_context.packet_size = kSamples20ms;
thread_context.packet_size_bytes = kSamples20ms * 2;
thread_context.socket = sockets[1];

HANDLE thread = ::CreateThread(NULL, 0, SyncSocketThread,
Expand Down

0 comments on commit 59404dd

Please sign in to comment.