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