diff options
author | cpu@chromium.org <cpu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-25 02:25:08 +0000 |
---|---|---|
committer | cpu@chromium.org <cpu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-25 02:25:08 +0000 |
commit | c1fb279fc643f24d300683f39c66efb68e69e2df (patch) | |
tree | 1750508fa4ae204a055bd11dc8db62d63fd7cfba /media/audio | |
parent | e35ac56ba6d1be8c6c61f6614e1f6800f64d663c (diff) | |
download | chromium_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.cc | 65 | ||||
-rw-r--r-- | media/audio/mac/audio_output_mac.cc | 120 | ||||
-rw-r--r-- | media/audio/mac/audio_output_mac.h | 63 | ||||
-rw-r--r-- | media/audio/mac/audio_output_mac_unittest.cc | 34 |
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(); +} |