summaryrefslogtreecommitdiffstats
path: root/media/audio
diff options
context:
space:
mode:
authorcpu@chromium.org <cpu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-14 22:37:35 +0000
committercpu@chromium.org <cpu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-14 22:37:35 +0000
commit0bbca872a2407e598d4c9257700568c17f591e78 (patch)
treee414bdd9db2ba45bebf0e5724daad6c4c6728918 /media/audio
parent5d5f7e314f9b4997c0f02cc2bc0e12f6c227f398 (diff)
downloadchromium_src-0bbca872a2407e598d4c9257700568c17f591e78.zip
chromium_src-0bbca872a2407e598d4c9257700568c17f591e78.tar.gz
chromium_src-0bbca872a2407e598d4c9257700568c17f591e78.tar.bz2
Second part of the low level audio for Mac
-Fixed leaks (audiomanager singleton, audiostream) -Moved simple_sources to be common for all platforms -Added trivial check for sinesource -Added some logic on the audio callback, not used yet Review URL: http://codereview.chromium.org/67058 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@13713 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/audio')
-rw-r--r--media/audio/mac/audio_manager_mac.cc93
-rw-r--r--media/audio/mac/audio_manager_mac.h38
-rw-r--r--media/audio/mac/audio_output_mac.cc55
-rw-r--r--media/audio/mac/audio_output_mac_unittest.cc26
-rw-r--r--media/audio/simple_sources.cc (renamed from media/audio/win/simple_sources_win.cc)0
5 files changed, 145 insertions, 67 deletions
diff --git a/media/audio/mac/audio_manager_mac.cc b/media/audio/mac/audio_manager_mac.cc
index cae40a9..7a8e15b 100644
--- a/media/audio/mac/audio_manager_mac.cc
+++ b/media/audio/mac/audio_manager_mac.cc
@@ -4,64 +4,61 @@
#include <CoreAudio/AudioHardware.h>
+#include "base/at_exit.h"
+#include "media/audio/mac/audio_manager_mac.h"
#include "media/audio/mac/audio_output_mac.h"
-// Mac OS X implementation of the AudioManager singleton. This class is internal
-// to the audio output and only internal users can call methods not exposed by
-// the AudioManager class.
-class AudioManagerMac : public AudioManager {
- public:
- AudioManagerMac() {
- }
-
- virtual bool HasAudioDevices() {
- AudioDeviceID output_device_id = 0;
- size_t size = sizeof(output_device_id);
- OSStatus err = AudioHardwareGetProperty(
- kAudioHardwarePropertyDefaultOutputDevice, &size, &output_device_id);
- return ((err == noErr) && (output_device_id > 0));
- }
+bool AudioManagerMac::HasAudioDevices() {
+ AudioDeviceID output_device_id = 0;
+ size_t size = sizeof(output_device_id);
+ OSStatus err = AudioHardwareGetProperty(
+ kAudioHardwarePropertyDefaultOutputDevice, &size, &output_device_id);
+ return ((err == noErr) && (output_device_id > 0));
+}
- virtual AudioOutputStream* MakeAudioStream(Format format, int channels,
- int sample_rate,
- char bits_per_sample) {
- // TODO(cpu): add mock format.
- if (format != AUDIO_PCM_LINEAR)
- return NULL;
- return new PCMQueueOutAudioOutputStream(this, channels, sample_rate,
- bits_per_sample);
- }
+AudioOutputStream* AudioManagerMac::MakeAudioStream(Format format, int channels,
+ int sample_rate,
+ char bits_per_sample) {
+ // TODO(cpu): add mock format.
+ if (format != AUDIO_PCM_LINEAR)
+ return NULL;
+ return new PCMQueueOutAudioOutputStream(this, channels, sample_rate,
+ bits_per_sample);
+}
- virtual void MuteAll() {
- // TODO(cpu): implement.
- }
+void AudioManagerMac::MuteAll() {
+ // TODO(cpu): implement.
+}
- virtual void UnMuteAll() {
- // TODO(cpu): implement.
- }
+void AudioManagerMac::UnMuteAll() {
+ // TODO(cpu): implement.
+}
- virtual const void* GetLastMockBuffer() {
- // TODO(cpu): implement.
- return NULL;
- }
+const void* AudioManagerMac::GetLastMockBuffer() {
+ // TODO(cpu): implement.
+ return NULL;
+}
- // Called by the stream when it has been released by calling Close().
- void ReleaseStream(PCMQueueOutAudioOutputStream* stream) {
- delete stream;
- }
+// Called by the stream when it has been released by calling Close().
+void AudioManagerMac::ReleaseStream(PCMQueueOutAudioOutputStream* stream) {
+ delete stream;
+}
- private:
- virtual ~AudioManagerMac() {}
- DISALLOW_COPY_AND_ASSIGN(AudioManagerMac);
-};
+namespace {
+ AudioManagerMac* g_audio_manager = NULL;
+
+} // namespace.
+
+void DestroyAudioManagerMac(void* param) {
+ delete g_audio_manager;
+ g_audio_manager = NULL;
+}
// By convention, the AudioManager is not thread safe.
AudioManager* AudioManager::GetAudioManager() {
- // TODO(cpu): Do not leak singleton.
- static AudioManagerMac* instance = NULL;
- if (!instance) {
- instance = new AudioManagerMac();
+ if (!g_audio_manager) {
+ g_audio_manager = new AudioManagerMac();
+ base::AtExitManager::RegisterCallback(&DestroyAudioManagerMac, NULL);
}
- return instance;
+ return g_audio_manager;
}
-
diff --git a/media/audio/mac/audio_manager_mac.h b/media/audio/mac/audio_manager_mac.h
new file mode 100644
index 0000000..670b51c
--- /dev/null
+++ b/media/audio/mac/audio_manager_mac.h
@@ -0,0 +1,38 @@
+// 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.
+
+#ifndef MEDIA_AUDIO_MAC_AUDIO_MANAGER_MAC_H_
+#define MEDIA_AUDIO_MAC_AUDIO_MANAGER_MAC_H_
+
+#include "base/basictypes.h"
+#include "media/audio/audio_output.h"
+
+class PCMQueueOutAudioOutputStream;
+
+// Mac OS X implementation of the AudioManager singleton. This class is internal
+// to the audio output and only internal users can call methods not exposed by
+// the AudioManager class.
+class AudioManagerMac : public AudioManager {
+public:
+ AudioManagerMac() {};
+ // Implementation of AudioManager.
+ virtual bool HasAudioDevices();
+ virtual AudioOutputStream* MakeAudioStream(Format format, int channels,
+ int sample_rate,
+ 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.
+ void ReleaseStream(PCMQueueOutAudioOutputStream* stream);
+
+private:
+ friend void DestroyAudioManagerMac(void *);
+ virtual ~AudioManagerMac() {};
+ DISALLOW_COPY_AND_ASSIGN(AudioManagerMac);
+};
+
+#endif // MEDIA_AUDIO_MAC_AUDIO_MANAGER_MAC_H_
diff --git a/media/audio/mac/audio_output_mac.cc b/media/audio/mac/audio_output_mac.cc
index da6772f..019baac 100644
--- a/media/audio/mac/audio_output_mac.cc
+++ b/media/audio/mac/audio_output_mac.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "media/audio/mac/audio_manager_mac.h"
#include "media/audio/mac/audio_output_mac.h"
#include "base/basictypes.h"
@@ -15,6 +16,8 @@ PCMQueueOutAudioOutputStream::PCMQueueOutAudioOutputStream(
buffer_(),
source_(NULL),
manager_(manager) {
+ // We must have a manager.
+ DCHECK(manager_);
// A frame is one sample across all channels. In interleaved audio the per
// frame fields identify the set of n |channels|. In uncompressed audio, a
// packet is always one frame.
@@ -69,25 +72,27 @@ bool PCMQueueOutAudioOutputStream::Open(size_t packet_size) {
}
void PCMQueueOutAudioOutputStream::Close() {
- // It is valid to call Close() before calling Open().
- if (!audio_queue_)
- return;
- OSStatus err = 0;
- for (size_t ix = 0; ix != kNumBuffers; ++ix) {
- if (buffer_[ix]) {
- err = AudioQueueFreeBuffer(audio_queue_, buffer_[ix]);
- if (err) {
- HandleError(err);
- break;
+ // It is valid to call Close() before calling Open(), thus audio_queue_
+ // might be NULL.
+ if (audio_queue_) {
+ OSStatus err = 0;
+ for (size_t ix = 0; ix != kNumBuffers; ++ix) {
+ if (buffer_[ix]) {
+ err = AudioQueueFreeBuffer(audio_queue_, buffer_[ix]);
+ if (err) {
+ HandleError(err);
+ break;
+ }
}
}
+ err = AudioQueueDispose(audio_queue_, true);
+ if (err) {
+ HandleError(err);
+ }
}
- err = AudioQueueDispose(audio_queue_, true);
- if (err) {
- HandleError(err);
- }
- // TODO(cpu): Inform the audio manager that we have been closed
- // right now we leak because of that.
+ // Inform the audio manager that we have been closed. This can cause our
+ // destruction.
+ manager_->ReleaseStream(this);
}
void PCMQueueOutAudioOutputStream::Stop() {
@@ -111,7 +116,23 @@ size_t PCMQueueOutAudioOutputStream::GetNumBuffers() {
void PCMQueueOutAudioOutputStream::RenderCallback(void* p_this,
AudioQueueRef queue,
AudioQueueBufferRef buffer) {
- // TODO(cpu): Implement.
+ PCMQueueOutAudioOutputStream* audio_stream =
+ static_cast<PCMQueueOutAudioOutputStream*>(p_this);
+ // Call the audio source to fill the free buffer with data.
+ size_t capacity = buffer->mAudioDataBytesCapacity;
+ size_t filled = audio_stream->source_->OnMoreData(audio_stream,
+ buffer->mAudioData,
+ capacity);
+ if (filled > capacity) {
+ // User probably overran our buffer.
+ audio_stream->HandleError(0);
+ return;
+ }
+ // Queue the audio data to the audio driver.
+ buffer->mAudioDataByteSize = filled;
+ OSStatus err = AudioQueueEnqueueBuffer(queue, buffer, 0, NULL);
+ if (err != noErr)
+ audio_stream->HandleError(err);
}
void PCMQueueOutAudioOutputStream::Start(AudioSourceCallback* callback) {
diff --git a/media/audio/mac/audio_output_mac_unittest.cc b/media/audio/mac/audio_output_mac_unittest.cc
index c1f67e1..6b357e7 100644
--- a/media/audio/mac/audio_output_mac_unittest.cc
+++ b/media/audio/mac/audio_output_mac_unittest.cc
@@ -4,11 +4,34 @@
#include "base/basictypes.h"
#include "media/audio/audio_output.h"
+#include "media/audio/simple_sources.h"
#include "testing/gtest/include/gtest/gtest.h"
+
+// Validate that the SineWaveAudioSource writes the expected values for
+// the FORMAT_16BIT_MONO.
+TEST(MacAudioTest, SineWaveAudio16MonoTest) {
+ const size_t samples = 1024;
+ const int freq = 200;
+
+ SineWaveAudioSource source(SineWaveAudioSource::FORMAT_16BIT_LINEAR_PCM, 1,
+ freq, AudioManager::kTelephoneSampleRate);
+
+ // TODO(cpu): Put the real test when the mock renderer is ported.
+ int16 buffer[samples] = { 0xffff };
+ source.OnMoreData(NULL, buffer, sizeof(buffer));
+ EXPECT_EQ(0, buffer[0]);
+ EXPECT_EQ(5126, buffer[1]);
+}
+
+// ===========================================================================
+// Validation of AudioManager::AUDIO_PCM_LINEAR
+//
+// Unlike windows, the tests can reliably detect the existense of real
+// audio devices on the bots thus no need for 'headless' detection.
+
// Test that can it be created and closed.
TEST(MacAudioTest, PCMWaveStreamGetAndClose) {
- // TODO(cpu) : skip if headless.
AudioManager* audio_man = AudioManager::GetAudioManager();
ASSERT_TRUE(NULL != audio_man);
if (!audio_man->HasAudioDevices())
@@ -21,7 +44,6 @@ TEST(MacAudioTest, PCMWaveStreamGetAndClose) {
// Test that it can be opened and closed.
TEST(MacAudioTest, PCMWaveStreamOpenAndClose) {
- // TODO(cpu) : skip if headless.
AudioManager* audio_man = AudioManager::GetAudioManager();
ASSERT_TRUE(NULL != audio_man);
if (!audio_man->HasAudioDevices())
diff --git a/media/audio/win/simple_sources_win.cc b/media/audio/simple_sources.cc
index b6fda23..b6fda23 100644
--- a/media/audio/win/simple_sources_win.cc
+++ b/media/audio/simple_sources.cc