summaryrefslogtreecommitdiffstats
path: root/media/audio
diff options
context:
space:
mode:
authorcpu@chromium.org <cpu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-25 02:25:08 +0000
committercpu@chromium.org <cpu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-25 02:25:08 +0000
commitc1fb279fc643f24d300683f39c66efb68e69e2df (patch)
tree1750508fa4ae204a055bd11dc8db62d63fd7cfba /media/audio
parente35ac56ba6d1be8c6c61f6614e1f6800f64d663c (diff)
downloadchromium_src-c1fb279fc643f24d300683f39c66efb68e69e2df.zip
chromium_src-c1fb279fc643f24d300683f39c66efb68e69e2df.tar.gz
chromium_src-c1fb279fc643f24d300683f39c66efb68e69e2df.tar.bz2
First part of the Mac Audio low level support
- Basic factory support for 16 PCM audio - Adds PCM audio using Queue Services - Many functions not implemented, trying to keep CLs to a decent size - Added two unit tests Review URL: http://codereview.chromium.org/42494 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@12431 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/audio')
-rw-r--r--media/audio/mac/audio_manager_mac.cc65
-rw-r--r--media/audio/mac/audio_output_mac.cc120
-rw-r--r--media/audio/mac/audio_output_mac.h63
-rw-r--r--media/audio/mac/audio_output_mac_unittest.cc34
4 files changed, 278 insertions, 4 deletions
diff --git a/media/audio/mac/audio_manager_mac.cc b/media/audio/mac/audio_manager_mac.cc
index 15a13b2..cae40a9 100644
--- a/media/audio/mac/audio_manager_mac.cc
+++ b/media/audio/mac/audio_manager_mac.cc
@@ -1,10 +1,67 @@
-// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// 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 "media/audio/audio_output.h"
+#include <CoreAudio/AudioHardware.h>
-// TODO(hclam): Do something more useful than returning NULL.
+#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));
+ }
+
+ 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);
+ }
+
+ virtual void MuteAll() {
+ // TODO(cpu): implement.
+ }
+
+ virtual void UnMuteAll() {
+ // TODO(cpu): implement.
+ }
+
+ virtual const void* GetLastMockBuffer() {
+ // TODO(cpu): implement.
+ return NULL;
+ }
+
+ // Called by the stream when it has been released by calling Close().
+ void ReleaseStream(PCMQueueOutAudioOutputStream* stream) {
+ delete stream;
+ }
+
+ private:
+ virtual ~AudioManagerMac() {}
+ DISALLOW_COPY_AND_ASSIGN(AudioManagerMac);
+};
+
+// By convention, the AudioManager is not thread safe.
AudioManager* AudioManager::GetAudioManager() {
- return NULL;
+ // TODO(cpu): Do not leak singleton.
+ static AudioManagerMac* instance = NULL;
+ if (!instance) {
+ instance = new AudioManagerMac();
+ }
+ return instance;
}
+
diff --git a/media/audio/mac/audio_output_mac.cc b/media/audio/mac/audio_output_mac.cc
new file mode 100644
index 0000000..3866a56
--- /dev/null
+++ b/media/audio/mac/audio_output_mac.cc
@@ -0,0 +1,120 @@
+// 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 "media/audio/mac/audio_output_mac.h"
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+PCMQueueOutAudioOutputStream::PCMQueueOutAudioOutputStream(
+ AudioManagerMac* manager, int channels, int sampling_rate,
+ char bits_per_sample)
+ : format_(),
+ audio_queue_(NULL),
+ buffer_(),
+ source_(NULL),
+ manager_(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.
+ format_.mSampleRate = sampling_rate;
+ format_.mFormatID = kAudioFormatLinearPCM;
+ format_.mFormatFlags = kLinearPCMFormatFlagIsPacked |
+ kLinearPCMFormatFlagIsSignedInteger;
+ format_.mBitsPerChannel = bits_per_sample;
+ format_.mBytesPerFrame = format_.mBytesPerPacket;
+ format_.mChannelsPerFrame = channels;
+ format_.mFramesPerPacket = 1;
+ format_.mBytesPerPacket = (format_.mBitsPerChannel * channels) / 8;
+}
+
+PCMQueueOutAudioOutputStream::~PCMQueueOutAudioOutputStream() {
+}
+
+void PCMQueueOutAudioOutputStream::HandleError(OSStatus err) {
+ if (source_)
+ source_->OnError(this, static_cast<int>(err));
+ NOTREACHED() << "error code " << err;
+}
+
+bool PCMQueueOutAudioOutputStream::Open(size_t packet_size) {
+ if (0 == packet_size) {
+ // TODO(cpu) : Impelement default buffer computation.
+ return false;
+ }
+ // Create the actual queue object and let the OS use its own thread to
+ // run its CFRunLoop.
+ OSStatus err = AudioQueueNewOutput(&format_, RenderCallback, this, NULL,
+ kCFRunLoopCommonModes, 0, &audio_queue_);
+ if (err != noErr) {
+ HandleError(err);
+ return false;
+ }
+ // Allocate the hardware-managed buffers.
+ for(size_t ix = 0; ix != kNumBuffers; ++ix) {
+ err = AudioQueueAllocateBuffer(audio_queue_, packet_size, &buffer_[ix]);
+ if (err != noErr) {
+ HandleError(err);
+ return false;
+ }
+ }
+ // Set initial volume here.
+ err = AudioQueueSetParameter(audio_queue_, kAudioQueueParam_Volume, 1.0);
+ if (err != noErr) {
+ HandleError(err);
+ return false;
+ }
+ return true;
+}
+
+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;
+ }
+ }
+ }
+ 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.
+}
+
+void PCMQueueOutAudioOutputStream::Stop() {
+ // TODO(cpu): Implement.
+}
+
+void PCMQueueOutAudioOutputStream::SetVolume(double left_level,
+ double right_level) {
+ // TODO(cpu): Implement.
+}
+
+void PCMQueueOutAudioOutputStream::GetVolume(double* left_level,
+ double* right_level) {
+ // TODO(cpu): Implement.
+}
+
+void PCMQueueOutAudioOutputStream::RenderCallback(void* p_this,
+ AudioQueueRef queue,
+ AudioQueueBufferRef buffer) {
+ // TODO(cpu): Implement.
+}
+
+void PCMQueueOutAudioOutputStream::Start(AudioSourceCallback* callback) {
+ OSStatus err = AudioQueueStart(audio_queue_, NULL);
+ if (err != noErr) {
+ HandleError(err);
+ return;
+ }
+ // TODO(cpu) : Prefill the avaiable buffers.
+}
diff --git a/media/audio/mac/audio_output_mac.h b/media/audio/mac/audio_output_mac.h
new file mode 100644
index 0000000..eb3c091
--- /dev/null
+++ b/media/audio/mac/audio_output_mac.h
@@ -0,0 +1,63 @@
+// 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_OUTPUT_MAC_H_
+#define MEDIA_AUDIO_MAC_OUTPUT_MAC_H_
+
+#include <AudioToolbox/AudioQueue.h>
+#include <AudioToolbox/AudioFormat.h>
+
+#include "media/audio/audio_output.h"
+
+#include "base/basictypes.h"
+
+class AudioManagerMac;
+
+// Implementation of AudioOuputStream for Mac OS X using the audio queue service
+// present in OS 10.5 and later. Audioqueue is the successor to the SoundManager
+// services but it is supported in 64 bits.
+class PCMQueueOutAudioOutputStream : public AudioOutputStream {
+ public:
+ // The ctor takes all the usual parameters, plus |manager| which is the
+ // the audio manager who is creating this object.
+ PCMQueueOutAudioOutputStream(AudioManagerMac* manager,
+ int channels, int sampling_rate,
+ char bits_per_sample);
+ // The dtor is typically called by the AudioManager only and it is usually
+ // triggered by calling AudioOutputStream::Close().
+ virtual ~PCMQueueOutAudioOutputStream();
+
+ // Implementation of AudioOutputStream.
+ virtual bool Open(size_t packet_size);
+ virtual void Close();
+ 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);
+
+ private:
+ // The audio is double buffered.
+ static const size_t kNumBuffers = 2;
+
+ // The OS calls back here when an audio buffer has been processed.
+ static void RenderCallback(void* p_this, AudioQueueRef queue,
+ AudioQueueBufferRef buffer);
+ // Called when an error occurs.
+ void HandleError(OSStatus err);
+
+ // Structure that holds the stream format details such as bitrate.
+ AudioStreamBasicDescription format_;
+ // Handle to the OS audio queue object.
+ AudioQueueRef audio_queue_;
+ // Array of pointers to the OS managed audio buffers.
+ AudioQueueBufferRef buffer_[kNumBuffers];
+ // Pointer to the object that will provide the audio samples.
+ AudioSourceCallback* source_;
+ // Our creator, the audio manager needs to be notified when we close.
+ AudioManagerMac* manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(PCMQueueOutAudioOutputStream);
+};
+
+#endif // MEDIA_AUDIO_MAC_OUTPUT_MAC_H_
diff --git a/media/audio/mac/audio_output_mac_unittest.cc b/media/audio/mac/audio_output_mac_unittest.cc
new file mode 100644
index 0000000..c1f67e1
--- /dev/null
+++ b/media/audio/mac/audio_output_mac_unittest.cc
@@ -0,0 +1,34 @@
+// 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/basictypes.h"
+#include "media/audio/audio_output.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// 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())
+ return;
+ AudioOutputStream* oas =
+ audio_man->MakeAudioStream(AudioManager::AUDIO_PCM_LINEAR, 2, 8000, 16);
+ ASSERT_TRUE(NULL != oas);
+ oas->Close();
+}
+
+// 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())
+ return;
+ AudioOutputStream* oas =
+ audio_man->MakeAudioStream(AudioManager::AUDIO_PCM_LINEAR, 2, 8000, 16);
+ ASSERT_TRUE(NULL != oas);
+ EXPECT_TRUE(oas->Open(1024));
+ oas->Close();
+}