OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include "webrtc/modules/audio_device/mac/audio_mixer_manager_mac.h" | 11 #include "webrtc/modules/audio_device/mac/audio_mixer_manager_mac.h" |
12 #include "webrtc/system_wrappers/include/trace.h" | 12 #include "webrtc/system_wrappers/include/trace.h" |
13 | 13 |
14 #include <unistd.h> // getpid() | 14 #include <unistd.h> // getpid() |
15 | 15 |
16 namespace webrtc { | 16 namespace webrtc { |
17 » | 17 |
18 #define WEBRTC_CA_RETURN_ON_ERR(expr) \ | 18 #define WEBRTC_CA_RETURN_ON_ERR(expr) \ |
19 do { \ | 19 do { \ |
20 err = expr; \ | 20 err = expr; \ |
21 if (err != noErr) { \ | 21 if (err != noErr) { \ |
22 logCAMsg(kTraceError, kTraceAudioDevice, _id, \ | 22 logCAMsg(kTraceError, kTraceAudioDevice, _id, "Error in " #expr, \ |
23 "Error in " #expr, (const char *)&err); \ | 23 (const char*) & err); \ |
24 return -1; \ | 24 return -1; \ |
25 } \ | 25 } \ |
26 } while(0) | 26 } while (0) |
27 | 27 |
28 #define WEBRTC_CA_LOG_ERR(expr) \ | 28 #define WEBRTC_CA_LOG_ERR(expr) \ |
29 do { \ | 29 do { \ |
30 err = expr; \ | 30 err = expr; \ |
31 if (err != noErr) { \ | 31 if (err != noErr) { \ |
32 logCAMsg(kTraceError, kTraceAudioDevice, _id, \ | 32 logCAMsg(kTraceError, kTraceAudioDevice, _id, "Error in " #expr, \ |
33 "Error in " #expr, (const char *)&err); \ | 33 (const char*) & err); \ |
34 } \ | 34 } \ |
35 } while(0) | 35 } while (0) |
36 | 36 |
37 #define WEBRTC_CA_LOG_WARN(expr) \ | 37 #define WEBRTC_CA_LOG_WARN(expr) \ |
38 do { \ | 38 do { \ |
39 err = expr; \ | 39 err = expr; \ |
40 if (err != noErr) { \ | 40 if (err != noErr) { \ |
41 logCAMsg(kTraceWarning, kTraceAudioDevice, _id, \ | 41 logCAMsg(kTraceWarning, kTraceAudioDevice, _id, "Error in " #expr, \ |
42 "Error in " #expr, (const char *)&err); \ | 42 (const char*) & err); \ |
43 } \ | 43 } \ |
44 } while(0) | 44 } while (0) |
45 | 45 |
46 AudioMixerManagerMac::AudioMixerManagerMac(const int32_t id) : | 46 AudioMixerManagerMac::AudioMixerManagerMac(const int32_t id) |
47 _critSect(*CriticalSectionWrapper::CreateCriticalSection()), | 47 : _critSect(*CriticalSectionWrapper::CreateCriticalSection()), |
48 _id(id), | 48 _id(id), |
49 _inputDeviceID(kAudioObjectUnknown), | 49 _inputDeviceID(kAudioObjectUnknown), |
50 _outputDeviceID(kAudioObjectUnknown), | 50 _outputDeviceID(kAudioObjectUnknown), |
51 _noInputChannels(0), | 51 _noInputChannels(0), |
52 _noOutputChannels(0) | 52 _noOutputChannels(0) { |
53 { | 53 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s constructed", |
54 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, | 54 __FUNCTION__); |
55 "%s constructed", __FUNCTION__); | 55 } |
56 } | 56 |
57 | 57 AudioMixerManagerMac::~AudioMixerManagerMac() { |
58 AudioMixerManagerMac::~AudioMixerManagerMac() | 58 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s destructed", |
59 { | 59 __FUNCTION__); |
60 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, | 60 |
61 "%s destructed", __FUNCTION__); | 61 Close(); |
62 | 62 |
63 Close(); | 63 delete &_critSect; |
64 | |
65 delete &_critSect; | |
66 } | 64 } |
67 | 65 |
68 // ============================================================================ | 66 // ============================================================================ |
69 // PUBLIC METHODS | 67 // PUBLIC METHODS |
70 // ============================================================================ | 68 // ============================================================================ |
71 | 69 |
72 int32_t AudioMixerManagerMac::Close() | 70 int32_t AudioMixerManagerMac::Close() { |
73 { | 71 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", __FUNCTION__); |
74 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", | 72 |
75 __FUNCTION__); | 73 CriticalSectionScoped lock(&_critSect); |
76 | 74 |
77 CriticalSectionScoped lock(&_critSect); | 75 CloseSpeaker(); |
78 | 76 CloseMicrophone(); |
79 CloseSpeaker(); | 77 |
80 CloseMicrophone(); | 78 return 0; |
| 79 } |
| 80 |
| 81 int32_t AudioMixerManagerMac::CloseSpeaker() { |
| 82 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", __FUNCTION__); |
| 83 |
| 84 CriticalSectionScoped lock(&_critSect); |
| 85 |
| 86 _outputDeviceID = kAudioObjectUnknown; |
| 87 _noOutputChannels = 0; |
| 88 |
| 89 return 0; |
| 90 } |
| 91 |
| 92 int32_t AudioMixerManagerMac::CloseMicrophone() { |
| 93 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", __FUNCTION__); |
| 94 |
| 95 CriticalSectionScoped lock(&_critSect); |
| 96 |
| 97 _inputDeviceID = kAudioObjectUnknown; |
| 98 _noInputChannels = 0; |
| 99 |
| 100 return 0; |
| 101 } |
| 102 |
| 103 int32_t AudioMixerManagerMac::OpenSpeaker(AudioDeviceID deviceID) { |
| 104 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, |
| 105 "AudioMixerManagerMac::OpenSpeaker(id=%d)", deviceID); |
| 106 |
| 107 CriticalSectionScoped lock(&_critSect); |
| 108 |
| 109 OSStatus err = noErr; |
| 110 UInt32 size = 0; |
| 111 pid_t hogPid = -1; |
| 112 |
| 113 _outputDeviceID = deviceID; |
| 114 |
| 115 // Check which process, if any, has hogged the device. |
| 116 AudioObjectPropertyAddress propertyAddress = { |
| 117 kAudioDevicePropertyHogMode, kAudioDevicePropertyScopeOutput, 0}; |
| 118 |
| 119 size = sizeof(hogPid); |
| 120 WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( |
| 121 _outputDeviceID, &propertyAddress, 0, NULL, &size, &hogPid)); |
| 122 |
| 123 if (hogPid == -1) { |
| 124 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, |
| 125 " No process has hogged the input device"); |
| 126 } |
| 127 // getpid() is apparently "always successful" |
| 128 else if (hogPid == getpid()) { |
| 129 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, |
| 130 " Our process has hogged the input device"); |
| 131 } else { |
| 132 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
| 133 " Another process (pid = %d) has hogged the input device", |
| 134 static_cast<int>(hogPid)); |
| 135 |
| 136 return -1; |
| 137 } |
| 138 |
| 139 // get number of channels from stream format |
| 140 propertyAddress.mSelector = kAudioDevicePropertyStreamFormat; |
| 141 |
| 142 // Get the stream format, to be able to read the number of channels. |
| 143 AudioStreamBasicDescription streamFormat; |
| 144 size = sizeof(AudioStreamBasicDescription); |
| 145 memset(&streamFormat, 0, size); |
| 146 WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( |
| 147 _outputDeviceID, &propertyAddress, 0, NULL, &size, &streamFormat)); |
| 148 |
| 149 _noOutputChannels = streamFormat.mChannelsPerFrame; |
| 150 |
| 151 return 0; |
| 152 } |
| 153 |
| 154 int32_t AudioMixerManagerMac::OpenMicrophone(AudioDeviceID deviceID) { |
| 155 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, |
| 156 "AudioMixerManagerMac::OpenMicrophone(id=%d)", deviceID); |
| 157 |
| 158 CriticalSectionScoped lock(&_critSect); |
| 159 |
| 160 OSStatus err = noErr; |
| 161 UInt32 size = 0; |
| 162 pid_t hogPid = -1; |
| 163 |
| 164 _inputDeviceID = deviceID; |
| 165 |
| 166 // Check which process, if any, has hogged the device. |
| 167 AudioObjectPropertyAddress propertyAddress = { |
| 168 kAudioDevicePropertyHogMode, kAudioDevicePropertyScopeInput, 0}; |
| 169 size = sizeof(hogPid); |
| 170 WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( |
| 171 _inputDeviceID, &propertyAddress, 0, NULL, &size, &hogPid)); |
| 172 if (hogPid == -1) { |
| 173 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, |
| 174 " No process has hogged the input device"); |
| 175 } |
| 176 // getpid() is apparently "always successful" |
| 177 else if (hogPid == getpid()) { |
| 178 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, |
| 179 " Our process has hogged the input device"); |
| 180 } else { |
| 181 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
| 182 " Another process (pid = %d) has hogged the input device", |
| 183 static_cast<int>(hogPid)); |
| 184 |
| 185 return -1; |
| 186 } |
| 187 |
| 188 // get number of channels from stream format |
| 189 propertyAddress.mSelector = kAudioDevicePropertyStreamFormat; |
| 190 |
| 191 // Get the stream format, to be able to read the number of channels. |
| 192 AudioStreamBasicDescription streamFormat; |
| 193 size = sizeof(AudioStreamBasicDescription); |
| 194 memset(&streamFormat, 0, size); |
| 195 WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( |
| 196 _inputDeviceID, &propertyAddress, 0, NULL, &size, &streamFormat)); |
| 197 |
| 198 _noInputChannels = streamFormat.mChannelsPerFrame; |
| 199 |
| 200 return 0; |
| 201 } |
| 202 |
| 203 bool AudioMixerManagerMac::SpeakerIsInitialized() const { |
| 204 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", __FUNCTION__); |
| 205 |
| 206 return (_outputDeviceID != kAudioObjectUnknown); |
| 207 } |
| 208 |
| 209 bool AudioMixerManagerMac::MicrophoneIsInitialized() const { |
| 210 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", __FUNCTION__); |
| 211 |
| 212 return (_inputDeviceID != kAudioObjectUnknown); |
| 213 } |
| 214 |
| 215 int32_t AudioMixerManagerMac::SetSpeakerVolume(uint32_t volume) { |
| 216 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, |
| 217 "AudioMixerManagerMac::SetSpeakerVolume(volume=%u)", volume); |
| 218 |
| 219 CriticalSectionScoped lock(&_critSect); |
| 220 |
| 221 if (_outputDeviceID == kAudioObjectUnknown) { |
| 222 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
| 223 " device ID has not been set"); |
| 224 return -1; |
| 225 } |
| 226 |
| 227 OSStatus err = noErr; |
| 228 UInt32 size = 0; |
| 229 bool success = false; |
| 230 |
| 231 // volume range is 0.0 - 1.0, convert from 0 -255 |
| 232 const Float32 vol = (Float32)(volume / 255.0); |
| 233 |
| 234 assert(vol <= 1.0 && vol >= 0.0); |
| 235 |
| 236 // Does the capture device have a master volume control? |
| 237 // If so, use it exclusively. |
| 238 AudioObjectPropertyAddress propertyAddress = { |
| 239 kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeOutput, 0}; |
| 240 Boolean isSettable = false; |
| 241 err = AudioObjectIsPropertySettable(_outputDeviceID, &propertyAddress, |
| 242 &isSettable); |
| 243 if (err == noErr && isSettable) { |
| 244 size = sizeof(vol); |
| 245 WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData( |
| 246 _outputDeviceID, &propertyAddress, 0, NULL, size, &vol)); |
81 | 247 |
82 return 0; | 248 return 0; |
83 | 249 } |
84 } | 250 |
85 | 251 // Otherwise try to set each channel. |
86 int32_t AudioMixerManagerMac::CloseSpeaker() | 252 for (UInt32 i = 1; i <= _noOutputChannels; i++) { |
87 { | 253 propertyAddress.mElement = i; |
88 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", | 254 isSettable = false; |
89 __FUNCTION__); | |
90 | |
91 CriticalSectionScoped lock(&_critSect); | |
92 | |
93 _outputDeviceID = kAudioObjectUnknown; | |
94 _noOutputChannels = 0; | |
95 | |
96 return 0; | |
97 } | |
98 | |
99 int32_t AudioMixerManagerMac::CloseMicrophone() | |
100 { | |
101 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", | |
102 __FUNCTION__); | |
103 | |
104 CriticalSectionScoped lock(&_critSect); | |
105 | |
106 _inputDeviceID = kAudioObjectUnknown; | |
107 _noInputChannels = 0; | |
108 | |
109 return 0; | |
110 } | |
111 | |
112 int32_t AudioMixerManagerMac::OpenSpeaker(AudioDeviceID deviceID) | |
113 { | |
114 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | |
115 "AudioMixerManagerMac::OpenSpeaker(id=%d)", deviceID); | |
116 | |
117 CriticalSectionScoped lock(&_critSect); | |
118 | |
119 OSStatus err = noErr; | |
120 UInt32 size = 0; | |
121 pid_t hogPid = -1; | |
122 | |
123 _outputDeviceID = deviceID; | |
124 | |
125 // Check which process, if any, has hogged the device. | |
126 AudioObjectPropertyAddress propertyAddress = { kAudioDevicePropertyHogMode, | |
127 kAudioDevicePropertyScopeOutput, 0 }; | |
128 | |
129 size = sizeof(hogPid); | |
130 WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_outputDeviceID, | |
131 &propertyAddress, 0, NULL, &size, &hogPid)); | |
132 | |
133 if (hogPid == -1) | |
134 { | |
135 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | |
136 " No process has hogged the input device"); | |
137 } | |
138 // getpid() is apparently "always successful" | |
139 else if (hogPid == getpid()) | |
140 { | |
141 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | |
142 " Our process has hogged the input device"); | |
143 } else | |
144 { | |
145 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | |
146 " Another process (pid = %d) has hogged the input device", | |
147 static_cast<int> (hogPid)); | |
148 | |
149 return -1; | |
150 } | |
151 | |
152 // get number of channels from stream format | |
153 propertyAddress.mSelector = kAudioDevicePropertyStreamFormat; | |
154 | |
155 // Get the stream format, to be able to read the number of channels. | |
156 AudioStreamBasicDescription streamFormat; | |
157 size = sizeof(AudioStreamBasicDescription); | |
158 memset(&streamFormat, 0, size); | |
159 WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_outputDeviceID, | |
160 &propertyAddress, 0, NULL, &size, &streamFormat)); | |
161 | |
162 _noOutputChannels = streamFormat.mChannelsPerFrame; | |
163 | |
164 return 0; | |
165 } | |
166 | |
167 int32_t AudioMixerManagerMac::OpenMicrophone(AudioDeviceID deviceID) | |
168 { | |
169 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | |
170 "AudioMixerManagerMac::OpenMicrophone(id=%d)", deviceID); | |
171 | |
172 CriticalSectionScoped lock(&_critSect); | |
173 | |
174 OSStatus err = noErr; | |
175 UInt32 size = 0; | |
176 pid_t hogPid = -1; | |
177 | |
178 _inputDeviceID = deviceID; | |
179 | |
180 // Check which process, if any, has hogged the device. | |
181 AudioObjectPropertyAddress propertyAddress = { kAudioDevicePropertyHogMode, | |
182 kAudioDevicePropertyScopeInput, 0 }; | |
183 size = sizeof(hogPid); | |
184 WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_inputDeviceID, | |
185 &propertyAddress, 0, NULL, &size, &hogPid)); | |
186 if (hogPid == -1) | |
187 { | |
188 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | |
189 " No process has hogged the input device"); | |
190 } | |
191 // getpid() is apparently "always successful" | |
192 else if (hogPid == getpid()) | |
193 { | |
194 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | |
195 " Our process has hogged the input device"); | |
196 } else | |
197 { | |
198 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | |
199 " Another process (pid = %d) has hogged the input device", | |
200 static_cast<int> (hogPid)); | |
201 | |
202 return -1; | |
203 } | |
204 | |
205 // get number of channels from stream format | |
206 propertyAddress.mSelector = kAudioDevicePropertyStreamFormat; | |
207 | |
208 // Get the stream format, to be able to read the number of channels. | |
209 AudioStreamBasicDescription streamFormat; | |
210 size = sizeof(AudioStreamBasicDescription); | |
211 memset(&streamFormat, 0, size); | |
212 WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_inputDeviceID, | |
213 &propertyAddress, 0, NULL, &size, &streamFormat)); | |
214 | |
215 _noInputChannels = streamFormat.mChannelsPerFrame; | |
216 | |
217 return 0; | |
218 } | |
219 | |
220 bool AudioMixerManagerMac::SpeakerIsInitialized() const | |
221 { | |
222 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", | |
223 __FUNCTION__); | |
224 | |
225 return (_outputDeviceID != kAudioObjectUnknown); | |
226 } | |
227 | |
228 bool AudioMixerManagerMac::MicrophoneIsInitialized() const | |
229 { | |
230 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", | |
231 __FUNCTION__); | |
232 | |
233 return (_inputDeviceID != kAudioObjectUnknown); | |
234 } | |
235 | |
236 int32_t AudioMixerManagerMac::SetSpeakerVolume(uint32_t volume) | |
237 { | |
238 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | |
239 "AudioMixerManagerMac::SetSpeakerVolume(volume=%u)", volume); | |
240 | |
241 CriticalSectionScoped lock(&_critSect); | |
242 | |
243 if (_outputDeviceID == kAudioObjectUnknown) | |
244 { | |
245 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | |
246 " device ID has not been set"); | |
247 return -1; | |
248 } | |
249 | |
250 OSStatus err = noErr; | |
251 UInt32 size = 0; | |
252 bool success = false; | |
253 | |
254 // volume range is 0.0 - 1.0, convert from 0 -255 | |
255 const Float32 vol = (Float32)(volume / 255.0); | |
256 | |
257 assert(vol <= 1.0 && vol >= 0.0); | |
258 | |
259 // Does the capture device have a master volume control? | |
260 // If so, use it exclusively. | |
261 AudioObjectPropertyAddress propertyAddress = { | |
262 kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeOutput, | |
263 0 }; | |
264 Boolean isSettable = false; | |
265 err = AudioObjectIsPropertySettable(_outputDeviceID, &propertyAddress, | 255 err = AudioObjectIsPropertySettable(_outputDeviceID, &propertyAddress, |
266 &isSettable); | 256 &isSettable); |
267 if (err == noErr && isSettable) | 257 if (err == noErr && isSettable) { |
268 { | 258 size = sizeof(vol); |
269 size = sizeof(vol); | 259 WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData( |
270 WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData(_outputDeviceID, | 260 _outputDeviceID, &propertyAddress, 0, NULL, size, &vol)); |
271 &propertyAddress, 0, NULL, size, &vol)); | 261 } |
272 | 262 success = true; |
273 return 0; | 263 } |
274 } | 264 |
275 | 265 if (!success) { |
276 // Otherwise try to set each channel. | 266 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
277 for (UInt32 i = 1; i <= _noOutputChannels; i++) | 267 " Unable to set a volume on any output channel"); |
278 { | 268 return -1; |
279 propertyAddress.mElement = i; | 269 } |
280 isSettable = false; | 270 |
281 err = AudioObjectIsPropertySettable(_outputDeviceID, &propertyAddress, | 271 return 0; |
282 &isSettable); | 272 } |
283 if (err == noErr && isSettable) | 273 |
284 { | 274 int32_t AudioMixerManagerMac::SpeakerVolume(uint32_t& volume) const { |
285 size = sizeof(vol); | 275 if (_outputDeviceID == kAudioObjectUnknown) { |
286 WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData(_outputDeviceID, | 276 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
287 &propertyAddress, 0, NULL, size, &vol)); | 277 " device ID has not been set"); |
288 } | 278 return -1; |
289 success = true; | 279 } |
290 } | 280 |
291 | 281 OSStatus err = noErr; |
292 if (!success) | 282 UInt32 size = 0; |
293 { | 283 unsigned int channels = 0; |
294 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 284 Float32 channelVol = 0; |
295 " Unable to set a volume on any output channel"); | 285 Float32 vol = 0; |
296 return -1; | 286 |
297 } | 287 // Does the device have a master volume control? |
298 | 288 // If so, use it exclusively. |
| 289 AudioObjectPropertyAddress propertyAddress = { |
| 290 kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeOutput, 0}; |
| 291 Boolean hasProperty = |
| 292 AudioObjectHasProperty(_outputDeviceID, &propertyAddress); |
| 293 if (hasProperty) { |
| 294 size = sizeof(vol); |
| 295 WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( |
| 296 _outputDeviceID, &propertyAddress, 0, NULL, &size, &vol)); |
| 297 |
| 298 // vol 0.0 to 1.0 -> convert to 0 - 255 |
| 299 volume = static_cast<uint32_t>(vol * 255 + 0.5); |
| 300 } else { |
| 301 // Otherwise get the average volume across channels. |
| 302 vol = 0; |
| 303 for (UInt32 i = 1; i <= _noOutputChannels; i++) { |
| 304 channelVol = 0; |
| 305 propertyAddress.mElement = i; |
| 306 hasProperty = AudioObjectHasProperty(_outputDeviceID, &propertyAddress); |
| 307 if (hasProperty) { |
| 308 size = sizeof(channelVol); |
| 309 WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( |
| 310 _outputDeviceID, &propertyAddress, 0, NULL, &size, &channelVol)); |
| 311 |
| 312 vol += channelVol; |
| 313 channels++; |
| 314 } |
| 315 } |
| 316 |
| 317 if (channels == 0) { |
| 318 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
| 319 " Unable to get a volume on any channel"); |
| 320 return -1; |
| 321 } |
| 322 |
| 323 assert(channels > 0); |
| 324 // vol 0.0 to 1.0 -> convert to 0 - 255 |
| 325 volume = static_cast<uint32_t>(255 * vol / channels + 0.5); |
| 326 } |
| 327 |
| 328 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, |
| 329 " AudioMixerManagerMac::SpeakerVolume() => vol=%i", vol); |
| 330 |
| 331 return 0; |
| 332 } |
| 333 |
| 334 int32_t AudioMixerManagerMac::MaxSpeakerVolume(uint32_t& maxVolume) const { |
| 335 if (_outputDeviceID == kAudioObjectUnknown) { |
| 336 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
| 337 " device ID has not been set"); |
| 338 return -1; |
| 339 } |
| 340 |
| 341 // volume range is 0.0 to 1.0 |
| 342 // we convert that to 0 - 255 |
| 343 maxVolume = 255; |
| 344 |
| 345 return 0; |
| 346 } |
| 347 |
| 348 int32_t AudioMixerManagerMac::MinSpeakerVolume(uint32_t& minVolume) const { |
| 349 if (_outputDeviceID == kAudioObjectUnknown) { |
| 350 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
| 351 " device ID has not been set"); |
| 352 return -1; |
| 353 } |
| 354 |
| 355 // volume range is 0.0 to 1.0 |
| 356 // we convert that to 0 - 255 |
| 357 minVolume = 0; |
| 358 |
| 359 return 0; |
| 360 } |
| 361 |
| 362 int32_t AudioMixerManagerMac::SpeakerVolumeStepSize(uint16_t& stepSize) const { |
| 363 if (_outputDeviceID == kAudioObjectUnknown) { |
| 364 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
| 365 " device ID has not been set"); |
| 366 return -1; |
| 367 } |
| 368 |
| 369 // volume range is 0.0 to 1.0 |
| 370 // we convert that to 0 - 255 |
| 371 stepSize = 1; |
| 372 |
| 373 return 0; |
| 374 } |
| 375 |
| 376 int32_t AudioMixerManagerMac::SpeakerVolumeIsAvailable(bool& available) { |
| 377 if (_outputDeviceID == kAudioObjectUnknown) { |
| 378 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
| 379 " device ID has not been set"); |
| 380 return -1; |
| 381 } |
| 382 |
| 383 OSStatus err = noErr; |
| 384 |
| 385 // Does the capture device have a master volume control? |
| 386 // If so, use it exclusively. |
| 387 AudioObjectPropertyAddress propertyAddress = { |
| 388 kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeOutput, 0}; |
| 389 Boolean isSettable = false; |
| 390 err = AudioObjectIsPropertySettable(_outputDeviceID, &propertyAddress, |
| 391 &isSettable); |
| 392 if (err == noErr && isSettable) { |
| 393 available = true; |
299 return 0; | 394 return 0; |
300 } | 395 } |
301 | 396 |
302 int32_t AudioMixerManagerMac::SpeakerVolume(uint32_t& volume) const | 397 // Otherwise try to set each channel. |
303 { | 398 for (UInt32 i = 1; i <= _noOutputChannels; i++) { |
304 | 399 propertyAddress.mElement = i; |
305 if (_outputDeviceID == kAudioObjectUnknown) | 400 isSettable = false; |
306 { | |
307 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | |
308 " device ID has not been set"); | |
309 return -1; | |
310 } | |
311 | |
312 OSStatus err = noErr; | |
313 UInt32 size = 0; | |
314 unsigned int channels = 0; | |
315 Float32 channelVol = 0; | |
316 Float32 vol = 0; | |
317 | |
318 // Does the device have a master volume control? | |
319 // If so, use it exclusively. | |
320 AudioObjectPropertyAddress propertyAddress = { | |
321 kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeOutput, | |
322 0 }; | |
323 Boolean hasProperty = AudioObjectHasProperty(_outputDeviceID, | |
324 &propertyAddress); | |
325 if (hasProperty) | |
326 { | |
327 size = sizeof(vol); | |
328 WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_outputDeviceID, | |
329 &propertyAddress, 0, NULL, &size, &vol)); | |
330 | |
331 // vol 0.0 to 1.0 -> convert to 0 - 255 | |
332 volume = static_cast<uint32_t> (vol * 255 + 0.5); | |
333 } else | |
334 { | |
335 // Otherwise get the average volume across channels. | |
336 vol = 0; | |
337 for (UInt32 i = 1; i <= _noOutputChannels; i++) | |
338 { | |
339 channelVol = 0; | |
340 propertyAddress.mElement = i; | |
341 hasProperty = AudioObjectHasProperty(_outputDeviceID, | |
342 &propertyAddress); | |
343 if (hasProperty) | |
344 { | |
345 size = sizeof(channelVol); | |
346 WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_outputDevice
ID, | |
347 &propertyAddress, 0, NULL, &size, &channelVol)); | |
348 | |
349 vol += channelVol; | |
350 channels++; | |
351 } | |
352 } | |
353 | |
354 if (channels == 0) | |
355 { | |
356 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | |
357 " Unable to get a volume on any channel"); | |
358 return -1; | |
359 } | |
360 | |
361 assert(channels > 0); | |
362 // vol 0.0 to 1.0 -> convert to 0 - 255 | |
363 volume = static_cast<uint32_t> (255 * vol / channels + 0.5); | |
364 } | |
365 | |
366 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | |
367 " AudioMixerManagerMac::SpeakerVolume() => vol=%i", vol); | |
368 | |
369 return 0; | |
370 } | |
371 | |
372 int32_t | |
373 AudioMixerManagerMac::MaxSpeakerVolume(uint32_t& maxVolume) const | |
374 { | |
375 | |
376 if (_outputDeviceID == kAudioObjectUnknown) | |
377 { | |
378 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | |
379 " device ID has not been set"); | |
380 return -1; | |
381 } | |
382 | |
383 // volume range is 0.0 to 1.0 | |
384 // we convert that to 0 - 255 | |
385 maxVolume = 255; | |
386 | |
387 return 0; | |
388 } | |
389 | |
390 int32_t | |
391 AudioMixerManagerMac::MinSpeakerVolume(uint32_t& minVolume) const | |
392 { | |
393 | |
394 if (_outputDeviceID == kAudioObjectUnknown) | |
395 { | |
396 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | |
397 " device ID has not been set"); | |
398 return -1; | |
399 } | |
400 | |
401 // volume range is 0.0 to 1.0 | |
402 // we convert that to 0 - 255 | |
403 minVolume = 0; | |
404 | |
405 return 0; | |
406 } | |
407 | |
408 int32_t | |
409 AudioMixerManagerMac::SpeakerVolumeStepSize(uint16_t& stepSize) const | |
410 { | |
411 | |
412 if (_outputDeviceID == kAudioObjectUnknown) | |
413 { | |
414 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | |
415 " device ID has not been set"); | |
416 return -1; | |
417 } | |
418 | |
419 // volume range is 0.0 to 1.0 | |
420 // we convert that to 0 - 255 | |
421 stepSize = 1; | |
422 | |
423 return 0; | |
424 } | |
425 | |
426 int32_t AudioMixerManagerMac::SpeakerVolumeIsAvailable(bool& available) | |
427 { | |
428 if (_outputDeviceID == kAudioObjectUnknown) | |
429 { | |
430 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | |
431 " device ID has not been set"); | |
432 return -1; | |
433 } | |
434 | |
435 OSStatus err = noErr; | |
436 | |
437 // Does the capture device have a master volume control? | |
438 // If so, use it exclusively. | |
439 AudioObjectPropertyAddress propertyAddress = { | |
440 kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeOutput, | |
441 0 }; | |
442 Boolean isSettable = false; | |
443 err = AudioObjectIsPropertySettable(_outputDeviceID, &propertyAddress, | 401 err = AudioObjectIsPropertySettable(_outputDeviceID, &propertyAddress, |
444 &isSettable); | 402 &isSettable); |
445 if (err == noErr && isSettable) | 403 if (err != noErr || !isSettable) { |
446 { | 404 available = false; |
447 available = true; | 405 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
448 return 0; | 406 " Volume cannot be set for output channel %d, err=%d", i, |
449 } | 407 err); |
450 | 408 return -1; |
451 // Otherwise try to set each channel. | 409 } |
452 for (UInt32 i = 1; i <= _noOutputChannels; i++) | 410 } |
453 { | 411 |
454 propertyAddress.mElement = i; | 412 available = true; |
455 isSettable = false; | 413 return 0; |
456 err = AudioObjectIsPropertySettable(_outputDeviceID, &propertyAddress, | 414 } |
457 &isSettable); | 415 |
458 if (err != noErr || !isSettable) | 416 int32_t AudioMixerManagerMac::SpeakerMuteIsAvailable(bool& available) { |
459 { | 417 if (_outputDeviceID == kAudioObjectUnknown) { |
460 available = false; | 418 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
461 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 419 " device ID has not been set"); |
462 " Volume cannot be set for output channel %d, err=%d", | 420 return -1; |
463 i, err); | 421 } |
464 return -1; | 422 |
465 } | 423 OSStatus err = noErr; |
466 } | 424 |
467 | 425 // Does the capture device have a master mute control? |
| 426 // If so, use it exclusively. |
| 427 AudioObjectPropertyAddress propertyAddress = { |
| 428 kAudioDevicePropertyMute, kAudioDevicePropertyScopeOutput, 0}; |
| 429 Boolean isSettable = false; |
| 430 err = AudioObjectIsPropertySettable(_outputDeviceID, &propertyAddress, |
| 431 &isSettable); |
| 432 if (err == noErr && isSettable) { |
468 available = true; | 433 available = true; |
469 return 0; | 434 return 0; |
470 } | 435 } |
471 | 436 |
472 int32_t AudioMixerManagerMac::SpeakerMuteIsAvailable(bool& available) | 437 // Otherwise try to set each channel. |
473 { | 438 for (UInt32 i = 1; i <= _noOutputChannels; i++) { |
474 if (_outputDeviceID == kAudioObjectUnknown) | 439 propertyAddress.mElement = i; |
475 { | 440 isSettable = false; |
476 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | |
477 " device ID has not been set"); | |
478 return -1; | |
479 } | |
480 | |
481 OSStatus err = noErr; | |
482 | |
483 // Does the capture device have a master mute control? | |
484 // If so, use it exclusively. | |
485 AudioObjectPropertyAddress propertyAddress = { kAudioDevicePropertyMute, | |
486 kAudioDevicePropertyScopeOutput, 0 }; | |
487 Boolean isSettable = false; | |
488 err = AudioObjectIsPropertySettable(_outputDeviceID, &propertyAddress, | 441 err = AudioObjectIsPropertySettable(_outputDeviceID, &propertyAddress, |
489 &isSettable); | 442 &isSettable); |
490 if (err == noErr && isSettable) | 443 if (err != noErr || !isSettable) { |
491 { | 444 available = false; |
492 available = true; | 445 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
493 return 0; | 446 " Mute cannot be set for output channel %d, err=%d", i, err); |
494 } | 447 return -1; |
495 | 448 } |
496 // Otherwise try to set each channel. | 449 } |
497 for (UInt32 i = 1; i <= _noOutputChannels; i++) | 450 |
498 { | 451 available = true; |
499 propertyAddress.mElement = i; | 452 return 0; |
500 isSettable = false; | 453 } |
501 err = AudioObjectIsPropertySettable(_outputDeviceID, &propertyAddress, | 454 |
502 &isSettable); | 455 int32_t AudioMixerManagerMac::SetSpeakerMute(bool enable) { |
503 if (err != noErr || !isSettable) | 456 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, |
504 { | 457 "AudioMixerManagerMac::SetSpeakerMute(enable=%u)", enable); |
505 available = false; | 458 |
506 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 459 CriticalSectionScoped lock(&_critSect); |
507 " Mute cannot be set for output channel %d, err=%d", | 460 |
508 i, err); | 461 if (_outputDeviceID == kAudioObjectUnknown) { |
509 return -1; | 462 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
510 } | 463 " device ID has not been set"); |
511 } | 464 return -1; |
512 | 465 } |
| 466 |
| 467 OSStatus err = noErr; |
| 468 UInt32 size = 0; |
| 469 UInt32 mute = enable ? 1 : 0; |
| 470 bool success = false; |
| 471 |
| 472 // Does the render device have a master mute control? |
| 473 // If so, use it exclusively. |
| 474 AudioObjectPropertyAddress propertyAddress = { |
| 475 kAudioDevicePropertyMute, kAudioDevicePropertyScopeOutput, 0}; |
| 476 Boolean isSettable = false; |
| 477 err = AudioObjectIsPropertySettable(_outputDeviceID, &propertyAddress, |
| 478 &isSettable); |
| 479 if (err == noErr && isSettable) { |
| 480 size = sizeof(mute); |
| 481 WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData( |
| 482 _outputDeviceID, &propertyAddress, 0, NULL, size, &mute)); |
| 483 |
| 484 return 0; |
| 485 } |
| 486 |
| 487 // Otherwise try to set each channel. |
| 488 for (UInt32 i = 1; i <= _noOutputChannels; i++) { |
| 489 propertyAddress.mElement = i; |
| 490 isSettable = false; |
| 491 err = AudioObjectIsPropertySettable(_outputDeviceID, &propertyAddress, |
| 492 &isSettable); |
| 493 if (err == noErr && isSettable) { |
| 494 size = sizeof(mute); |
| 495 WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData( |
| 496 _outputDeviceID, &propertyAddress, 0, NULL, size, &mute)); |
| 497 } |
| 498 success = true; |
| 499 } |
| 500 |
| 501 if (!success) { |
| 502 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
| 503 " Unable to set mute on any input channel"); |
| 504 return -1; |
| 505 } |
| 506 |
| 507 return 0; |
| 508 } |
| 509 |
| 510 int32_t AudioMixerManagerMac::SpeakerMute(bool& enabled) const { |
| 511 if (_outputDeviceID == kAudioObjectUnknown) { |
| 512 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
| 513 " device ID has not been set"); |
| 514 return -1; |
| 515 } |
| 516 |
| 517 OSStatus err = noErr; |
| 518 UInt32 size = 0; |
| 519 unsigned int channels = 0; |
| 520 UInt32 channelMuted = 0; |
| 521 UInt32 muted = 0; |
| 522 |
| 523 // Does the device have a master volume control? |
| 524 // If so, use it exclusively. |
| 525 AudioObjectPropertyAddress propertyAddress = { |
| 526 kAudioDevicePropertyMute, kAudioDevicePropertyScopeOutput, 0}; |
| 527 Boolean hasProperty = |
| 528 AudioObjectHasProperty(_outputDeviceID, &propertyAddress); |
| 529 if (hasProperty) { |
| 530 size = sizeof(muted); |
| 531 WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( |
| 532 _outputDeviceID, &propertyAddress, 0, NULL, &size, &muted)); |
| 533 |
| 534 // 1 means muted |
| 535 enabled = static_cast<bool>(muted); |
| 536 } else { |
| 537 // Otherwise check if all channels are muted. |
| 538 for (UInt32 i = 1; i <= _noOutputChannels; i++) { |
| 539 muted = 0; |
| 540 propertyAddress.mElement = i; |
| 541 hasProperty = AudioObjectHasProperty(_outputDeviceID, &propertyAddress); |
| 542 if (hasProperty) { |
| 543 size = sizeof(channelMuted); |
| 544 WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( |
| 545 _outputDeviceID, &propertyAddress, 0, NULL, &size, &channelMuted)); |
| 546 |
| 547 muted = (muted && channelMuted); |
| 548 channels++; |
| 549 } |
| 550 } |
| 551 |
| 552 if (channels == 0) { |
| 553 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
| 554 " Unable to get mute for any channel"); |
| 555 return -1; |
| 556 } |
| 557 |
| 558 assert(channels > 0); |
| 559 // 1 means muted |
| 560 enabled = static_cast<bool>(muted); |
| 561 } |
| 562 |
| 563 WEBRTC_TRACE( |
| 564 kTraceInfo, kTraceAudioDevice, _id, |
| 565 " AudioMixerManagerMac::SpeakerMute() => enabled=%d, enabled"); |
| 566 |
| 567 return 0; |
| 568 } |
| 569 |
| 570 int32_t AudioMixerManagerMac::StereoPlayoutIsAvailable(bool& available) { |
| 571 if (_outputDeviceID == kAudioObjectUnknown) { |
| 572 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
| 573 " device ID has not been set"); |
| 574 return -1; |
| 575 } |
| 576 |
| 577 available = (_noOutputChannels == 2); |
| 578 return 0; |
| 579 } |
| 580 |
| 581 int32_t AudioMixerManagerMac::StereoRecordingIsAvailable(bool& available) { |
| 582 if (_inputDeviceID == kAudioObjectUnknown) { |
| 583 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
| 584 " device ID has not been set"); |
| 585 return -1; |
| 586 } |
| 587 |
| 588 available = (_noInputChannels == 2); |
| 589 return 0; |
| 590 } |
| 591 |
| 592 int32_t AudioMixerManagerMac::MicrophoneMuteIsAvailable(bool& available) { |
| 593 if (_inputDeviceID == kAudioObjectUnknown) { |
| 594 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
| 595 " device ID has not been set"); |
| 596 return -1; |
| 597 } |
| 598 |
| 599 OSStatus err = noErr; |
| 600 |
| 601 // Does the capture device have a master mute control? |
| 602 // If so, use it exclusively. |
| 603 AudioObjectPropertyAddress propertyAddress = { |
| 604 kAudioDevicePropertyMute, kAudioDevicePropertyScopeInput, 0}; |
| 605 Boolean isSettable = false; |
| 606 err = AudioObjectIsPropertySettable(_inputDeviceID, &propertyAddress, |
| 607 &isSettable); |
| 608 if (err == noErr && isSettable) { |
513 available = true; | 609 available = true; |
514 return 0; | 610 return 0; |
515 } | 611 } |
516 | 612 |
517 int32_t AudioMixerManagerMac::SetSpeakerMute(bool enable) | 613 // Otherwise try to set each channel. |
518 { | 614 for (UInt32 i = 1; i <= _noInputChannels; i++) { |
519 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 615 propertyAddress.mElement = i; |
520 "AudioMixerManagerMac::SetSpeakerMute(enable=%u)", enable); | 616 isSettable = false; |
521 | |
522 CriticalSectionScoped lock(&_critSect); | |
523 | |
524 if (_outputDeviceID == kAudioObjectUnknown) | |
525 { | |
526 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | |
527 " device ID has not been set"); | |
528 return -1; | |
529 } | |
530 | |
531 OSStatus err = noErr; | |
532 UInt32 size = 0; | |
533 UInt32 mute = enable ? 1 : 0; | |
534 bool success = false; | |
535 | |
536 // Does the render device have a master mute control? | |
537 // If so, use it exclusively. | |
538 AudioObjectPropertyAddress propertyAddress = { kAudioDevicePropertyMute, | |
539 kAudioDevicePropertyScopeOutput, 0 }; | |
540 Boolean isSettable = false; | |
541 err = AudioObjectIsPropertySettable(_outputDeviceID, &propertyAddress, | |
542 &isSettable); | |
543 if (err == noErr && isSettable) | |
544 { | |
545 size = sizeof(mute); | |
546 WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData(_outputDeviceID, | |
547 &propertyAddress, 0, NULL, size, &mute)); | |
548 | |
549 return 0; | |
550 } | |
551 | |
552 // Otherwise try to set each channel. | |
553 for (UInt32 i = 1; i <= _noOutputChannels; i++) | |
554 { | |
555 propertyAddress.mElement = i; | |
556 isSettable = false; | |
557 err = AudioObjectIsPropertySettable(_outputDeviceID, &propertyAddress, | |
558 &isSettable); | |
559 if (err == noErr && isSettable) | |
560 { | |
561 size = sizeof(mute); | |
562 WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData(_outputDeviceID, | |
563 &propertyAddress, 0, NULL, size, &mute)); | |
564 } | |
565 success = true; | |
566 } | |
567 | |
568 if (!success) | |
569 { | |
570 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | |
571 " Unable to set mute on any input channel"); | |
572 return -1; | |
573 } | |
574 | |
575 return 0; | |
576 } | |
577 | |
578 int32_t AudioMixerManagerMac::SpeakerMute(bool& enabled) const | |
579 { | |
580 | |
581 if (_outputDeviceID == kAudioObjectUnknown) | |
582 { | |
583 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | |
584 " device ID has not been set"); | |
585 return -1; | |
586 } | |
587 | |
588 OSStatus err = noErr; | |
589 UInt32 size = 0; | |
590 unsigned int channels = 0; | |
591 UInt32 channelMuted = 0; | |
592 UInt32 muted = 0; | |
593 | |
594 // Does the device have a master volume control? | |
595 // If so, use it exclusively. | |
596 AudioObjectPropertyAddress propertyAddress = { kAudioDevicePropertyMute, | |
597 kAudioDevicePropertyScopeOutput, 0 }; | |
598 Boolean hasProperty = AudioObjectHasProperty(_outputDeviceID, | |
599 &propertyAddress); | |
600 if (hasProperty) | |
601 { | |
602 size = sizeof(muted); | |
603 WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_outputDeviceID, | |
604 &propertyAddress, 0, NULL, &size, &muted)); | |
605 | |
606 // 1 means muted | |
607 enabled = static_cast<bool> (muted); | |
608 } else | |
609 { | |
610 // Otherwise check if all channels are muted. | |
611 for (UInt32 i = 1; i <= _noOutputChannels; i++) | |
612 { | |
613 muted = 0; | |
614 propertyAddress.mElement = i; | |
615 hasProperty = AudioObjectHasProperty(_outputDeviceID, | |
616 &propertyAddress); | |
617 if (hasProperty) | |
618 { | |
619 size = sizeof(channelMuted); | |
620 WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_outputDevice
ID, | |
621 &propertyAddress, 0, NULL, &size, &channelMuted)); | |
622 | |
623 muted = (muted && channelMuted); | |
624 channels++; | |
625 } | |
626 } | |
627 | |
628 if (channels == 0) | |
629 { | |
630 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | |
631 " Unable to get mute for any channel"); | |
632 return -1; | |
633 } | |
634 | |
635 assert(channels > 0); | |
636 // 1 means muted | |
637 enabled = static_cast<bool> (muted); | |
638 } | |
639 | |
640 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | |
641 " AudioMixerManagerMac::SpeakerMute() => enabled=%d, enable
d"); | |
642 | |
643 return 0; | |
644 } | |
645 | |
646 int32_t AudioMixerManagerMac::StereoPlayoutIsAvailable(bool& available) | |
647 { | |
648 if (_outputDeviceID == kAudioObjectUnknown) | |
649 { | |
650 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | |
651 " device ID has not been set"); | |
652 return -1; | |
653 } | |
654 | |
655 available = (_noOutputChannels == 2); | |
656 return 0; | |
657 } | |
658 | |
659 int32_t AudioMixerManagerMac::StereoRecordingIsAvailable(bool& available) | |
660 { | |
661 if (_inputDeviceID == kAudioObjectUnknown) | |
662 { | |
663 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | |
664 " device ID has not been set"); | |
665 return -1; | |
666 } | |
667 | |
668 available = (_noInputChannels == 2); | |
669 return 0; | |
670 } | |
671 | |
672 int32_t AudioMixerManagerMac::MicrophoneMuteIsAvailable(bool& available) | |
673 { | |
674 if (_inputDeviceID == kAudioObjectUnknown) | |
675 { | |
676 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | |
677 " device ID has not been set"); | |
678 return -1; | |
679 } | |
680 | |
681 OSStatus err = noErr; | |
682 | |
683 // Does the capture device have a master mute control? | |
684 // If so, use it exclusively. | |
685 AudioObjectPropertyAddress propertyAddress = { kAudioDevicePropertyMute, | |
686 kAudioDevicePropertyScopeInput, 0 }; | |
687 Boolean isSettable = false; | |
688 err = AudioObjectIsPropertySettable(_inputDeviceID, &propertyAddress, | 617 err = AudioObjectIsPropertySettable(_inputDeviceID, &propertyAddress, |
689 &isSettable); | 618 &isSettable); |
690 if (err == noErr && isSettable) | 619 if (err != noErr || !isSettable) { |
691 { | 620 available = false; |
692 available = true; | 621 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
693 return 0; | 622 " Mute cannot be set for output channel %d, err=%d", i, err); |
694 } | 623 return -1; |
695 | 624 } |
696 // Otherwise try to set each channel. | 625 } |
697 for (UInt32 i = 1; i <= _noInputChannels; i++) | 626 |
698 { | 627 available = true; |
699 propertyAddress.mElement = i; | 628 return 0; |
700 isSettable = false; | 629 } |
701 err = AudioObjectIsPropertySettable(_inputDeviceID, &propertyAddress, | 630 |
702 &isSettable); | 631 int32_t AudioMixerManagerMac::SetMicrophoneMute(bool enable) { |
703 if (err != noErr || !isSettable) | 632 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, |
704 { | 633 "AudioMixerManagerMac::SetMicrophoneMute(enable=%u)", enable); |
705 available = false; | 634 |
706 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 635 CriticalSectionScoped lock(&_critSect); |
707 " Mute cannot be set for output channel %d, err=%d", | 636 |
708 i, err); | 637 if (_inputDeviceID == kAudioObjectUnknown) { |
709 return -1; | 638 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
710 } | 639 " device ID has not been set"); |
711 } | 640 return -1; |
712 | 641 } |
| 642 |
| 643 OSStatus err = noErr; |
| 644 UInt32 size = 0; |
| 645 UInt32 mute = enable ? 1 : 0; |
| 646 bool success = false; |
| 647 |
| 648 // Does the capture device have a master mute control? |
| 649 // If so, use it exclusively. |
| 650 AudioObjectPropertyAddress propertyAddress = { |
| 651 kAudioDevicePropertyMute, kAudioDevicePropertyScopeInput, 0}; |
| 652 Boolean isSettable = false; |
| 653 err = AudioObjectIsPropertySettable(_inputDeviceID, &propertyAddress, |
| 654 &isSettable); |
| 655 if (err == noErr && isSettable) { |
| 656 size = sizeof(mute); |
| 657 WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData( |
| 658 _inputDeviceID, &propertyAddress, 0, NULL, size, &mute)); |
| 659 |
| 660 return 0; |
| 661 } |
| 662 |
| 663 // Otherwise try to set each channel. |
| 664 for (UInt32 i = 1; i <= _noInputChannels; i++) { |
| 665 propertyAddress.mElement = i; |
| 666 isSettable = false; |
| 667 err = AudioObjectIsPropertySettable(_inputDeviceID, &propertyAddress, |
| 668 &isSettable); |
| 669 if (err == noErr && isSettable) { |
| 670 size = sizeof(mute); |
| 671 WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData( |
| 672 _inputDeviceID, &propertyAddress, 0, NULL, size, &mute)); |
| 673 } |
| 674 success = true; |
| 675 } |
| 676 |
| 677 if (!success) { |
| 678 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
| 679 " Unable to set mute on any input channel"); |
| 680 return -1; |
| 681 } |
| 682 |
| 683 return 0; |
| 684 } |
| 685 |
| 686 int32_t AudioMixerManagerMac::MicrophoneMute(bool& enabled) const { |
| 687 if (_inputDeviceID == kAudioObjectUnknown) { |
| 688 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
| 689 " device ID has not been set"); |
| 690 return -1; |
| 691 } |
| 692 |
| 693 OSStatus err = noErr; |
| 694 UInt32 size = 0; |
| 695 unsigned int channels = 0; |
| 696 UInt32 channelMuted = 0; |
| 697 UInt32 muted = 0; |
| 698 |
| 699 // Does the device have a master volume control? |
| 700 // If so, use it exclusively. |
| 701 AudioObjectPropertyAddress propertyAddress = { |
| 702 kAudioDevicePropertyMute, kAudioDevicePropertyScopeInput, 0}; |
| 703 Boolean hasProperty = |
| 704 AudioObjectHasProperty(_inputDeviceID, &propertyAddress); |
| 705 if (hasProperty) { |
| 706 size = sizeof(muted); |
| 707 WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( |
| 708 _inputDeviceID, &propertyAddress, 0, NULL, &size, &muted)); |
| 709 |
| 710 // 1 means muted |
| 711 enabled = static_cast<bool>(muted); |
| 712 } else { |
| 713 // Otherwise check if all channels are muted. |
| 714 for (UInt32 i = 1; i <= _noInputChannels; i++) { |
| 715 muted = 0; |
| 716 propertyAddress.mElement = i; |
| 717 hasProperty = AudioObjectHasProperty(_inputDeviceID, &propertyAddress); |
| 718 if (hasProperty) { |
| 719 size = sizeof(channelMuted); |
| 720 WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( |
| 721 _inputDeviceID, &propertyAddress, 0, NULL, &size, &channelMuted)); |
| 722 |
| 723 muted = (muted && channelMuted); |
| 724 channels++; |
| 725 } |
| 726 } |
| 727 |
| 728 if (channels == 0) { |
| 729 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
| 730 " Unable to get mute for any channel"); |
| 731 return -1; |
| 732 } |
| 733 |
| 734 assert(channels > 0); |
| 735 // 1 means muted |
| 736 enabled = static_cast<bool>(muted); |
| 737 } |
| 738 |
| 739 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, |
| 740 " AudioMixerManagerMac::MicrophoneMute() => enabled=%d", |
| 741 enabled); |
| 742 |
| 743 return 0; |
| 744 } |
| 745 |
| 746 int32_t AudioMixerManagerMac::MicrophoneBoostIsAvailable(bool& available) { |
| 747 if (_inputDeviceID == kAudioObjectUnknown) { |
| 748 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
| 749 " device ID has not been set"); |
| 750 return -1; |
| 751 } |
| 752 |
| 753 available = false; // No AudioObjectPropertySelector value for Mic Boost |
| 754 |
| 755 return 0; |
| 756 } |
| 757 |
| 758 int32_t AudioMixerManagerMac::SetMicrophoneBoost(bool enable) { |
| 759 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, |
| 760 "AudioMixerManagerMac::SetMicrophoneBoost(enable=%u)", enable); |
| 761 |
| 762 CriticalSectionScoped lock(&_critSect); |
| 763 |
| 764 if (_inputDeviceID == kAudioObjectUnknown) { |
| 765 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
| 766 " device ID has not been set"); |
| 767 return -1; |
| 768 } |
| 769 |
| 770 // Ensure that the selected microphone has a valid boost control. |
| 771 bool available(false); |
| 772 MicrophoneBoostIsAvailable(available); |
| 773 if (!available) { |
| 774 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
| 775 " it is not possible to enable microphone boost"); |
| 776 return -1; |
| 777 } |
| 778 |
| 779 // It is assumed that the call above fails! |
| 780 return 0; |
| 781 } |
| 782 |
| 783 int32_t AudioMixerManagerMac::MicrophoneBoost(bool& enabled) const { |
| 784 if (_inputDeviceID == kAudioObjectUnknown) { |
| 785 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
| 786 " device ID has not been set"); |
| 787 return -1; |
| 788 } |
| 789 |
| 790 // Microphone boost cannot be enabled on this platform! |
| 791 enabled = false; |
| 792 |
| 793 return 0; |
| 794 } |
| 795 |
| 796 int32_t AudioMixerManagerMac::MicrophoneVolumeIsAvailable(bool& available) { |
| 797 if (_inputDeviceID == kAudioObjectUnknown) { |
| 798 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
| 799 " device ID has not been set"); |
| 800 return -1; |
| 801 } |
| 802 |
| 803 OSStatus err = noErr; |
| 804 |
| 805 // Does the capture device have a master volume control? |
| 806 // If so, use it exclusively. |
| 807 AudioObjectPropertyAddress propertyAddress = { |
| 808 kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeInput, 0}; |
| 809 Boolean isSettable = false; |
| 810 err = AudioObjectIsPropertySettable(_inputDeviceID, &propertyAddress, |
| 811 &isSettable); |
| 812 if (err == noErr && isSettable) { |
713 available = true; | 813 available = true; |
714 return 0; | 814 return 0; |
715 } | 815 } |
716 | 816 |
717 int32_t AudioMixerManagerMac::SetMicrophoneMute(bool enable) | 817 // Otherwise try to set each channel. |
718 { | 818 for (UInt32 i = 1; i <= _noInputChannels; i++) { |
719 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 819 propertyAddress.mElement = i; |
720 "AudioMixerManagerMac::SetMicrophoneMute(enable=%u)", enable); | 820 isSettable = false; |
721 | |
722 CriticalSectionScoped lock(&_critSect); | |
723 | |
724 if (_inputDeviceID == kAudioObjectUnknown) | |
725 { | |
726 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | |
727 " device ID has not been set"); | |
728 return -1; | |
729 } | |
730 | |
731 OSStatus err = noErr; | |
732 UInt32 size = 0; | |
733 UInt32 mute = enable ? 1 : 0; | |
734 bool success = false; | |
735 | |
736 // Does the capture device have a master mute control? | |
737 // If so, use it exclusively. | |
738 AudioObjectPropertyAddress propertyAddress = { kAudioDevicePropertyMute, | |
739 kAudioDevicePropertyScopeInput, 0 }; | |
740 Boolean isSettable = false; | |
741 err = AudioObjectIsPropertySettable(_inputDeviceID, &propertyAddress, | 821 err = AudioObjectIsPropertySettable(_inputDeviceID, &propertyAddress, |
742 &isSettable); | 822 &isSettable); |
743 if (err == noErr && isSettable) | 823 if (err != noErr || !isSettable) { |
744 { | 824 available = false; |
745 size = sizeof(mute); | 825 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
746 WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData(_inputDeviceID, | 826 " Volume cannot be set for input channel %d, err=%d", i, |
747 &propertyAddress, 0, NULL, size, &mute)); | 827 err); |
748 | 828 return -1; |
749 return 0; | 829 } |
750 } | 830 } |
751 | 831 |
752 // Otherwise try to set each channel. | 832 available = true; |
753 for (UInt32 i = 1; i <= _noInputChannels; i++) | 833 return 0; |
754 { | 834 } |
755 propertyAddress.mElement = i; | 835 |
756 isSettable = false; | 836 int32_t AudioMixerManagerMac::SetMicrophoneVolume(uint32_t volume) { |
757 err = AudioObjectIsPropertySettable(_inputDeviceID, &propertyAddress, | 837 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, |
758 &isSettable); | 838 "AudioMixerManagerMac::SetMicrophoneVolume(volume=%u)", volume); |
759 if (err == noErr && isSettable) | 839 |
760 { | 840 CriticalSectionScoped lock(&_critSect); |
761 size = sizeof(mute); | 841 |
762 WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData(_inputDeviceID, | 842 if (_inputDeviceID == kAudioObjectUnknown) { |
763 &propertyAddress, 0, NULL, size, &mute)); | 843 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
764 } | 844 " device ID has not been set"); |
765 success = true; | 845 return -1; |
766 } | 846 } |
767 | 847 |
768 if (!success) | 848 OSStatus err = noErr; |
769 { | 849 UInt32 size = 0; |
770 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 850 bool success = false; |
771 " Unable to set mute on any input channel"); | 851 |
772 return -1; | 852 // volume range is 0.0 - 1.0, convert from 0 - 255 |
773 } | 853 const Float32 vol = (Float32)(volume / 255.0); |
| 854 |
| 855 assert(vol <= 1.0 && vol >= 0.0); |
| 856 |
| 857 // Does the capture device have a master volume control? |
| 858 // If so, use it exclusively. |
| 859 AudioObjectPropertyAddress propertyAddress = { |
| 860 kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeInput, 0}; |
| 861 Boolean isSettable = false; |
| 862 err = AudioObjectIsPropertySettable(_inputDeviceID, &propertyAddress, |
| 863 &isSettable); |
| 864 if (err == noErr && isSettable) { |
| 865 size = sizeof(vol); |
| 866 WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData( |
| 867 _inputDeviceID, &propertyAddress, 0, NULL, size, &vol)); |
774 | 868 |
775 return 0; | 869 return 0; |
776 } | 870 } |
777 | 871 |
778 int32_t AudioMixerManagerMac::MicrophoneMute(bool& enabled) const | 872 // Otherwise try to set each channel. |
779 { | 873 for (UInt32 i = 1; i <= _noInputChannels; i++) { |
780 | 874 propertyAddress.mElement = i; |
781 if (_inputDeviceID == kAudioObjectUnknown) | 875 isSettable = false; |
782 { | |
783 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | |
784 " device ID has not been set"); | |
785 return -1; | |
786 } | |
787 | |
788 OSStatus err = noErr; | |
789 UInt32 size = 0; | |
790 unsigned int channels = 0; | |
791 UInt32 channelMuted = 0; | |
792 UInt32 muted = 0; | |
793 | |
794 // Does the device have a master volume control? | |
795 // If so, use it exclusively. | |
796 AudioObjectPropertyAddress propertyAddress = { kAudioDevicePropertyMute, | |
797 kAudioDevicePropertyScopeInput, 0 }; | |
798 Boolean hasProperty = AudioObjectHasProperty(_inputDeviceID, | |
799 &propertyAddress); | |
800 if (hasProperty) | |
801 { | |
802 size = sizeof(muted); | |
803 WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_inputDeviceID, | |
804 &propertyAddress, 0, NULL, &size, &muted)); | |
805 | |
806 // 1 means muted | |
807 enabled = static_cast<bool> (muted); | |
808 } else | |
809 { | |
810 // Otherwise check if all channels are muted. | |
811 for (UInt32 i = 1; i <= _noInputChannels; i++) | |
812 { | |
813 muted = 0; | |
814 propertyAddress.mElement = i; | |
815 hasProperty = AudioObjectHasProperty(_inputDeviceID, | |
816 &propertyAddress); | |
817 if (hasProperty) | |
818 { | |
819 size = sizeof(channelMuted); | |
820 WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_inputDeviceI
D, | |
821 &propertyAddress, 0, NULL, &size, &channelMuted)); | |
822 | |
823 muted = (muted && channelMuted); | |
824 channels++; | |
825 } | |
826 } | |
827 | |
828 if (channels == 0) | |
829 { | |
830 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | |
831 " Unable to get mute for any channel"); | |
832 return -1; | |
833 } | |
834 | |
835 assert(channels > 0); | |
836 // 1 means muted | |
837 enabled = static_cast<bool> (muted); | |
838 } | |
839 | |
840 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | |
841 " AudioMixerManagerMac::MicrophoneMute() => enabled=%d", | |
842 enabled); | |
843 | |
844 return 0; | |
845 } | |
846 | |
847 int32_t AudioMixerManagerMac::MicrophoneBoostIsAvailable(bool& available) | |
848 { | |
849 if (_inputDeviceID == kAudioObjectUnknown) | |
850 { | |
851 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | |
852 " device ID has not been set"); | |
853 return -1; | |
854 } | |
855 | |
856 available = false; // No AudioObjectPropertySelector value for Mic Boost | |
857 | |
858 return 0; | |
859 } | |
860 | |
861 int32_t AudioMixerManagerMac::SetMicrophoneBoost(bool enable) | |
862 { | |
863 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | |
864 "AudioMixerManagerMac::SetMicrophoneBoost(enable=%u)", enable); | |
865 | |
866 CriticalSectionScoped lock(&_critSect); | |
867 | |
868 if (_inputDeviceID == kAudioObjectUnknown) | |
869 { | |
870 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | |
871 " device ID has not been set"); | |
872 return -1; | |
873 } | |
874 | |
875 // Ensure that the selected microphone has a valid boost control. | |
876 bool available(false); | |
877 MicrophoneBoostIsAvailable(available); | |
878 if (!available) | |
879 { | |
880 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | |
881 " it is not possible to enable microphone boost"); | |
882 return -1; | |
883 } | |
884 | |
885 // It is assumed that the call above fails! | |
886 return 0; | |
887 } | |
888 | |
889 int32_t AudioMixerManagerMac::MicrophoneBoost(bool& enabled) const | |
890 { | |
891 | |
892 if (_inputDeviceID == kAudioObjectUnknown) | |
893 { | |
894 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | |
895 " device ID has not been set"); | |
896 return -1; | |
897 } | |
898 | |
899 // Microphone boost cannot be enabled on this platform! | |
900 enabled = false; | |
901 | |
902 return 0; | |
903 } | |
904 | |
905 int32_t AudioMixerManagerMac::MicrophoneVolumeIsAvailable(bool& available) | |
906 { | |
907 if (_inputDeviceID == kAudioObjectUnknown) | |
908 { | |
909 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | |
910 " device ID has not been set"); | |
911 return -1; | |
912 } | |
913 | |
914 OSStatus err = noErr; | |
915 | |
916 // Does the capture device have a master volume control? | |
917 // If so, use it exclusively. | |
918 AudioObjectPropertyAddress | |
919 propertyAddress = { kAudioDevicePropertyVolumeScalar, | |
920 kAudioDevicePropertyScopeInput, 0 }; | |
921 Boolean isSettable = false; | |
922 err = AudioObjectIsPropertySettable(_inputDeviceID, &propertyAddress, | 876 err = AudioObjectIsPropertySettable(_inputDeviceID, &propertyAddress, |
923 &isSettable); | 877 &isSettable); |
924 if (err == noErr && isSettable) | 878 if (err == noErr && isSettable) { |
925 { | 879 size = sizeof(vol); |
926 available = true; | 880 WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData( |
927 return 0; | 881 _inputDeviceID, &propertyAddress, 0, NULL, size, &vol)); |
928 } | 882 } |
929 | 883 success = true; |
930 // Otherwise try to set each channel. | 884 } |
931 for (UInt32 i = 1; i <= _noInputChannels; i++) | 885 |
932 { | 886 if (!success) { |
933 propertyAddress.mElement = i; | 887 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
934 isSettable = false; | 888 " Unable to set a level on any input channel"); |
935 err = AudioObjectIsPropertySettable(_inputDeviceID, &propertyAddress, | 889 return -1; |
936 &isSettable); | 890 } |
937 if (err != noErr || !isSettable) | 891 |
938 { | 892 return 0; |
939 available = false; | 893 } |
940 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 894 |
941 " Volume cannot be set for input channel %d, err=%d", | 895 int32_t AudioMixerManagerMac::MicrophoneVolume(uint32_t& volume) const { |
942 i, err); | 896 if (_inputDeviceID == kAudioObjectUnknown) { |
943 return -1; | 897 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
944 } | 898 " device ID has not been set"); |
945 } | 899 return -1; |
946 | 900 } |
947 available = true; | 901 |
948 return 0; | 902 OSStatus err = noErr; |
949 } | 903 UInt32 size = 0; |
950 | 904 unsigned int channels = 0; |
951 int32_t AudioMixerManagerMac::SetMicrophoneVolume(uint32_t volume) | 905 Float32 channelVol = 0; |
952 { | 906 Float32 volFloat32 = 0; |
953 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 907 |
954 "AudioMixerManagerMac::SetMicrophoneVolume(volume=%u)", volume)
; | 908 // Does the device have a master volume control? |
955 | 909 // If so, use it exclusively. |
956 CriticalSectionScoped lock(&_critSect); | 910 AudioObjectPropertyAddress propertyAddress = { |
957 | 911 kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeInput, 0}; |
958 if (_inputDeviceID == kAudioObjectUnknown) | 912 Boolean hasProperty = |
959 { | 913 AudioObjectHasProperty(_inputDeviceID, &propertyAddress); |
960 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 914 if (hasProperty) { |
961 " device ID has not been set"); | 915 size = sizeof(volFloat32); |
962 return -1; | 916 WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( |
963 } | 917 _inputDeviceID, &propertyAddress, 0, NULL, &size, &volFloat32)); |
964 | 918 |
965 OSStatus err = noErr; | 919 // vol 0.0 to 1.0 -> convert to 0 - 255 |
966 UInt32 size = 0; | 920 volume = static_cast<uint32_t>(volFloat32 * 255 + 0.5); |
967 bool success = false; | 921 } else { |
968 | 922 // Otherwise get the average volume across channels. |
969 // volume range is 0.0 - 1.0, convert from 0 - 255 | 923 volFloat32 = 0; |
970 const Float32 vol = (Float32)(volume / 255.0); | 924 for (UInt32 i = 1; i <= _noInputChannels; i++) { |
971 | 925 channelVol = 0; |
972 assert(vol <= 1.0 && vol >= 0.0); | 926 propertyAddress.mElement = i; |
973 | 927 hasProperty = AudioObjectHasProperty(_inputDeviceID, &propertyAddress); |
974 // Does the capture device have a master volume control? | 928 if (hasProperty) { |
975 // If so, use it exclusively. | 929 size = sizeof(channelVol); |
976 AudioObjectPropertyAddress | 930 WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData( |
977 propertyAddress = { kAudioDevicePropertyVolumeScalar, | 931 _inputDeviceID, &propertyAddress, 0, NULL, &size, &channelVol)); |
978 kAudioDevicePropertyScopeInput, 0 }; | 932 |
979 Boolean isSettable = false; | 933 volFloat32 += channelVol; |
980 err = AudioObjectIsPropertySettable(_inputDeviceID, &propertyAddress, | 934 channels++; |
981 &isSettable); | 935 } |
982 if (err == noErr && isSettable) | 936 } |
983 { | 937 |
984 size = sizeof(vol); | 938 if (channels == 0) { |
985 WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData(_inputDeviceID, | 939 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
986 &propertyAddress, 0, NULL, size, &vol)); | 940 " Unable to get a level on any channel"); |
987 | 941 return -1; |
988 return 0; | 942 } |
989 } | 943 |
990 | 944 assert(channels > 0); |
991 // Otherwise try to set each channel. | 945 // vol 0.0 to 1.0 -> convert to 0 - 255 |
992 for (UInt32 i = 1; i <= _noInputChannels; i++) | 946 volume = static_cast<uint32_t>(255 * volFloat32 / channels + 0.5); |
993 { | 947 } |
994 propertyAddress.mElement = i; | 948 |
995 isSettable = false; | 949 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, |
996 err = AudioObjectIsPropertySettable(_inputDeviceID, &propertyAddress, | 950 " AudioMixerManagerMac::MicrophoneVolume() => vol=%u", |
997 &isSettable); | 951 volume); |
998 if (err == noErr && isSettable) | 952 |
999 { | 953 return 0; |
1000 size = sizeof(vol); | 954 } |
1001 WEBRTC_CA_RETURN_ON_ERR(AudioObjectSetPropertyData(_inputDeviceID, | 955 |
1002 &propertyAddress, 0, NULL, size, &vol)); | 956 int32_t AudioMixerManagerMac::MaxMicrophoneVolume(uint32_t& maxVolume) const { |
1003 } | 957 if (_inputDeviceID == kAudioObjectUnknown) { |
1004 success = true; | 958 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
1005 } | 959 " device ID has not been set"); |
1006 | 960 return -1; |
1007 if (!success) | 961 } |
1008 { | 962 |
1009 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 963 // volume range is 0.0 to 1.0 |
1010 " Unable to set a level on any input channel"); | 964 // we convert that to 0 - 255 |
1011 return -1; | 965 maxVolume = 255; |
1012 } | 966 |
1013 | 967 return 0; |
1014 return 0; | 968 } |
1015 } | 969 |
1016 | 970 int32_t AudioMixerManagerMac::MinMicrophoneVolume(uint32_t& minVolume) const { |
1017 int32_t | 971 if (_inputDeviceID == kAudioObjectUnknown) { |
1018 AudioMixerManagerMac::MicrophoneVolume(uint32_t& volume) const | 972 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
1019 { | 973 " device ID has not been set"); |
1020 | 974 return -1; |
1021 if (_inputDeviceID == kAudioObjectUnknown) | 975 } |
1022 { | 976 |
1023 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 977 // volume range is 0.0 to 1.0 |
1024 " device ID has not been set"); | 978 // we convert that to 0 - 10 |
1025 return -1; | 979 minVolume = 0; |
1026 } | 980 |
1027 | 981 return 0; |
1028 OSStatus err = noErr; | 982 } |
1029 UInt32 size = 0; | 983 |
1030 unsigned int channels = 0; | 984 int32_t AudioMixerManagerMac::MicrophoneVolumeStepSize( |
1031 Float32 channelVol = 0; | 985 uint16_t& stepSize) const { |
1032 Float32 volFloat32 = 0; | 986 if (_inputDeviceID == kAudioObjectUnknown) { |
1033 | 987 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, |
1034 // Does the device have a master volume control? | 988 " device ID has not been set"); |
1035 // If so, use it exclusively. | 989 return -1; |
1036 AudioObjectPropertyAddress | 990 } |
1037 propertyAddress = { kAudioDevicePropertyVolumeScalar, | 991 |
1038 kAudioDevicePropertyScopeInput, 0 }; | 992 // volume range is 0.0 to 1.0 |
1039 Boolean hasProperty = AudioObjectHasProperty(_inputDeviceID, | 993 // we convert that to 0 - 10 |
1040 &propertyAddress); | 994 stepSize = 1; |
1041 if (hasProperty) | 995 |
1042 { | 996 return 0; |
1043 size = sizeof(volFloat32); | |
1044 WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_inputDeviceID, | |
1045 &propertyAddress, 0, NULL, &size, &volFloat32)); | |
1046 | |
1047 // vol 0.0 to 1.0 -> convert to 0 - 255 | |
1048 volume = static_cast<uint32_t> (volFloat32 * 255 + 0.5); | |
1049 } else | |
1050 { | |
1051 // Otherwise get the average volume across channels. | |
1052 volFloat32 = 0; | |
1053 for (UInt32 i = 1; i <= _noInputChannels; i++) | |
1054 { | |
1055 channelVol = 0; | |
1056 propertyAddress.mElement = i; | |
1057 hasProperty = AudioObjectHasProperty(_inputDeviceID, | |
1058 &propertyAddress); | |
1059 if (hasProperty) | |
1060 { | |
1061 size = sizeof(channelVol); | |
1062 WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(_inputDeviceI
D, | |
1063 &propertyAddress, 0, NULL, &size, &channelVol)); | |
1064 | |
1065 volFloat32 += channelVol; | |
1066 channels++; | |
1067 } | |
1068 } | |
1069 | |
1070 if (channels == 0) | |
1071 { | |
1072 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | |
1073 " Unable to get a level on any channel"); | |
1074 return -1; | |
1075 } | |
1076 | |
1077 assert(channels > 0); | |
1078 // vol 0.0 to 1.0 -> convert to 0 - 255 | |
1079 volume = static_cast<uint32_t> | |
1080 (255 * volFloat32 / channels + 0.5); | |
1081 } | |
1082 | |
1083 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | |
1084 " AudioMixerManagerMac::MicrophoneVolume() => vol=%u", | |
1085 volume); | |
1086 | |
1087 return 0; | |
1088 } | |
1089 | |
1090 int32_t | |
1091 AudioMixerManagerMac::MaxMicrophoneVolume(uint32_t& maxVolume) const | |
1092 { | |
1093 | |
1094 if (_inputDeviceID == kAudioObjectUnknown) | |
1095 { | |
1096 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | |
1097 " device ID has not been set"); | |
1098 return -1; | |
1099 } | |
1100 | |
1101 // volume range is 0.0 to 1.0 | |
1102 // we convert that to 0 - 255 | |
1103 maxVolume = 255; | |
1104 | |
1105 return 0; | |
1106 } | |
1107 | |
1108 int32_t | |
1109 AudioMixerManagerMac::MinMicrophoneVolume(uint32_t& minVolume) const | |
1110 { | |
1111 | |
1112 if (_inputDeviceID == kAudioObjectUnknown) | |
1113 { | |
1114 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | |
1115 " device ID has not been set"); | |
1116 return -1; | |
1117 } | |
1118 | |
1119 // volume range is 0.0 to 1.0 | |
1120 // we convert that to 0 - 10 | |
1121 minVolume = 0; | |
1122 | |
1123 return 0; | |
1124 } | |
1125 | |
1126 int32_t | |
1127 AudioMixerManagerMac::MicrophoneVolumeStepSize(uint16_t& stepSize) const | |
1128 { | |
1129 | |
1130 if (_inputDeviceID == kAudioObjectUnknown) | |
1131 { | |
1132 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | |
1133 " device ID has not been set"); | |
1134 return -1; | |
1135 } | |
1136 | |
1137 // volume range is 0.0 to 1.0 | |
1138 // we convert that to 0 - 10 | |
1139 stepSize = 1; | |
1140 | |
1141 return 0; | |
1142 } | 997 } |
1143 | 998 |
1144 // ============================================================================ | 999 // ============================================================================ |
1145 // Private Methods | 1000 // Private Methods |
1146 // ============================================================================ | 1001 // ============================================================================ |
1147 | 1002 |
1148 // CoreAudio errors are best interpreted as four character strings. | 1003 // CoreAudio errors are best interpreted as four character strings. |
1149 void AudioMixerManagerMac::logCAMsg(const TraceLevel level, | 1004 void AudioMixerManagerMac::logCAMsg(const TraceLevel level, |
1150 const TraceModule module, | 1005 const TraceModule module, |
1151 const int32_t id, const char *msg, | 1006 const int32_t id, |
1152 const char *err) | 1007 const char* msg, |
1153 { | 1008 const char* err) { |
1154 assert(msg != NULL); | 1009 assert(msg != NULL); |
1155 assert(err != NULL); | 1010 assert(err != NULL); |
1156 | 1011 |
1157 #ifdef WEBRTC_ARCH_BIG_ENDIAN | 1012 #ifdef WEBRTC_ARCH_BIG_ENDIAN |
1158 WEBRTC_TRACE(level, module, id, "%s: %.4s", msg, err); | 1013 WEBRTC_TRACE(level, module, id, "%s: %.4s", msg, err); |
1159 #else | 1014 #else |
1160 // We need to flip the characters in this case. | 1015 // We need to flip the characters in this case. |
1161 WEBRTC_TRACE(level, module, id, "%s: %.1s%.1s%.1s%.1s", msg, err + 3, err | 1016 WEBRTC_TRACE(level, module, id, "%s: %.1s%.1s%.1s%.1s", msg, err + 3, err + 2, |
1162 + 2, err + 1, err); | 1017 err + 1, err); |
1163 #endif | 1018 #endif |
1164 } | 1019 } |
1165 | 1020 |
1166 } // namespace webrtc | 1021 } // namespace webrtc |
1167 // EOF | 1022 // EOF |
OLD | NEW |