Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(491)

Unified Diff: media/audio/win/audio_output_win_unittest.cc

Issue 10832285: Switch OnMoreData() to use AudioBus. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase. Comments. Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/audio/win/audio_low_latency_output_win_unittest.cc ('k') | media/audio/win/waveout_output_win.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/audio/win/audio_output_win_unittest.cc
diff --git a/media/audio/win/audio_output_win_unittest.cc b/media/audio/win/audio_output_win_unittest.cc
index 76aea2d45ddd7d7930e1ae4b461ad9c28903e363..b3d6a38646442a3384b4c0584f2394dcac5ed863 100644
--- a/media/audio/win/audio_output_win_unittest.cc
+++ b/media/audio/win/audio_output_win_unittest.cc
@@ -8,6 +8,7 @@
#include "base/basictypes.h"
#include "base/base_paths.h"
#include "base/file_util.h"
+#include "base/memory/aligned_memory.h"
#include "base/path_service.h"
#include "base/sync_socket.h"
#include "base/win/scoped_com_initializer.h"
@@ -24,6 +25,7 @@ using ::testing::_;
using ::testing::AnyNumber;
using ::testing::DoAll;
using ::testing::Field;
+using ::testing::Invoke;
using ::testing::InSequence;
using ::testing::NiceMock;
using ::testing::NotNull;
@@ -45,14 +47,12 @@ class TestSourceBasic : public AudioOutputStream::AudioSourceCallback {
had_error_(0) {
}
// AudioSourceCallback::OnMoreData implementation:
- virtual uint32 OnMoreData(uint8* dest,
- uint32 max_size,
- AudioBuffersState buffers_state) {
+ virtual int OnMoreData(AudioBus* audio_bus,
+ AudioBuffersState buffers_state) {
++callback_count_;
- // Touch the first byte to make sure memory is good.
- if (max_size)
- reinterpret_cast<char*>(dest)[0] = 1;
- return max_size;
+ // Touch the channel memory value to make sure memory is good.
+ audio_bus->Zero();
+ return audio_bus->frames();
}
// AudioSourceCallback::OnError implementation:
virtual void OnError(AudioOutputStream* stream, int code) {
@@ -77,46 +77,6 @@ class TestSourceBasic : public AudioOutputStream::AudioSourceCallback {
};
const int kMaxNumBuffers = 3;
-// Specializes TestSourceBasic to detect that the AudioStream is using
-// triple buffering correctly.
-class TestSourceTripleBuffer : public TestSourceBasic {
- public:
- TestSourceTripleBuffer() {
- buffer_address_[0] = NULL;
- buffer_address_[1] = NULL;
- buffer_address_[2] = NULL;
- }
- // Override of TestSourceBasic::OnMoreData.
- virtual uint32 OnMoreData(uint8* dest,
- uint32 max_size,
- AudioBuffersState buffers_state) {
- // Call the base, which increments the callback_count_.
- TestSourceBasic::OnMoreData(dest, max_size, buffers_state);
- if (callback_count() % NumberOfWaveOutBuffers() == 2) {
- set_error(!CompareExistingIfNotNULL(2, dest));
- } else if (callback_count() % NumberOfWaveOutBuffers() == 1) {
- set_error(!CompareExistingIfNotNULL(1, dest));
- } else {
- set_error(!CompareExistingIfNotNULL(0, dest));
- }
- if (callback_count() > kMaxNumBuffers) {
- set_error(buffer_address_[0] == buffer_address_[1]);
- set_error(buffer_address_[1] == buffer_address_[2]);
- }
- return max_size;
- }
-
- private:
- bool CompareExistingIfNotNULL(uint32 index, void* address) {
- void*& entry = buffer_address_[index];
- if (!entry)
- entry = address;
- return (entry == address);
- }
-
- void* buffer_address_[kMaxNumBuffers];
-};
-
// Specializes TestSourceBasic to simulate a source that blocks for some time
// in the OnMoreData callback.
class TestSourceLaggy : public TestSourceBasic {
@@ -124,15 +84,14 @@ class TestSourceLaggy : public TestSourceBasic {
TestSourceLaggy(int laggy_after_buffer, int lag_in_ms)
: laggy_after_buffer_(laggy_after_buffer), lag_in_ms_(lag_in_ms) {
}
- virtual uint32 OnMoreData(uint8* dest,
- uint32 max_size,
- AudioBuffersState buffers_state) {
+ virtual int OnMoreData(AudioBus* audio_bus,
+ AudioBuffersState buffers_state) {
// Call the base, which increments the callback_count_.
- TestSourceBasic::OnMoreData(dest, max_size, buffers_state);
+ TestSourceBasic::OnMoreData(audio_bus, buffers_state);
if (callback_count() > kMaxNumBuffers) {
::Sleep(lag_in_ms_);
}
- return max_size;
+ return audio_bus->frames();
}
private:
int laggy_after_buffer_;
@@ -141,10 +100,14 @@ class TestSourceLaggy : public TestSourceBasic {
class MockAudioSource : public AudioOutputStream::AudioSourceCallback {
public:
- MOCK_METHOD3(OnMoreData, uint32(uint8* dest,
- uint32 max_size,
- AudioBuffersState buffers_state));
+ MOCK_METHOD2(OnMoreData, int(AudioBus* audio_bus,
+ AudioBuffersState buffers_state));
MOCK_METHOD2(OnError, void(AudioOutputStream* stream, int code));
+
+ static int ClearData(AudioBus* audio_bus, AudioBuffersState buffers_state) {
+ audio_bus->Zero();
+ return audio_bus->frames();
+ }
};
// Helper class to memory map an entire file. The mapping is read-only. Don't
@@ -295,30 +258,6 @@ TEST(WinAudioTest, PCMWaveStreamOpenLimit) {
oas->Close();
}
-// Test that it uses the triple buffers correctly. Because it uses the actual
-// audio device, you might hear a short pop noise for a short time.
-TEST(WinAudioTest, PCMWaveStreamTripleBuffer) {
- scoped_ptr<AudioManager> audio_man(AudioManager::Create());
- if (!audio_man->HasAudioOutputDevices()) {
- LOG(WARNING) << "No output device detected.";
- return;
- }
-
- AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
- AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
- 16000, 16, 256));
- ASSERT_TRUE(NULL != oas);
- TestSourceTripleBuffer test_triple_buffer;
- EXPECT_TRUE(oas->Open());
- oas->Start(&test_triple_buffer);
- ::Sleep(300);
- EXPECT_GT(test_triple_buffer.callback_count(), kMaxNumBuffers);
- EXPECT_FALSE(test_triple_buffer.had_error());
- oas->Stop();
- ::Sleep(500);
- 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.
@@ -362,8 +301,7 @@ TEST(WinAudioTest, PCMWaveStreamPlaySlowLoop) {
AudioParameters::kAudioCDSampleRate, 16, samples_100_ms));
ASSERT_TRUE(NULL != oas);
- SineWaveAudioSource source(SineWaveAudioSource::FORMAT_16BIT_LINEAR_PCM, 1,
- 200.0, AudioParameters::kAudioCDSampleRate);
+ SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate);
EXPECT_TRUE(oas->Open());
oas->SetVolume(1.0);
@@ -393,8 +331,7 @@ TEST(WinAudioTest, PCMWaveStreamPlay200HzTone44Kss) {
AudioParameters::kAudioCDSampleRate, 16, samples_100_ms));
ASSERT_TRUE(NULL != oas);
- SineWaveAudioSource source(SineWaveAudioSource::FORMAT_16BIT_LINEAR_PCM, 1,
- 200.0, AudioParameters::kAudioCDSampleRate);
+ SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate);
EXPECT_TRUE(oas->Open());
oas->SetVolume(1.0);
@@ -422,8 +359,7 @@ TEST(WinAudioTest, PCMWaveStreamPlay200HzTone22Kss) {
samples_100_ms));
ASSERT_TRUE(NULL != oas);
- SineWaveAudioSource source(SineWaveAudioSource::FORMAT_16BIT_LINEAR_PCM, 1,
- 200.0, AudioParameters::kAudioCDSampleRate/2);
+ SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate/2);
EXPECT_TRUE(oas->Open());
@@ -440,11 +376,9 @@ TEST(WinAudioTest, PCMWaveStreamPlay200HzTone22Kss) {
oas->Close();
}
-// Uses the PushSource to play a 2 seconds file clip for about 5 seconds. We
+// 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. What you hear is a sweeping tone from 1KHz
-// to 2KHz with a bit of fade out at the end for one second. The file is two
-// of these sweeping tones back to back.
+// object roughly at the same time.
TEST(WinAudioTest, PushSourceFile16KHz) {
scoped_ptr<AudioManager> audio_man(AudioManager::Create());
if (!audio_man->HasAudioOutputDevices()) {
@@ -452,44 +386,29 @@ TEST(WinAudioTest, PushSourceFile16KHz) {
return;
}
- // Open sweep02_16b_mono_16KHz.raw which has no format. It contains the
- // raw 16 bit samples for a single channel in little-endian format. The
- // creation sample rate is 16KHz.
- FilePath audio_file;
- ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &audio_file));
- audio_file = audio_file.Append(kAudioFile1_16b_m_16K);
- // Map the entire file in memory.
- ReadOnlyMappedFile file_reader(audio_file.value().c_str());
- ASSERT_TRUE(file_reader.is_valid());
-
+ static const int kSampleRate = 16000;
+ SineWaveAudioSource source(1, 200.0, kSampleRate);
// Compute buffer size for 100ms of audio.
- const uint32 kSamples100ms = (16000 / 1000) * 100;
- const uint32 kSize100ms = kSamples100ms * 2;
+ const uint32 kSamples100ms = (kSampleRate / 1000) * 100;
+ // Restrict SineWaveAudioSource to 100ms of samples.
+ source.CapSamples(kSamples100ms);
AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
- 16000, 16, kSamples100ms));
+ kSampleRate, 16, kSamples100ms));
ASSERT_TRUE(NULL != oas);
EXPECT_TRUE(oas->Open());
- uint32 offset = 0;
- const uint32 kMaxStartOffset = file_reader.size() - kSize100ms;
+ 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.
- PushSource push_source;
for (uint32 ix = 0; ix != 100; ++ix) {
- push_source.Write(file_reader.GetChunkAt(offset), kSize100ms);
- if (ix == 2) {
- // For glitch free, start playing after some buffers are in.
- oas->Start(&push_source);
- }
::Sleep(10);
- offset += kSize100ms;
- if (offset > kMaxStartOffset)
- offset = 0;
+ source.Reset();
}
// Play a little bit more of the file.
@@ -515,8 +434,7 @@ TEST(WinAudioTest, PCMWaveStreamPlayTwice200HzTone44Kss) {
AudioParameters::kAudioCDSampleRate, 16, samples_100_ms));
ASSERT_TRUE(NULL != oas);
- SineWaveAudioSource source(SineWaveAudioSource::FORMAT_16BIT_LINEAR_PCM, 1,
- 200.0, AudioParameters::kAudioCDSampleRate);
+ SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate);
EXPECT_TRUE(oas->Open());
oas->SetVolume(1.0);
@@ -561,8 +479,7 @@ TEST(WinAudioTest, PCMWaveStreamPlay200HzToneLowLatency) {
16, n * samples_10_ms));
ASSERT_TRUE(NULL != oas);
- SineWaveAudioSource source(SineWaveAudioSource::FORMAT_16BIT_LINEAR_PCM, 1,
- 200.0, sample_rate);
+ SineWaveAudioSource source(1, 200, sample_rate);
bool opened = oas->Open();
if (!opened) {
@@ -608,36 +525,37 @@ TEST(WinAudioTest, PCMWaveStreamPendingBytes) {
// pending bytes will go down and eventually read zero.
InSequence s;
- EXPECT_CALL(source, OnMoreData(NotNull(), bytes_100_ms,
+ EXPECT_CALL(source, OnMoreData(NotNull(),
Field(&AudioBuffersState::pending_bytes, 0)))
- .WillOnce(Return(bytes_100_ms));
+ .WillOnce(Invoke(MockAudioSource::ClearData));
switch (NumberOfWaveOutBuffers()) {
case 2:
break; // Calls are the same as at end of 3-buffer scheme.
case 3:
- EXPECT_CALL(source, OnMoreData(NotNull(), bytes_100_ms,
+ EXPECT_CALL(source, OnMoreData(NotNull(),
Field(&AudioBuffersState::pending_bytes,
bytes_100_ms)))
- .WillOnce(Return(bytes_100_ms));
- EXPECT_CALL(source, OnMoreData(NotNull(), bytes_100_ms,
+ .WillOnce(Invoke(MockAudioSource::ClearData));
+ EXPECT_CALL(source, OnMoreData(NotNull(),
Field(&AudioBuffersState::pending_bytes,
2 * bytes_100_ms)))
- .WillOnce(Return(bytes_100_ms));
- EXPECT_CALL(source, OnMoreData(NotNull(), bytes_100_ms,
+ .WillOnce(Invoke(MockAudioSource::ClearData));
+ EXPECT_CALL(source, OnMoreData(NotNull(),
Field(&AudioBuffersState::pending_bytes,
2 * bytes_100_ms)))
.Times(AnyNumber())
.WillRepeatedly(Return(0));
break;
default:
- ASSERT_TRUE(false) << "Unexpected number of buffers";
+ ASSERT_TRUE(false)
+ << "Unexpected number of buffers: " << NumberOfWaveOutBuffers();
}
- EXPECT_CALL(source, OnMoreData(NotNull(), bytes_100_ms,
+ EXPECT_CALL(source, OnMoreData(NotNull(),
Field(&AudioBuffersState::pending_bytes,
bytes_100_ms)))
.Times(AnyNumber())
.WillRepeatedly(Return(0));
- EXPECT_CALL(source, OnMoreData(NotNull(), bytes_100_ms,
+ EXPECT_CALL(source, OnMoreData(NotNull(),
Field(&AudioBuffersState::pending_bytes, 0)))
.Times(AnyNumber())
.WillRepeatedly(Return(0));
@@ -652,19 +570,24 @@ TEST(WinAudioTest, PCMWaveStreamPendingBytes) {
// from a potentially remote thread.
class SyncSocketSource : public AudioOutputStream::AudioSourceCallback {
public:
- explicit SyncSocketSource(base::SyncSocket* socket)
- : socket_(socket) {}
-
- ~SyncSocketSource() {
+ SyncSocketSource(base::SyncSocket* socket, const AudioParameters& params)
+ : socket_(socket) {
+ // Setup AudioBus wrapping data we'll receive over the sync socket.
+ data_size_ = AudioBus::CalculateMemorySize(params);
+ data_.reset(static_cast<float*>(
+ base::AlignedAlloc(data_size_, AudioBus::kChannelAlignment)));
+ audio_bus_ = AudioBus::WrapMemory(params, data_.get());
}
+ ~SyncSocketSource() {}
// AudioSourceCallback::OnMoreData implementation:
- virtual uint32 OnMoreData(uint8* dest,
- uint32 max_size,
- AudioBuffersState buffers_state) {
+ virtual int OnMoreData(AudioBus* audio_bus,
+ AudioBuffersState buffers_state) {
socket_->Send(&buffers_state, sizeof(buffers_state));
- uint32 got = socket_->Receive(dest, max_size);
- return got;
+ uint32 size = socket_->Receive(data_.get(), data_size_);
+ DCHECK_EQ(static_cast<size_t>(size) % sizeof(*audio_bus_->channel(0)), 0U);
+ audio_bus_->CopyTo(audio_bus);
+ return audio_bus_->frames();
}
// AudioSourceCallback::OnError implementation:
virtual void OnError(AudioOutputStream* stream, int code) {
@@ -672,11 +595,16 @@ class SyncSocketSource : public AudioOutputStream::AudioSourceCallback {
private:
base::SyncSocket* socket_;
+ int data_size_;
+ scoped_ptr_malloc<float, base::ScopedPtrAlignedFree> data_;
+ scoped_ptr<AudioBus> audio_bus_;
};
struct SyncThreadContext {
base::SyncSocket* socket;
int sample_rate;
+ int channels;
+ int frames;
double sine_freq;
uint32 packet_size_bytes;
};
@@ -690,24 +618,26 @@ struct SyncThreadContext {
DWORD __stdcall SyncSocketThread(void* context) {
SyncThreadContext& ctx = *(reinterpret_cast<SyncThreadContext*>(context));
- const int kTwoSecBytes =
- AudioParameters::kAudioCDSampleRate * 2 * sizeof(uint16); // NOLINT
- uint8* buffer = new uint8[kTwoSecBytes];
- SineWaveAudioSource sine(SineWaveAudioSource::FORMAT_16BIT_LINEAR_PCM,
- 1, ctx.sine_freq, ctx.sample_rate);
- sine.OnMoreData(buffer, kTwoSecBytes, AudioBuffersState());
+ // Setup AudioBus wrapping data we'll pass over the sync socket.
+ scoped_ptr_malloc<float, base::ScopedPtrAlignedFree> data(static_cast<float*>(
+ base::AlignedAlloc(ctx.packet_size_bytes, AudioBus::kChannelAlignment)));
+ scoped_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;
AudioBuffersState buffers_state;
int times = 0;
- for (int ix = 0; ix < kTwoSecBytes; ix += ctx.packet_size_bytes) {
+ for (int ix = 0; ix < kTwoSecFrames; ix += ctx.frames) {
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_bytes);
+ sine.OnMoreData(audio_bus.get(), buffers_state);
+ ctx.socket->Send(data.get(), ctx.packet_size_bytes);
++times;
}
- delete buffer;
return 0;
}
@@ -726,11 +656,13 @@ TEST(WinAudioTest, SyncSocketBasic) {
return;
}
- int sample_rate = AudioParameters::kAudioCDSampleRate;
- const uint32 kSamples20ms = sample_rate / 50;
- AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
- AudioParameters(AudioParameters::AUDIO_PCM_LINEAR,
- CHANNEL_LAYOUT_MONO, sample_rate, 16, kSamples20ms));
+ static const int sample_rate = AudioParameters::kAudioCDSampleRate;
+ static const uint32 kSamples20ms = sample_rate / 50;
+ AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
+ CHANNEL_LAYOUT_MONO, sample_rate, 16, kSamples20ms);
+
+
+ AudioOutputStream* oas = audio_man->MakeAudioOutputStream(params);
ASSERT_TRUE(NULL != oas);
ASSERT_TRUE(oas->Open());
@@ -738,12 +670,14 @@ TEST(WinAudioTest, SyncSocketBasic) {
base::SyncSocket sockets[2];
ASSERT_TRUE(base::SyncSocket::CreatePair(&sockets[0], &sockets[1]));
- SyncSocketSource source(&sockets[0]);
+ SyncSocketSource source(&sockets[0], params);
SyncThreadContext thread_context;
- thread_context.sample_rate = sample_rate;
+ thread_context.sample_rate = params.sample_rate();
thread_context.sine_freq = 200.0;
- thread_context.packet_size_bytes = kSamples20ms * 2;
+ thread_context.packet_size_bytes = AudioBus::CalculateMemorySize(params);
+ thread_context.frames = params.frames_per_buffer();
+ thread_context.channels = params.channels();
thread_context.socket = &sockets[1];
HANDLE thread = ::CreateThread(NULL, 0, SyncSocketThread,
« no previous file with comments | « media/audio/win/audio_low_latency_output_win_unittest.cc ('k') | media/audio/win/waveout_output_win.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698