OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | |
3 * | |
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 | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 #include "webrtc/voice_engine/voe_hardware_impl.h" | |
12 | |
13 #include <assert.h> | |
14 | |
15 #include "webrtc/system_wrappers/include/trace.h" | |
16 #include "webrtc/voice_engine/include/voe_errors.h" | |
17 #include "webrtc/voice_engine/voice_engine_impl.h" | |
18 | |
19 namespace webrtc { | |
20 | |
21 VoEHardware* VoEHardware::GetInterface(VoiceEngine* voiceEngine) { | |
22 if (NULL == voiceEngine) { | |
23 return NULL; | |
24 } | |
25 VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine); | |
26 s->AddRef(); | |
27 return s; | |
28 } | |
29 | |
30 VoEHardwareImpl::VoEHardwareImpl(voe::SharedData* shared) : _shared(shared) { | |
31 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1), | |
32 "VoEHardwareImpl() - ctor"); | |
33 } | |
34 | |
35 VoEHardwareImpl::~VoEHardwareImpl() { | |
36 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1), | |
37 "~VoEHardwareImpl() - dtor"); | |
38 } | |
39 | |
40 int VoEHardwareImpl::SetAudioDeviceLayer(AudioLayers audioLayer) { | |
41 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), | |
42 "SetAudioDeviceLayer(audioLayer=%d)", audioLayer); | |
43 | |
44 // Don't allow a change if VoE is initialized | |
45 if (_shared->statistics().Initialized()) { | |
46 _shared->SetLastError(VE_ALREADY_INITED, kTraceError); | |
47 return -1; | |
48 } | |
49 | |
50 // Map to AudioDeviceModule::AudioLayer | |
51 AudioDeviceModule::AudioLayer wantedLayer( | |
52 AudioDeviceModule::kPlatformDefaultAudio); | |
53 switch (audioLayer) { | |
54 case kAudioPlatformDefault: | |
55 // already set above | |
56 break; | |
57 case kAudioWindowsCore: | |
58 wantedLayer = AudioDeviceModule::kWindowsCoreAudio; | |
59 break; | |
60 case kAudioLinuxAlsa: | |
61 wantedLayer = AudioDeviceModule::kLinuxAlsaAudio; | |
62 break; | |
63 case kAudioLinuxPulse: | |
64 wantedLayer = AudioDeviceModule::kLinuxPulseAudio; | |
65 break; | |
66 } | |
67 | |
68 // Save the audio device layer for Init() | |
69 _shared->set_audio_device_layer(wantedLayer); | |
70 | |
71 return 0; | |
72 } | |
73 | |
74 int VoEHardwareImpl::GetAudioDeviceLayer(AudioLayers& audioLayer) { | |
75 // Can always be called regardless of VoE state | |
76 | |
77 AudioDeviceModule::AudioLayer activeLayer( | |
78 AudioDeviceModule::kPlatformDefaultAudio); | |
79 | |
80 if (_shared->audio_device()) { | |
81 // Get active audio layer from ADM | |
82 if (_shared->audio_device()->ActiveAudioLayer(&activeLayer) != 0) { | |
83 _shared->SetLastError(VE_UNDEFINED_SC_ERR, kTraceError, | |
84 " Audio Device error"); | |
85 return -1; | |
86 } | |
87 } else { | |
88 // Return VoE's internal layer setting | |
89 activeLayer = _shared->audio_device_layer(); | |
90 } | |
91 | |
92 // Map to AudioLayers | |
93 switch (activeLayer) { | |
94 case AudioDeviceModule::kPlatformDefaultAudio: | |
95 audioLayer = kAudioPlatformDefault; | |
96 break; | |
97 case AudioDeviceModule::kWindowsCoreAudio: | |
98 audioLayer = kAudioWindowsCore; | |
99 break; | |
100 case AudioDeviceModule::kLinuxAlsaAudio: | |
101 audioLayer = kAudioLinuxAlsa; | |
102 break; | |
103 case AudioDeviceModule::kLinuxPulseAudio: | |
104 audioLayer = kAudioLinuxPulse; | |
105 break; | |
106 default: | |
107 _shared->SetLastError(VE_UNDEFINED_SC_ERR, kTraceError, | |
108 " unknown audio layer"); | |
109 } | |
110 | |
111 return 0; | |
112 } | |
113 int VoEHardwareImpl::GetNumOfRecordingDevices(int& devices) { | |
114 if (!_shared->statistics().Initialized()) { | |
115 _shared->SetLastError(VE_NOT_INITED, kTraceError); | |
116 return -1; | |
117 } | |
118 | |
119 devices = static_cast<int>(_shared->audio_device()->RecordingDevices()); | |
120 | |
121 return 0; | |
122 } | |
123 | |
124 int VoEHardwareImpl::GetNumOfPlayoutDevices(int& devices) { | |
125 if (!_shared->statistics().Initialized()) { | |
126 _shared->SetLastError(VE_NOT_INITED, kTraceError); | |
127 return -1; | |
128 } | |
129 | |
130 devices = static_cast<int>(_shared->audio_device()->PlayoutDevices()); | |
131 | |
132 return 0; | |
133 } | |
134 | |
135 int VoEHardwareImpl::GetRecordingDeviceName(int index, | |
136 char strNameUTF8[128], | |
137 char strGuidUTF8[128]) { | |
138 if (!_shared->statistics().Initialized()) { | |
139 _shared->SetLastError(VE_NOT_INITED, kTraceError); | |
140 return -1; | |
141 } | |
142 if (strNameUTF8 == NULL) { | |
143 _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError, | |
144 "GetRecordingDeviceName() invalid argument"); | |
145 return -1; | |
146 } | |
147 | |
148 // Note that strGuidUTF8 is allowed to be NULL | |
149 | |
150 // Init len variable to length of supplied vectors | |
151 const uint16_t strLen = 128; | |
152 | |
153 // Check if length has been changed in module | |
154 static_assert(strLen == kAdmMaxDeviceNameSize, ""); | |
155 static_assert(strLen == kAdmMaxGuidSize, ""); | |
156 | |
157 char name[strLen]; | |
158 char guid[strLen]; | |
159 | |
160 // Get names from module | |
161 if (_shared->audio_device()->RecordingDeviceName(index, name, guid) != 0) { | |
162 _shared->SetLastError(VE_CANNOT_RETRIEVE_DEVICE_NAME, kTraceError, | |
163 "GetRecordingDeviceName() failed to get device name"); | |
164 return -1; | |
165 } | |
166 | |
167 // Copy to vectors supplied by user | |
168 strncpy(strNameUTF8, name, strLen); | |
169 | |
170 if (strGuidUTF8 != NULL) { | |
171 strncpy(strGuidUTF8, guid, strLen); | |
172 } | |
173 | |
174 return 0; | |
175 } | |
176 | |
177 int VoEHardwareImpl::GetPlayoutDeviceName(int index, | |
178 char strNameUTF8[128], | |
179 char strGuidUTF8[128]) { | |
180 if (!_shared->statistics().Initialized()) { | |
181 _shared->SetLastError(VE_NOT_INITED, kTraceError); | |
182 return -1; | |
183 } | |
184 if (strNameUTF8 == NULL) { | |
185 _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError, | |
186 "GetPlayoutDeviceName() invalid argument"); | |
187 return -1; | |
188 } | |
189 | |
190 // Note that strGuidUTF8 is allowed to be NULL | |
191 | |
192 // Init len variable to length of supplied vectors | |
193 const uint16_t strLen = 128; | |
194 | |
195 // Check if length has been changed in module | |
196 static_assert(strLen == kAdmMaxDeviceNameSize, ""); | |
197 static_assert(strLen == kAdmMaxGuidSize, ""); | |
198 | |
199 char name[strLen]; | |
200 char guid[strLen]; | |
201 | |
202 // Get names from module | |
203 if (_shared->audio_device()->PlayoutDeviceName(index, name, guid) != 0) { | |
204 _shared->SetLastError(VE_CANNOT_RETRIEVE_DEVICE_NAME, kTraceError, | |
205 "GetPlayoutDeviceName() failed to get device name"); | |
206 return -1; | |
207 } | |
208 | |
209 // Copy to vectors supplied by user | |
210 strncpy(strNameUTF8, name, strLen); | |
211 | |
212 if (strGuidUTF8 != NULL) { | |
213 strncpy(strGuidUTF8, guid, strLen); | |
214 } | |
215 | |
216 return 0; | |
217 } | |
218 | |
219 int VoEHardwareImpl::SetRecordingDevice(int index, | |
220 StereoChannel recordingChannel) { | |
221 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), | |
222 "SetRecordingDevice(index=%d, recordingChannel=%d)", index, | |
223 (int)recordingChannel); | |
224 rtc::CritScope cs(_shared->crit_sec()); | |
225 | |
226 if (!_shared->statistics().Initialized()) { | |
227 _shared->SetLastError(VE_NOT_INITED, kTraceError); | |
228 return -1; | |
229 } | |
230 | |
231 bool isRecording(false); | |
232 | |
233 // Store state about activated recording to be able to restore it after the | |
234 // recording device has been modified. | |
235 if (_shared->audio_device()->Recording()) { | |
236 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1), | |
237 "SetRecordingDevice() device is modified while recording" | |
238 " is active..."); | |
239 isRecording = true; | |
240 if (_shared->audio_device()->StopRecording() == -1) { | |
241 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError, | |
242 "SetRecordingDevice() unable to stop recording"); | |
243 return -1; | |
244 } | |
245 } | |
246 | |
247 // We let the module do the index sanity | |
248 | |
249 // Set recording channel | |
250 AudioDeviceModule::ChannelType recCh = AudioDeviceModule::kChannelBoth; | |
251 switch (recordingChannel) { | |
252 case kStereoLeft: | |
253 recCh = AudioDeviceModule::kChannelLeft; | |
254 break; | |
255 case kStereoRight: | |
256 recCh = AudioDeviceModule::kChannelRight; | |
257 break; | |
258 case kStereoBoth: | |
259 // default setting kChannelBoth (<=> mono) | |
260 break; | |
261 } | |
262 | |
263 if (_shared->audio_device()->SetRecordingChannel(recCh) != 0) { | |
264 _shared->SetLastError( | |
265 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning, | |
266 "SetRecordingChannel() unable to set the recording channel"); | |
267 } | |
268 | |
269 // Map indices to unsigned since underlying functions need that | |
270 uint16_t indexU = static_cast<uint16_t>(index); | |
271 | |
272 int32_t res(0); | |
273 | |
274 if (index == -1) { | |
275 res = _shared->audio_device()->SetRecordingDevice( | |
276 AudioDeviceModule::kDefaultCommunicationDevice); | |
277 } else if (index == -2) { | |
278 res = _shared->audio_device()->SetRecordingDevice( | |
279 AudioDeviceModule::kDefaultDevice); | |
280 } else { | |
281 res = _shared->audio_device()->SetRecordingDevice(indexU); | |
282 } | |
283 | |
284 if (res != 0) { | |
285 _shared->SetLastError( | |
286 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError, | |
287 "SetRecordingDevice() unable to set the recording device"); | |
288 return -1; | |
289 } | |
290 | |
291 // Init microphone, so user can do volume settings etc | |
292 if (_shared->audio_device()->InitMicrophone() == -1) { | |
293 _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceWarning, | |
294 "SetRecordingDevice() cannot access microphone"); | |
295 } | |
296 | |
297 // Set number of channels | |
298 bool available = false; | |
299 if (_shared->audio_device()->StereoRecordingIsAvailable(&available) != 0) { | |
300 _shared->SetLastError( | |
301 VE_SOUNDCARD_ERROR, kTraceWarning, | |
302 "StereoRecordingIsAvailable() failed to query stereo recording"); | |
303 } | |
304 | |
305 if (_shared->audio_device()->SetStereoRecording(available) != 0) { | |
306 _shared->SetLastError( | |
307 VE_SOUNDCARD_ERROR, kTraceWarning, | |
308 "SetRecordingDevice() failed to set mono recording mode"); | |
309 } | |
310 | |
311 // Restore recording if it was enabled already when calling this function. | |
312 if (isRecording) { | |
313 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1), | |
314 "SetRecordingDevice() recording is now being restored..."); | |
315 if (_shared->audio_device()->InitRecording() != 0) { | |
316 WEBRTC_TRACE(kTraceError, kTraceVoice, | |
317 VoEId(_shared->instance_id(), -1), | |
318 "SetRecordingDevice() failed to initialize recording"); | |
319 return -1; | |
320 } | |
321 if (_shared->audio_device()->StartRecording() != 0) { | |
322 WEBRTC_TRACE(kTraceError, kTraceVoice, | |
323 VoEId(_shared->instance_id(), -1), | |
324 "SetRecordingDevice() failed to start recording"); | |
325 return -1; | |
326 } | |
327 } | |
328 | |
329 return 0; | |
330 } | |
331 | |
332 int VoEHardwareImpl::SetPlayoutDevice(int index) { | |
333 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), | |
334 "SetPlayoutDevice(index=%d)", index); | |
335 rtc::CritScope cs(_shared->crit_sec()); | |
336 | |
337 if (!_shared->statistics().Initialized()) { | |
338 _shared->SetLastError(VE_NOT_INITED, kTraceError); | |
339 return -1; | |
340 } | |
341 | |
342 bool isPlaying(false); | |
343 | |
344 // Store state about activated playout to be able to restore it after the | |
345 // playout device has been modified. | |
346 if (_shared->audio_device()->Playing()) { | |
347 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1), | |
348 "SetPlayoutDevice() device is modified while playout is " | |
349 "active..."); | |
350 isPlaying = true; | |
351 if (_shared->audio_device()->StopPlayout() == -1) { | |
352 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError, | |
353 "SetPlayoutDevice() unable to stop playout"); | |
354 return -1; | |
355 } | |
356 } | |
357 | |
358 // We let the module do the index sanity | |
359 | |
360 // Map indices to unsigned since underlying functions need that | |
361 uint16_t indexU = static_cast<uint16_t>(index); | |
362 | |
363 int32_t res(0); | |
364 | |
365 if (index == -1) { | |
366 res = _shared->audio_device()->SetPlayoutDevice( | |
367 AudioDeviceModule::kDefaultCommunicationDevice); | |
368 } else if (index == -2) { | |
369 res = _shared->audio_device()->SetPlayoutDevice( | |
370 AudioDeviceModule::kDefaultDevice); | |
371 } else { | |
372 res = _shared->audio_device()->SetPlayoutDevice(indexU); | |
373 } | |
374 | |
375 if (res != 0) { | |
376 _shared->SetLastError( | |
377 VE_SOUNDCARD_ERROR, kTraceError, | |
378 "SetPlayoutDevice() unable to set the playout device"); | |
379 return -1; | |
380 } | |
381 | |
382 // Init speaker, so user can do volume settings etc | |
383 if (_shared->audio_device()->InitSpeaker() == -1) { | |
384 _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceWarning, | |
385 "SetPlayoutDevice() cannot access speaker"); | |
386 } | |
387 | |
388 // Set number of channels | |
389 bool available = false; | |
390 _shared->audio_device()->StereoPlayoutIsAvailable(&available); | |
391 if (_shared->audio_device()->SetStereoPlayout(available) != 0) { | |
392 _shared->SetLastError( | |
393 VE_SOUNDCARD_ERROR, kTraceWarning, | |
394 "SetPlayoutDevice() failed to set stereo playout mode"); | |
395 } | |
396 | |
397 // Restore playout if it was enabled already when calling this function. | |
398 if (isPlaying) { | |
399 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1), | |
400 "SetPlayoutDevice() playout is now being restored..."); | |
401 if (_shared->audio_device()->InitPlayout() != 0) { | |
402 WEBRTC_TRACE(kTraceError, kTraceVoice, | |
403 VoEId(_shared->instance_id(), -1), | |
404 "SetPlayoutDevice() failed to initialize playout"); | |
405 return -1; | |
406 } | |
407 if (_shared->audio_device()->StartPlayout() != 0) { | |
408 WEBRTC_TRACE(kTraceError, kTraceVoice, | |
409 VoEId(_shared->instance_id(), -1), | |
410 "SetPlayoutDevice() failed to start playout"); | |
411 return -1; | |
412 } | |
413 } | |
414 | |
415 return 0; | |
416 } | |
417 | |
418 int VoEHardwareImpl::SetRecordingSampleRate(unsigned int samples_per_sec) { | |
419 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), | |
420 "%s", __FUNCTION__); | |
421 if (!_shared->statistics().Initialized()) { | |
422 _shared->SetLastError(VE_NOT_INITED, kTraceError); | |
423 return false; | |
424 } | |
425 return _shared->audio_device()->SetRecordingSampleRate(samples_per_sec); | |
426 } | |
427 | |
428 int VoEHardwareImpl::RecordingSampleRate(unsigned int* samples_per_sec) const { | |
429 if (!_shared->statistics().Initialized()) { | |
430 _shared->SetLastError(VE_NOT_INITED, kTraceError); | |
431 return false; | |
432 } | |
433 return _shared->audio_device()->RecordingSampleRate(samples_per_sec); | |
434 } | |
435 | |
436 int VoEHardwareImpl::SetPlayoutSampleRate(unsigned int samples_per_sec) { | |
437 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), | |
438 "%s", __FUNCTION__); | |
439 if (!_shared->statistics().Initialized()) { | |
440 _shared->SetLastError(VE_NOT_INITED, kTraceError); | |
441 return false; | |
442 } | |
443 return _shared->audio_device()->SetPlayoutSampleRate(samples_per_sec); | |
444 } | |
445 | |
446 int VoEHardwareImpl::PlayoutSampleRate(unsigned int* samples_per_sec) const { | |
447 if (!_shared->statistics().Initialized()) { | |
448 _shared->SetLastError(VE_NOT_INITED, kTraceError); | |
449 return false; | |
450 } | |
451 return _shared->audio_device()->PlayoutSampleRate(samples_per_sec); | |
452 } | |
453 | |
454 bool VoEHardwareImpl::BuiltInAECIsAvailable() const { | |
455 if (!_shared->statistics().Initialized()) { | |
456 _shared->SetLastError(VE_NOT_INITED, kTraceError); | |
457 return false; | |
458 } | |
459 return _shared->audio_device()->BuiltInAECIsAvailable(); | |
460 } | |
461 | |
462 int VoEHardwareImpl::EnableBuiltInAEC(bool enable) { | |
463 if (!_shared->statistics().Initialized()) { | |
464 _shared->SetLastError(VE_NOT_INITED, kTraceError); | |
465 return -1; | |
466 } | |
467 return _shared->audio_device()->EnableBuiltInAEC(enable); | |
468 } | |
469 | |
470 bool VoEHardwareImpl::BuiltInAGCIsAvailable() const { | |
471 if (!_shared->statistics().Initialized()) { | |
472 _shared->SetLastError(VE_NOT_INITED, kTraceError); | |
473 return false; | |
474 } | |
475 return _shared->audio_device()->BuiltInAGCIsAvailable(); | |
476 } | |
477 | |
478 int VoEHardwareImpl::EnableBuiltInAGC(bool enable) { | |
479 if (!_shared->statistics().Initialized()) { | |
480 _shared->SetLastError(VE_NOT_INITED, kTraceError); | |
481 return -1; | |
482 } | |
483 return _shared->audio_device()->EnableBuiltInAGC(enable); | |
484 } | |
485 | |
486 bool VoEHardwareImpl::BuiltInNSIsAvailable() const { | |
487 if (!_shared->statistics().Initialized()) { | |
488 _shared->SetLastError(VE_NOT_INITED, kTraceError); | |
489 return false; | |
490 } | |
491 return _shared->audio_device()->BuiltInNSIsAvailable(); | |
492 } | |
493 | |
494 int VoEHardwareImpl::EnableBuiltInNS(bool enable) { | |
495 if (!_shared->statistics().Initialized()) { | |
496 _shared->SetLastError(VE_NOT_INITED, kTraceError); | |
497 return -1; | |
498 } | |
499 return _shared->audio_device()->EnableBuiltInNS(enable); | |
500 } | |
501 | |
502 } // namespace webrtc | |
OLD | NEW |