diff options
author | cpu@chromium.org <cpu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-14 22:37:35 +0000 |
---|---|---|
committer | cpu@chromium.org <cpu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-14 22:37:35 +0000 |
commit | 0bbca872a2407e598d4c9257700568c17f591e78 (patch) | |
tree | e414bdd9db2ba45bebf0e5724daad6c4c6728918 /media/audio | |
parent | 5d5f7e314f9b4997c0f02cc2bc0e12f6c227f398 (diff) | |
download | chromium_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.cc | 93 | ||||
-rw-r--r-- | media/audio/mac/audio_manager_mac.h | 38 | ||||
-rw-r--r-- | media/audio/mac/audio_output_mac.cc | 55 | ||||
-rw-r--r-- | media/audio/mac/audio_output_mac_unittest.cc | 26 | ||||
-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 |