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