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