Chromium Code Reviews| OLD | NEW | 
|---|---|
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include <CoreAudio/AudioHardware.h> | 5 #include <CoreAudio/AudioHardware.h> | 
| 6 | 6 | 
| 7 #include "base/sys_info.h" | |
| 7 #include "media/audio/fake_audio_input_stream.h" | 8 #include "media/audio/fake_audio_input_stream.h" | 
| 8 #include "media/audio/fake_audio_output_stream.h" | 9 #include "media/audio/fake_audio_output_stream.h" | 
| 9 #include "media/audio/mac/audio_input_mac.h" | 10 #include "media/audio/mac/audio_input_mac.h" | 
| 10 #include "media/audio/mac/audio_manager_mac.h" | 11 #include "media/audio/mac/audio_manager_mac.h" | 
| 11 #include "media/audio/mac/audio_output_mac.h" | 12 #include "media/audio/mac/audio_output_mac.h" | 
| 12 #include "media/base/limits.h" | 13 #include "media/base/limits.h" | 
| 13 | 14 | 
| 14 namespace { | 15 namespace { | 
| 16 | |
| 17 // Maximum number of output streams that can be open simultaneously. | |
| 18 const size_t kMaxOutputStreams = 50; | |
| 19 | |
| 20 // By experiment the maximum number of audio streams allowed in Leopard | |
| 21 // is 18. But we put a slightly smaller number just to be safe. | |
| 22 const size_t kMaxOutputStreamsLeopard = 15; | |
| 23 | |
| 15 const int kMaxInputChannels = 2; | 24 const int kMaxInputChannels = 2; | 
| 16 | 25 | 
| 26 // Returns the number of audio streams allowed. This is a practical limit to | |
| 27 // prevent failure caused by too many audio streams opened. | |
| 28 size_t GetMaxAudioOutputStreamsAllowed() { | |
| 
 
scherkus (not reviewing)
2010/11/29 22:42:13
what about caching the result as a static and lazy
 
Sergey Ulanov
2010/11/29 22:58:12
Done.
 
 | |
| 29 // We are hitting a bug in Leopard where too many audio streams will cause | |
| 30 // a deadlock in the AudioQueue API when starting the stream. Unfortunately | |
| 31 // there's no way to detect it within the AudioQueue API, so we put a | |
| 32 // special hard limit only for Leopard. | |
| 33 // See bug: http://crbug.com/30242 | |
| 34 int32 major, minor, bugfix; | |
| 35 base::SysInfo::OperatingSystemVersionNumbers(&major, &minor, &bugfix); | |
| 36 if (major < 10 || (major == 10 && minor <= 5)) | |
| 37 return kMaxOutputStreamsLeopard; | |
| 38 | |
| 39 // In OS other than OSX Leopard, the number of audio streams allowed is a | |
| 40 // lot more so we return a separate number. | |
| 41 return kMaxOutputStreams; | |
| 42 } | |
| 43 | |
| 17 bool HasAudioHardware(AudioObjectPropertySelector selector) { | 44 bool HasAudioHardware(AudioObjectPropertySelector selector) { | 
| 18 AudioDeviceID output_device_id = kAudioObjectUnknown; | 45 AudioDeviceID output_device_id = kAudioObjectUnknown; | 
| 19 const AudioObjectPropertyAddress property_address = { | 46 const AudioObjectPropertyAddress property_address = { | 
| 20 selector, | 47 selector, | 
| 21 kAudioObjectPropertyScopeGlobal, // mScope | 48 kAudioObjectPropertyScopeGlobal, // mScope | 
| 22 kAudioObjectPropertyElementMaster // mElement | 49 kAudioObjectPropertyElementMaster // mElement | 
| 23 }; | 50 }; | 
| 24 size_t output_device_id_size = sizeof(output_device_id); | 51 size_t output_device_id_size = sizeof(output_device_id); | 
| 25 OSStatus err = AudioObjectGetPropertyData(kAudioObjectSystemObject, | 52 OSStatus err = AudioObjectGetPropertyData(kAudioObjectSystemObject, | 
| 26 &property_address, | 53 &property_address, | 
| 27 0, // inQualifierDataSize | 54 0, // inQualifierDataSize | 
| 28 NULL, // inQualifierData | 55 NULL, // inQualifierData | 
| 29 &output_device_id_size, | 56 &output_device_id_size, | 
| 30 &output_device_id); | 57 &output_device_id); | 
| 31 return err == kAudioHardwareNoError && | 58 return err == kAudioHardwareNoError && | 
| 32 output_device_id != kAudioObjectUnknown; | 59 output_device_id != kAudioObjectUnknown; | 
| 33 } | 60 } | 
| 34 } // namespace | 61 } // namespace | 
| 35 | 62 | 
| 63 AudioManagerMac::AudioManagerMac() | |
| 64 : num_output_streams_(0), | |
| 65 max_output_streams_(GetMaxAudioOutputStreamsAllowed()) { | |
| 66 } | |
| 67 | |
| 36 bool AudioManagerMac::HasAudioOutputDevices() { | 68 bool AudioManagerMac::HasAudioOutputDevices() { | 
| 37 return HasAudioHardware(kAudioHardwarePropertyDefaultOutputDevice); | 69 return HasAudioHardware(kAudioHardwarePropertyDefaultOutputDevice); | 
| 38 } | 70 } | 
| 39 | 71 | 
| 40 bool AudioManagerMac::HasAudioInputDevices() { | 72 bool AudioManagerMac::HasAudioInputDevices() { | 
| 41 return HasAudioHardware(kAudioHardwarePropertyDefaultInputDevice); | 73 return HasAudioHardware(kAudioHardwarePropertyDefaultInputDevice); | 
| 42 } | 74 } | 
| 43 | 75 | 
| 44 AudioOutputStream* AudioManagerMac::MakeAudioOutputStream( | 76 AudioOutputStream* AudioManagerMac::MakeAudioOutputStream( | 
| 45 AudioParameters params) { | 77 AudioParameters params) { | 
| 46 if (params.format == AudioParameters::AUDIO_MOCK) | 78 if (params.format == AudioParameters::AUDIO_MOCK) { | 
| 47 return FakeAudioOutputStream::MakeFakeStream(params); | 79 return FakeAudioOutputStream::MakeFakeStream(params); | 
| 48 else if (params.format != AudioParameters::AUDIO_PCM_LINEAR) | 80 } else if (params.format != AudioParameters::AUDIO_PCM_LINEAR) { | 
| 49 return NULL; | 81 return NULL; | 
| 82 } | |
| 83 | |
| 84 // Limit the number of audio streams opened. This is to prevent using | |
| 85 // excessive resources for a large number of audio streams. More | |
| 86 // importantly it prevents instability on certain systems. | |
| 87 // See bug: http://crbug.com/30242 | |
| 88 if (num_output_streams_ >= max_output_streams_) { | |
| 89 return NULL; | |
| 90 } | |
| 91 | |
| 92 num_output_streams_++; | |
| 50 return new PCMQueueOutAudioOutputStream(this, params); | 93 return new PCMQueueOutAudioOutputStream(this, params); | 
| 51 } | 94 } | 
| 52 | 95 | 
| 53 AudioInputStream* AudioManagerMac::MakeAudioInputStream( | 96 AudioInputStream* AudioManagerMac::MakeAudioInputStream( | 
| 54 AudioParameters params) { | 97 AudioParameters params) { | 
| 55 if (!params.IsValid() || (params.channels > kMaxInputChannels)) | 98 if (!params.IsValid() || (params.channels > kMaxInputChannels)) | 
| 56 return NULL; | 99 return NULL; | 
| 57 | 100 | 
| 58 if (params.format == AudioParameters::AUDIO_MOCK) { | 101 if (params.format == AudioParameters::AUDIO_MOCK) { | 
| 59 return FakeAudioInputStream::MakeFakeStream(params); | 102 return FakeAudioInputStream::MakeFakeStream(params); | 
| 60 } else if (params.format == AudioParameters::AUDIO_PCM_LINEAR) { | 103 } else if (params.format == AudioParameters::AUDIO_PCM_LINEAR) { | 
| 61 return new PCMQueueInAudioInputStream(this, params); | 104 return new PCMQueueInAudioInputStream(this, params); | 
| 62 } | 105 } | 
| 63 return NULL; | 106 return NULL; | 
| 64 } | 107 } | 
| 65 | 108 | 
| 66 void AudioManagerMac::MuteAll() { | 109 void AudioManagerMac::MuteAll() { | 
| 67 // TODO(cpu): implement. | 110 // TODO(cpu): implement. | 
| 68 } | 111 } | 
| 69 | 112 | 
| 70 void AudioManagerMac::UnMuteAll() { | 113 void AudioManagerMac::UnMuteAll() { | 
| 71 // TODO(cpu): implement. | 114 // TODO(cpu): implement. | 
| 72 } | 115 } | 
| 73 | 116 | 
| 74 // Called by the stream when it has been released by calling Close(). | 117 // Called by the stream when it has been released by calling Close(). | 
| 75 void AudioManagerMac::ReleaseOutputStream( | 118 void AudioManagerMac::ReleaseOutputStream( | 
| 76 PCMQueueOutAudioOutputStream* stream) { | 119 PCMQueueOutAudioOutputStream* stream) { | 
| 120 DCHECK(stream); | |
| 121 num_output_streams_--; | |
| 77 delete stream; | 122 delete stream; | 
| 78 } | 123 } | 
| 79 | 124 | 
| 80 // Called by the stream when it has been released by calling Close(). | 125 // Called by the stream when it has been released by calling Close(). | 
| 81 void AudioManagerMac::ReleaseInputStream(PCMQueueInAudioInputStream* stream) { | 126 void AudioManagerMac::ReleaseInputStream(PCMQueueInAudioInputStream* stream) { | 
| 82 delete stream; | 127 delete stream; | 
| 83 } | 128 } | 
| 84 | 129 | 
| 85 // static | 130 // static | 
| 86 AudioManager* AudioManager::CreateAudioManager() { | 131 AudioManager* AudioManager::CreateAudioManager() { | 
| 87 return new AudioManagerMac(); | 132 return new AudioManagerMac(); | 
| 88 } | 133 } | 
| OLD | NEW |