Skip to content
Snippets Groups Projects
Commit dff80f15 authored by hclam@google.com's avatar hclam@google.com
Browse files

Refactoring to share MockAudioOutputStream implementations across 3 platforms

Re-trying the previous CL. The last change got reverted because of valgrind
failure.

TBR=scherkus

Original CL: http://codereview.chromium.org/155471

Review URL: http://codereview.chromium.org/159167

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@21242 0039d316-1c4b-4281-b951-d872f2087c98
parent ee01535e
No related branches found
No related tags found
No related merge requests found
Showing
with 191 additions and 197 deletions
......@@ -182,11 +182,6 @@ class AudioRendererHostTest : public testing::Test {
DISALLOW_COPY_AND_ASSIGN(AudioRendererHostTest);
};
// Audio output stream only works stably on windows. Also there's no mock
// audio output streams for mac and linux.
// TODO(hclam): make these tests work on mac and linux.
#if defined(OS_WIN)
TEST_F(AudioRendererHostTest, MockStreamDataConversation) {
scoped_ptr<AudioRendererHost::IPCAudioSource> source(CreateMockStream());
......@@ -226,4 +221,3 @@ TEST_F(AudioRendererHostTest, MockStreamDataConversation) {
source->Close();
}
#endif
......@@ -91,9 +91,7 @@ class AudioOutputStream {
// Starts playing audio and generating AudioSourceCallback::OnMoreData().
// Since implementor of AudioOutputStream may have internal buffers, right
// after calling this method initial buffers are fetched. User of this
// object should prepare |AudioOutputStream::GetNumBuffers()| before calling
// AudioOutputStream::Start().
// after calling this method initial buffers are fetched.
//
// The output stream does not take ownership of this callback.
virtual void Start(AudioSourceCallback* callback) = 0;
......@@ -114,11 +112,6 @@ class AudioOutputStream {
// After calling this method, the object should not be used anymore.
virtual void Close() = 0;
// Gets the number of internal buffers used in this output stream. This
// method is useful for providing information about how user of this object
// should prepare initial buffers before calling AudioOutputStream::Start().
virtual size_t GetNumBuffers() = 0;
protected:
virtual ~AudioOutputStream() {}
};
......@@ -164,11 +157,6 @@ class AudioManager {
virtual void MuteAll() = 0;
virtual void UnMuteAll() = 0;
// For testing purposes only. Returns the internal buffer of the last
// AUDIO_MOCK AudioOutputStream closed. Returns NULL if none closed yet.
// The buffer size is the same as passed to AudioOutputStream::Open().
virtual const void* GetLastMockBuffer() = 0;
// Get AudioManager singleton.
// TODO(cpu): Define threading requirements for interacting with AudioManager.
static AudioManager* GetAudioManager();
......
// Copyright (c) 2009 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 "base/at_exit.h"
#include "media/audio/fake_audio_output_stream.h"
bool FakeAudioOutputStream::has_created_fake_stream_ = false;
FakeAudioOutputStream* FakeAudioOutputStream::last_fake_stream_ = NULL;
// static
AudioOutputStream* FakeAudioOutputStream::MakeFakeStream() {
if (!has_created_fake_stream_)
base::AtExitManager::RegisterCallback(&DestroyLastFakeStream, NULL);
has_created_fake_stream_ = true;
return new FakeAudioOutputStream();
}
// static
FakeAudioOutputStream* FakeAudioOutputStream::GetLastFakeStream() {
return last_fake_stream_;
}
bool FakeAudioOutputStream::Open(size_t packet_size) {
if (packet_size < sizeof(int16))
return false;
packet_size_ = packet_size;
buffer_.reset(new char[packet_size_]);
return true;
}
void FakeAudioOutputStream::Start(AudioSourceCallback* callback) {
callback_ = callback;
memset(buffer_.get(), 0, packet_size_);
callback_->OnMoreData(this, buffer_.get(), packet_size_);
}
void FakeAudioOutputStream::Stop() {
}
void FakeAudioOutputStream::SetVolume(double left_level, double right_level) {
left_volume_ = left_level;
right_volume_ = right_level;
}
void FakeAudioOutputStream::GetVolume(double* left_level, double* right_level) {
*left_level = left_volume_;
*right_level = right_volume_;
}
void FakeAudioOutputStream::Close() {
callback_->OnClose(this);
callback_ = NULL;
if (last_fake_stream_)
delete last_fake_stream_;
last_fake_stream_ = this;
}
FakeAudioOutputStream::FakeAudioOutputStream()
: left_volume_(0),
right_volume_(0),
callback_(NULL),
packet_size_(0) {
}
// static
void FakeAudioOutputStream::DestroyLastFakeStream(void* param) {
if (last_fake_stream_)
delete last_fake_stream_;
}
// Copyright (c) 2009 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.
//
// A fake implementation of AudioOutputStream. It is used for testing purpose.
// TODO(hclam): Implement a thread in this fake output stream to simulate an
// audio output stream reading from AudioSourceCallback.
#ifndef MEDIA_AUDIO_FAKE_AUDIO_OUTPUT_STREAM_H_
#define MEDIA_AUDIO_FAKE_AUDIO_OUTOUT_STREAM_H_
#include <vector>
#include "base/scoped_ptr.h"
#include "media/audio/audio_output.h"
class FakeAudioOutputStream : public AudioOutputStream {
public:
static AudioOutputStream* MakeFakeStream();
static FakeAudioOutputStream* GetLastFakeStream();
virtual bool Open(size_t packet_size);
virtual void Start(AudioSourceCallback* callback);
virtual void Stop();
virtual void SetVolume(double left_level, double right_level);
virtual void GetVolume(double* left_level, double* right_level);
virtual void Close();
char* buffer() { return buffer_.get(); }
double left_volume() { return left_volume_; }
double right_volume() { return right_volume_; }
private:
FakeAudioOutputStream();
virtual ~FakeAudioOutputStream() {}
static void DestroyLastFakeStream(void* param);
static bool has_created_fake_stream_;
static FakeAudioOutputStream* last_fake_stream_;
double left_volume_;
double right_volume_;
AudioSourceCallback* callback_;
scoped_array<char> buffer_;
size_t packet_size_;
DISALLOW_COPY_AND_ASSIGN(FakeAudioOutputStream);
};
#endif // MEDIA_AUDIO_FAKE_AUDIO_OUTPUT_STREAM_H_
......@@ -527,7 +527,3 @@ void AlsaPCMOutputStream::SetVolume(double left_level, double right_level) {
void AlsaPCMOutputStream::GetVolume(double* left_level, double* right_level) {
NOTIMPLEMENTED();
}
size_t AlsaPCMOutputStream::GetNumBuffers() {
return 0;
}
......@@ -65,7 +65,6 @@ class AlsaPCMOutputStream :
virtual void Stop();
virtual void SetVolume(double left_level, double right_level);
virtual void GetVolume(double* left_level, double* right_level);
virtual size_t GetNumBuffers();
private:
// Closes the playback handle, reporting errors if any occur. Returns true
......
......@@ -6,6 +6,7 @@
#include "base/at_exit.h"
#include "base/logging.h"
#include "media/audio/fake_audio_output_stream.h"
#include "media/audio/linux/alsa_output.h"
namespace {
......@@ -27,11 +28,15 @@ AudioOutputStream* AudioManagerLinux::MakeAudioStream(Format format,
// surround40, surround51, etc.
//
// http://0pointer.de/blog/projects/guide-to-sound-apis.html
AlsaPCMOutputStream* stream =
new AlsaPCMOutputStream(AlsaPCMOutputStream::kDefaultDevice,
100 /* 100ms minimal buffer */,
format, channels, sample_rate, bits_per_sample);
return stream;
if (format == AudioManager::AUDIO_MOCK) {
return FakeAudioOutputStream::MakeFakeStream();
} else {
AlsaPCMOutputStream* stream =
new AlsaPCMOutputStream(AlsaPCMOutputStream::kDefaultDevice,
100 /* 100ms minimal buffer */,
format, channels, sample_rate, bits_per_sample);
return stream;
}
}
AudioManagerLinux::AudioManagerLinux() {
......@@ -50,12 +55,6 @@ void AudioManagerLinux::UnMuteAll() {
NOTIMPLEMENTED();
}
const void* AudioManagerLinux::GetLastMockBuffer() {
// TODO(ajwong): Implement.
NOTIMPLEMENTED();
return NULL;
}
// TODO(ajwong): Collapse this with the windows version.
void DestroyAudioManagerLinux(void* not_used) {
delete g_audio_manager;
......
......@@ -19,7 +19,6 @@ class AudioManagerLinux : public AudioManager {
char bits_per_sample);
virtual void MuteAll();
virtual void UnMuteAll();
virtual const void* GetLastMockBuffer();
private:
// Friend function for invoking the private destructor at exit.
......
......@@ -5,6 +5,7 @@
#include <CoreAudio/AudioHardware.h>
#include "base/at_exit.h"
#include "media/audio/fake_audio_output_stream.h"
#include "media/audio/mac/audio_manager_mac.h"
#include "media/audio/mac/audio_output_mac.h"
......@@ -19,8 +20,9 @@ bool AudioManagerMac::HasAudioDevices() {
AudioOutputStream* AudioManagerMac::MakeAudioStream(Format format, int channels,
int sample_rate,
char bits_per_sample) {
// TODO(cpu): add mock format.
if (format != AUDIO_PCM_LINEAR)
if (format == AUDIO_MOCK)
return FakeAudioOutputStream::MakeFakeStream();
else if (format != AUDIO_PCM_LINEAR)
return NULL;
return new PCMQueueOutAudioOutputStream(this, channels, sample_rate,
bits_per_sample);
......@@ -34,19 +36,15 @@ void AudioManagerMac::UnMuteAll() {
// TODO(cpu): implement.
}
const void* AudioManagerMac::GetLastMockBuffer() {
// TODO(cpu): implement.
return NULL;
}
// Called by the stream when it has been released by calling Close().
void AudioManagerMac::ReleaseStream(PCMQueueOutAudioOutputStream* stream) {
delete stream;
}
namespace {
AudioManagerMac* g_audio_manager = NULL;
AudioManagerMac* g_audio_manager = NULL;
} // namespace.
void DestroyAudioManagerMac(void* param) {
......
......@@ -24,7 +24,6 @@ class AudioManagerMac : public AudioManager {
char bits_per_sample);
virtual void MuteAll();
virtual void UnMuteAll();
virtual const void* GetLastMockBuffer();
// Mac-only method to free a stream created in MakeAudioStream.
// It is called internally by the audio stream when it has been closed.
......
......@@ -145,10 +145,6 @@ void PCMQueueOutAudioOutputStream::GetVolume(double* left_level,
// TODO(cpu): Implement.
}
size_t PCMQueueOutAudioOutputStream::GetNumBuffers() {
return kNumBuffers;
}
// Note to future hackers of this function: Do not add locks here because we
// call out to third party source that might do crazy things including adquire
// external locks or somehow re-enter here because its legal for them to call
......
......@@ -35,7 +35,6 @@ class PCMQueueOutAudioOutputStream : public AudioOutputStream {
virtual void Stop();
virtual void SetVolume(double left_level, double right_level);
virtual void GetVolume(double* left_level, double* right_level);
virtual size_t GetNumBuffers();
private:
// The audio is double buffered.
......
......@@ -118,7 +118,7 @@ void PushSource::CleanUp() {
AutoLock auto_lock(lock_);
PacketList::const_iterator it;
for (it = packets_.begin(); it != packets_.end(); ++it) {
delete it->buffer;
delete [] it->buffer;
buffered_bytes_ -= it->size;
}
packets_.clear();
......
......@@ -6,6 +6,7 @@
#include "base/basictypes.h"
#include "base/scoped_ptr.h"
#include "base/time.h"
#include "media/audio/fake_audio_output_stream.h"
#include "media/audio/simple_sources.h"
#include "testing/gtest/include/gtest/gtest.h"
......@@ -60,3 +61,48 @@ TEST(SimpleSourcesTest, PushSourceSmallerWrite) {
push_source.OnClose(NULL);
}
// 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(SimpleSources, 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();
ASSERT_TRUE(FakeAudioOutputStream::GetLastFakeStream());
const int16* last_buffer =
reinterpret_cast<int16*>(
FakeAudioOutputStream::GetLastFakeStream()->buffer());
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]);
}
......@@ -11,7 +11,6 @@
#include "media/audio/audio_output.h"
class PCMWaveOutAudioOutputStream;
class AudioOutputStreamMockWin;
// Windows implementation of the AudioManager singleton. This class is internal
// to the audio output and only internal users can call methods not exposed by
......@@ -26,12 +25,10 @@ class AudioManagerWin : public AudioManager {
char bits_per_sample);
virtual void MuteAll();
virtual void UnMuteAll();
virtual const void* GetLastMockBuffer();
// Windows-only methods to free a stream created in MakeAudioStream. These
// are called internally by the audio stream when it has been closed.
void ReleaseStream(PCMWaveOutAudioOutputStream* stream);
void ReleaseStream(AudioOutputStreamMockWin* stream);
private:
friend void DestroyAudioManagerWin(void *);
......
......@@ -9,81 +9,10 @@
#include "base/at_exit.h"
#include "base/basictypes.h"
#include "media/audio/fake_audio_output_stream.h"
#include "media/audio/win/audio_manager_win.h"
#include "media/audio/win/waveout_output_win.h"
// A do-nothing audio stream. It behaves like a regular audio stream but does
// not have any side effect, except possibly the creation and tear-down of
// of a thread. It is useful to test code that uses audio streams such as
// audio sources.
class AudioOutputStreamMockWin : public AudioOutputStream {
public:
explicit AudioOutputStreamMockWin(AudioManagerWin* manager)
: manager_(manager),
callback_(NULL),
buffer_(NULL),
packet_size_(0),
left_volume_(1.0),
right_volume_(1.0) {
}
virtual ~AudioOutputStreamMockWin() {
delete[] buffer_;
packet_size_ = 0;
}
virtual bool Open(size_t packet_size) {
if (packet_size < sizeof(int16))
return false;
packet_size_ = packet_size;
buffer_ = new char[packet_size_];
return true;
}
virtual void Start(AudioSourceCallback* callback) {
callback_ = callback;
memset(buffer_, 0, packet_size_);
callback_->OnMoreData(this, buffer_, packet_size_);
}
// TODO(cpu): flesh out Start and Stop methods. We need a thread to
// perform periodic callbacks.
virtual void Stop() {
}
virtual void SetVolume(double left_level, double right_level) {
left_volume_ = left_level;
right_volume_ = right_level;
}
virtual void GetVolume(double* left_level, double* right_level) {
*left_level = left_volume_;
*right_level = right_volume_;
}
virtual size_t GetNumBuffers() {
return 1;
}
virtual void Close() {
callback_->OnClose(this);
callback_ = NULL;
manager_->ReleaseStream(this);
}
char* buffer() {
return buffer_;
}
private:
AudioManagerWin* manager_;
AudioSourceCallback* callback_;
char* buffer_;
size_t packet_size_;
double left_volume_;
double right_volume_;
};
namespace {
// The next 3 constants are some sensible limits to prevent integer overflow
......@@ -102,18 +31,10 @@ const int kMaxChannels = 6;
const int kMaxSampleRate = 192000;
const int kMaxBitsPerSample = 64;
AudioOutputStreamMockWin* g_last_mock_stream = NULL;
AudioManagerWin* g_audio_manager = NULL;
void ReplaceLastMockStream(AudioOutputStreamMockWin* newer) {
if (g_last_mock_stream)
delete g_last_mock_stream;
g_last_mock_stream = newer;
}
} // namespace.
bool AudioManagerWin::HasAudioDevices() {
return (::waveOutGetNumDevs() != 0);
}
......@@ -122,7 +43,6 @@ bool AudioManagerWin::HasAudioDevices() {
// should suffice most windows user's needs.
// - PCMWaveOutAudioOutputStream: Based on the waveOutWrite API (in progress)
// - PCMDXSoundAudioOutputStream: Based on DirectSound or XAudio (future work).
AudioOutputStream* AudioManagerWin::MakeAudioStream(Format format, int channels,
int sample_rate,
char bits_per_sample) {
......@@ -132,7 +52,7 @@ AudioOutputStream* AudioManagerWin::MakeAudioStream(Format format, int channels,
return NULL;
if (format == AUDIO_MOCK) {
return new AudioOutputStreamMockWin(this);
return FakeAudioOutputStream::MakeFakeStream();
} else if (format == AUDIO_PCM_LINEAR) {
return new PCMWaveOutAudioOutputStream(this, channels, sample_rate,
bits_per_sample, WAVE_MAPPER);
......@@ -145,15 +65,6 @@ void AudioManagerWin::ReleaseStream(PCMWaveOutAudioOutputStream* stream) {
delete stream;
}
void AudioManagerWin::ReleaseStream(AudioOutputStreamMockWin *stream) {
// Note that we keep the last mock stream so GetLastMockBuffer() works.
ReplaceLastMockStream(stream);
}
const void* AudioManagerWin::GetLastMockBuffer() {
return (g_last_mock_stream) ? g_last_mock_stream->buffer() : NULL;
}
void AudioManagerWin::MuteAll() {
}
......@@ -161,7 +72,6 @@ void AudioManagerWin::UnMuteAll() {
}
AudioManagerWin::~AudioManagerWin() {
ReplaceLastMockStream(NULL);
}
void DestroyAudioManagerWin(void* param) {
......
......@@ -193,51 +193,6 @@ TEST(WinAudioTest, MockStreamBasicCallbacks) {
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.
// TODO(hclam): move this test to SimpleSourcesTest once mock audio stream is
// implemented on other platform.
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
//
......
......@@ -215,10 +215,6 @@ void PCMWaveOutAudioOutputStream::GetVolume(double* left_level,
*right_level = volume_;
}
size_t PCMWaveOutAudioOutputStream::GetNumBuffers() {
return kNumBuffers;
}
void PCMWaveOutAudioOutputStream::HandleError(MMRESULT error) {
DLOG(WARNING) << "PCMWaveOutAudio error " << error;
callback_->OnError(this, error);
......
......@@ -40,7 +40,6 @@ class PCMWaveOutAudioOutputStream : public AudioOutputStream {
virtual void Stop();
virtual void SetVolume(double left_level, double right_level);
virtual void GetVolume(double* left_level, double* right_level);
virtual size_t GetNumBuffers();
// Sends a buffer to the audio driver for playback.
void QueueNextPacket(WAVEHDR* buffer);
......
......@@ -32,6 +32,8 @@
'audio/audio_output.h',
'audio/audio_util.cc',
'audio/audio_util.h',
'audio/fake_audio_output_stream.cc',
'audio/fake_audio_output_stream.h',
'audio/linux/audio_manager_linux.cc',
'audio/linux/audio_manager_linux.h',
'audio/linux/alsa_output.cc',
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment