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