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/modules/audio_device/audio_device_config.h" 12 #include "webrtc/modules/audio_device/audio_device_utility.h" 13 #include "webrtc/modules/audio_device/win/audio_device_wave_win.h" 14 15 #include "webrtc/system_wrappers/interface/event_wrapper.h" 16 #include "webrtc/system_wrappers/interface/thread_wrapper.h" 17 #include "webrtc/system_wrappers/interface/trace.h" 18 19 #include <windows.h> 20 #include <objbase.h> // CoTaskMemAlloc, CoTaskMemFree 21 #include <strsafe.h> // StringCchCopy(), StringCchCat(), StringCchPrintf() 22 #include <assert.h> 23 24 // Avoids the need of Windows 7 SDK 25 #ifndef WAVE_MAPPED_DEFAULT_COMMUNICATION_DEVICE 26 #define WAVE_MAPPED_DEFAULT_COMMUNICATION_DEVICE 0x0010 27 #endif 28 29 // Supported in Windows Vista and Windows 7. 30 // http://msdn.microsoft.com/en-us/library/dd370819(v=VS.85).aspx 31 // Taken from Mmddk.h. 32 #define DRV_RESERVED 0x0800 33 #define DRV_QUERYFUNCTIONINSTANCEID (DRV_RESERVED + 17) 34 #define DRV_QUERYFUNCTIONINSTANCEIDSIZE (DRV_RESERVED + 18) 35 36 #define POW2(A) (2 << ((A) - 1)) 37 38 namespace webrtc { 39 40 // ============================================================================ 41 // Construction & Destruction 42 // ============================================================================ 43 44 // ---------------------------------------------------------------------------- 45 // AudioDeviceWindowsWave - ctor 46 // ---------------------------------------------------------------------------- 47 48 AudioDeviceWindowsWave::AudioDeviceWindowsWave(const int32_t id) : 49 _ptrAudioBuffer(NULL), 50 _critSect(*CriticalSectionWrapper::CreateCriticalSection()), 51 _timeEvent(*EventWrapper::Create()), 52 _recStartEvent(*EventWrapper::Create()), 53 _playStartEvent(*EventWrapper::Create()), 54 _hGetCaptureVolumeThread(NULL), 55 _hShutdownGetVolumeEvent(NULL), 56 _hSetCaptureVolumeThread(NULL), 57 _hShutdownSetVolumeEvent(NULL), 58 _hSetCaptureVolumeEvent(NULL), 59 _ptrThread(NULL), 60 _threadID(0), 61 _critSectCb(*CriticalSectionWrapper::CreateCriticalSection()), 62 _id(id), 63 _mixerManager(id), 64 _usingInputDeviceIndex(false), 65 _usingOutputDeviceIndex(false), 66 _inputDevice(AudioDeviceModule::kDefaultDevice), 67 _outputDevice(AudioDeviceModule::kDefaultDevice), 68 _inputDeviceIndex(0), 69 _outputDeviceIndex(0), 70 _inputDeviceIsSpecified(false), 71 _outputDeviceIsSpecified(false), 72 _initialized(false), 73 _recIsInitialized(false), 74 _playIsInitialized(false), 75 _recording(false), 76 _playing(false), 77 _startRec(false), 78 _stopRec(false), 79 _startPlay(false), 80 _stopPlay(false), 81 _AGC(false), 82 _hWaveIn(NULL), 83 _hWaveOut(NULL), 84 _recChannels(N_REC_CHANNELS), 85 _playChannels(N_PLAY_CHANNELS), 86 _recBufCount(0), 87 _recPutBackDelay(0), 88 _recDelayCount(0), 89 _playBufCount(0), 90 _prevPlayTime(0), 91 _prevRecTime(0), 92 _prevTimerCheckTime(0), 93 _timesdwBytes(0), 94 _timerFaults(0), 95 _timerRestartAttempts(0), 96 _no_of_msecleft_warnings(0), 97 _MAX_minBuffer(65), 98 _useHeader(0), 99 _dTcheckPlayBufDelay(10), 100 _playBufDelay(80), 101 _playBufDelayFixed(80), 102 _minPlayBufDelay(20), 103 _avgCPULoad(0), 104 _sndCardPlayDelay(0), 105 _sndCardRecDelay(0), 106 _plSampOld(0), 107 _rcSampOld(0), 108 _playBufType(AudioDeviceModule::kAdaptiveBufferSize), 109 _recordedBytes(0), 110 _playWarning(0), 111 _playError(0), 112 _recWarning(0), 113 _recError(0), 114 _newMicLevel(0), 115 _minMicVolume(0), 116 _maxMicVolume(0) 117 { 118 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, id, "%s created", __FUNCTION__); 119 120 // Initialize value, set to 0 if it fails 121 if (!QueryPerformanceFrequency(&_perfFreq)) 122 { 123 _perfFreq.QuadPart = 0; 124 } 125 126 _hShutdownGetVolumeEvent = CreateEvent(NULL, FALSE, FALSE, NULL); 127 _hShutdownSetVolumeEvent = CreateEvent(NULL, FALSE, FALSE, NULL); 128 _hSetCaptureVolumeEvent = CreateEvent(NULL, FALSE, FALSE, NULL); 129 } 130 131 // ---------------------------------------------------------------------------- 132 // AudioDeviceWindowsWave - dtor 133 // ---------------------------------------------------------------------------- 134 135 AudioDeviceWindowsWave::~AudioDeviceWindowsWave() 136 { 137 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s destroyed", __FUNCTION__); 138 139 Terminate(); 140 141 delete &_recStartEvent; 142 delete &_playStartEvent; 143 delete &_timeEvent; 144 delete &_critSect; 145 delete &_critSectCb; 146 147 if (NULL != _hShutdownGetVolumeEvent) 148 { 149 CloseHandle(_hShutdownGetVolumeEvent); 150 _hShutdownGetVolumeEvent = NULL; 151 } 152 153 if (NULL != _hShutdownSetVolumeEvent) 154 { 155 CloseHandle(_hShutdownSetVolumeEvent); 156 _hShutdownSetVolumeEvent = NULL; 157 } 158 159 if (NULL != _hSetCaptureVolumeEvent) 160 { 161 CloseHandle(_hSetCaptureVolumeEvent); 162 _hSetCaptureVolumeEvent = NULL; 163 } 164 } 165 166 // ============================================================================ 167 // API 168 // ============================================================================ 169 170 // ---------------------------------------------------------------------------- 171 // AttachAudioBuffer 172 // ---------------------------------------------------------------------------- 173 174 void AudioDeviceWindowsWave::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) 175 { 176 177 CriticalSectionScoped lock(&_critSect); 178 179 _ptrAudioBuffer = audioBuffer; 180 181 // inform the AudioBuffer about default settings for this implementation 182 _ptrAudioBuffer->SetRecordingSampleRate(N_REC_SAMPLES_PER_SEC); 183 _ptrAudioBuffer->SetPlayoutSampleRate(N_PLAY_SAMPLES_PER_SEC); 184 _ptrAudioBuffer->SetRecordingChannels(N_REC_CHANNELS); 185 _ptrAudioBuffer->SetPlayoutChannels(N_PLAY_CHANNELS); 186 } 187 188 // ---------------------------------------------------------------------------- 189 // ActiveAudioLayer 190 // ---------------------------------------------------------------------------- 191 192 int32_t AudioDeviceWindowsWave::ActiveAudioLayer(AudioDeviceModule::AudioLayer& audioLayer) const 193 { 194 audioLayer = AudioDeviceModule::kWindowsWaveAudio; 195 return 0; 196 } 197 198 // ---------------------------------------------------------------------------- 199 // Init 200 // ---------------------------------------------------------------------------- 201 202 int32_t AudioDeviceWindowsWave::Init() 203 { 204 205 CriticalSectionScoped lock(&_critSect); 206 207 if (_initialized) 208 { 209 return 0; 210 } 211 212 const uint32_t nowTime(AudioDeviceUtility::GetTimeInMS()); 213 214 _recordedBytes = 0; 215 _prevRecByteCheckTime = nowTime; 216 _prevRecTime = nowTime; 217 _prevPlayTime = nowTime; 218 _prevTimerCheckTime = nowTime; 219 220 _playWarning = 0; 221 _playError = 0; 222 _recWarning = 0; 223 _recError = 0; 224 225 _mixerManager.EnumerateAll(); 226 227 if (_ptrThread) 228 { 229 // thread is already created and active 230 return 0; 231 } 232 233 const char* threadName = "webrtc_audio_module_thread"; 234 _ptrThread = ThreadWrapper::CreateThread(ThreadFunc, 235 this, 236 kRealtimePriority, 237 threadName); 238 if (_ptrThread == NULL) 239 { 240 WEBRTC_TRACE(kTraceCritical, kTraceAudioDevice, _id, 241 "failed to create the audio thread"); 242 return -1; 243 } 244 245 unsigned int threadID(0); 246 if (!_ptrThread->Start(threadID)) 247 { 248 WEBRTC_TRACE(kTraceCritical, kTraceAudioDevice, _id, 249 "failed to start the audio thread"); 250 delete _ptrThread; 251 _ptrThread = NULL; 252 return -1; 253 } 254 _threadID = threadID; 255 256 const bool periodic(true); 257 if (!_timeEvent.StartTimer(periodic, TIMER_PERIOD_MS)) 258 { 259 WEBRTC_TRACE(kTraceCritical, kTraceAudioDevice, _id, 260 "failed to start the timer event"); 261 if (_ptrThread->Stop()) 262 { 263 delete _ptrThread; 264 _ptrThread = NULL; 265 } 266 else 267 { 268 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 269 "unable to stop the activated thread"); 270 } 271 return -1; 272 } 273 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 274 "periodic timer (dT=%d) is now active", TIMER_PERIOD_MS); 275 276 _hGetCaptureVolumeThread = CreateThread(NULL, 277 0, 278 GetCaptureVolumeThread, 279 this, 280 0, 281 NULL); 282 if (_hGetCaptureVolumeThread == NULL) 283 { 284 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 285 " failed to create the volume getter thread"); 286 return -1; 287 } 288 289 SetThreadPriority(_hGetCaptureVolumeThread, THREAD_PRIORITY_NORMAL); 290 291 _hSetCaptureVolumeThread = CreateThread(NULL, 292 0, 293 SetCaptureVolumeThread, 294 this, 295 0, 296 NULL); 297 if (_hSetCaptureVolumeThread == NULL) 298 { 299 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 300 " failed to create the volume setter thread"); 301 return -1; 302 } 303 304 SetThreadPriority(_hSetCaptureVolumeThread, THREAD_PRIORITY_NORMAL); 305 306 _initialized = true; 307 308 return 0; 309 } 310 311 // ---------------------------------------------------------------------------- 312 // Terminate 313 // ---------------------------------------------------------------------------- 314 315 int32_t AudioDeviceWindowsWave::Terminate() 316 { 317 318 if (!_initialized) 319 { 320 return 0; 321 } 322 323 _critSect.Enter(); 324 325 _mixerManager.Close(); 326 327 if (_ptrThread) 328 { 329 ThreadWrapper* tmpThread = _ptrThread; 330 _ptrThread = NULL; 331 _critSect.Leave(); 332 333 tmpThread->SetNotAlive(); 334 _timeEvent.Set(); 335 336 if (tmpThread->Stop()) 337 { 338 delete tmpThread; 339 } 340 else 341 { 342 _critSect.Leave(); 343 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 344 "failed to close down the audio thread"); 345 return -1; 346 } 347 } 348 else 349 { 350 _critSect.Leave(); 351 } 352 353 _critSect.Enter(); 354 SetEvent(_hShutdownGetVolumeEvent); 355 _critSect.Leave(); 356 int32_t ret = WaitForSingleObject(_hGetCaptureVolumeThread, 2000); 357 if (ret != WAIT_OBJECT_0) 358 { 359 // the thread did not stop as it should 360 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 361 " failed to close down volume getter thread"); 362 CloseHandle(_hGetCaptureVolumeThread); 363 _hGetCaptureVolumeThread = NULL; 364 return -1; 365 } 366 _critSect.Enter(); 367 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 368 " volume getter thread is now closed"); 369 370 SetEvent(_hShutdownSetVolumeEvent); 371 _critSect.Leave(); 372 ret = WaitForSingleObject(_hSetCaptureVolumeThread, 2000); 373 if (ret != WAIT_OBJECT_0) 374 { 375 // the thread did not stop as it should 376 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 377 " failed to close down volume setter thread"); 378 CloseHandle(_hSetCaptureVolumeThread); 379 _hSetCaptureVolumeThread = NULL; 380 return -1; 381 } 382 _critSect.Enter(); 383 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 384 " volume setter thread is now closed"); 385 386 CloseHandle(_hGetCaptureVolumeThread); 387 _hGetCaptureVolumeThread = NULL; 388 389 CloseHandle(_hSetCaptureVolumeThread); 390 _hSetCaptureVolumeThread = NULL; 391 392 _critSect.Leave(); 393 394 _timeEvent.StopTimer(); 395 396 _initialized = false; 397 _outputDeviceIsSpecified = false; 398 _inputDeviceIsSpecified = false; 399 400 return 0; 401 } 402 403 404 DWORD WINAPI AudioDeviceWindowsWave::GetCaptureVolumeThread(LPVOID context) 405 { 406 return(((AudioDeviceWindowsWave*)context)->DoGetCaptureVolumeThread()); 407 } 408 409 DWORD WINAPI AudioDeviceWindowsWave::SetCaptureVolumeThread(LPVOID context) 410 { 411 return(((AudioDeviceWindowsWave*)context)->DoSetCaptureVolumeThread()); 412 } 413 414 DWORD AudioDeviceWindowsWave::DoGetCaptureVolumeThread() 415 { 416 HANDLE waitObject = _hShutdownGetVolumeEvent; 417 418 while (1) 419 { 420 DWORD waitResult = WaitForSingleObject(waitObject, 421 GET_MIC_VOLUME_INTERVAL_MS); 422 switch (waitResult) 423 { 424 case WAIT_OBJECT_0: // _hShutdownGetVolumeEvent 425 return 0; 426 case WAIT_TIMEOUT: // timeout notification 427 break; 428 default: // unexpected error 429 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 430 " unknown wait termination on get volume thread"); 431 return -1; 432 } 433 434 if (AGC()) 435 { 436 uint32_t currentMicLevel = 0; 437 if (MicrophoneVolume(currentMicLevel) == 0) 438 { 439 // This doesn't set the system volume, just stores it. 440 _critSect.Enter(); 441 if (_ptrAudioBuffer) 442 { 443 _ptrAudioBuffer->SetCurrentMicLevel(currentMicLevel); 444 } 445 _critSect.Leave(); 446 } 447 } 448 } 449 } 450 451 DWORD AudioDeviceWindowsWave::DoSetCaptureVolumeThread() 452 { 453 HANDLE waitArray[2] = {_hShutdownSetVolumeEvent, _hSetCaptureVolumeEvent}; 454 455 while (1) 456 { 457 DWORD waitResult = WaitForMultipleObjects(2, waitArray, FALSE, INFINITE); 458 switch (waitResult) 459 { 460 case WAIT_OBJECT_0: // _hShutdownSetVolumeEvent 461 return 0; 462 case WAIT_OBJECT_0 + 1: // _hSetCaptureVolumeEvent 463 break; 464 default: // unexpected error 465 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 466 " unknown wait termination on set volume thread"); 467 return -1; 468 } 469 470 _critSect.Enter(); 471 uint32_t newMicLevel = _newMicLevel; 472 _critSect.Leave(); 473 474 if (SetMicrophoneVolume(newMicLevel) == -1) 475 { 476 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 477 " the required modification of the microphone volume failed"); 478 } 479 } 480 return 0; 481 } 482 483 // ---------------------------------------------------------------------------- 484 // Initialized 485 // ---------------------------------------------------------------------------- 486 487 bool AudioDeviceWindowsWave::Initialized() const 488 { 489 return (_initialized); 490 } 491 492 // ---------------------------------------------------------------------------- 493 // InitSpeaker 494 // ---------------------------------------------------------------------------- 495 496 int32_t AudioDeviceWindowsWave::InitSpeaker() 497 { 498 499 CriticalSectionScoped lock(&_critSect); 500 501 if (_playing) 502 { 503 return -1; 504 } 505 506 if (_mixerManager.EnumerateSpeakers() == -1) 507 { 508 // failed to locate any valid/controllable speaker 509 return -1; 510 } 511 512 if (IsUsingOutputDeviceIndex()) 513 { 514 if (_mixerManager.OpenSpeaker(OutputDeviceIndex()) == -1) 515 { 516 return -1; 517 } 518 } 519 else 520 { 521 if (_mixerManager.OpenSpeaker(OutputDevice()) == -1) 522 { 523 return -1; 524 } 525 } 526 527 return 0; 528 } 529 530 // ---------------------------------------------------------------------------- 531 // InitMicrophone 532 // ---------------------------------------------------------------------------- 533 534 int32_t AudioDeviceWindowsWave::InitMicrophone() 535 { 536 537 CriticalSectionScoped lock(&_critSect); 538 539 if (_recording) 540 { 541 return -1; 542 } 543 544 if (_mixerManager.EnumerateMicrophones() == -1) 545 { 546 // failed to locate any valid/controllable microphone 547 return -1; 548 } 549 550 if (IsUsingInputDeviceIndex()) 551 { 552 if (_mixerManager.OpenMicrophone(InputDeviceIndex()) == -1) 553 { 554 return -1; 555 } 556 } 557 else 558 { 559 if (_mixerManager.OpenMicrophone(InputDevice()) == -1) 560 { 561 return -1; 562 } 563 } 564 565 uint32_t maxVol = 0; 566 if (_mixerManager.MaxMicrophoneVolume(maxVol) == -1) 567 { 568 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 569 " unable to retrieve max microphone volume"); 570 } 571 _maxMicVolume = maxVol; 572 573 uint32_t minVol = 0; 574 if (_mixerManager.MinMicrophoneVolume(minVol) == -1) 575 { 576 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 577 " unable to retrieve min microphone volume"); 578 } 579 _minMicVolume = minVol; 580 581 return 0; 582 } 583 584 // ---------------------------------------------------------------------------- 585 // SpeakerIsInitialized 586 // ---------------------------------------------------------------------------- 587 588 bool AudioDeviceWindowsWave::SpeakerIsInitialized() const 589 { 590 return (_mixerManager.SpeakerIsInitialized()); 591 } 592 593 // ---------------------------------------------------------------------------- 594 // MicrophoneIsInitialized 595 // ---------------------------------------------------------------------------- 596 597 bool AudioDeviceWindowsWave::MicrophoneIsInitialized() const 598 { 599 return (_mixerManager.MicrophoneIsInitialized()); 600 } 601 602 // ---------------------------------------------------------------------------- 603 // SpeakerVolumeIsAvailable 604 // ---------------------------------------------------------------------------- 605 606 int32_t AudioDeviceWindowsWave::SpeakerVolumeIsAvailable(bool& available) 607 { 608 609 bool isAvailable(false); 610 611 // Enumerate all avaliable speakers and make an attempt to open up the 612 // output mixer corresponding to the currently selected output device. 613 // 614 if (InitSpeaker() == -1) 615 { 616 // failed to find a valid speaker 617 available = false; 618 return 0; 619 } 620 621 // Check if the selected speaker has a volume control 622 // 623 _mixerManager.SpeakerVolumeIsAvailable(isAvailable); 624 available = isAvailable; 625 626 // Close the initialized output mixer 627 // 628 _mixerManager.CloseSpeaker(); 629 630 return 0; 631 } 632 633 // ---------------------------------------------------------------------------- 634 // SetSpeakerVolume 635 // ---------------------------------------------------------------------------- 636 637 int32_t AudioDeviceWindowsWave::SetSpeakerVolume(uint32_t volume) 638 { 639 640 return (_mixerManager.SetSpeakerVolume(volume)); 641 } 642 643 // ---------------------------------------------------------------------------- 644 // SpeakerVolume 645 // ---------------------------------------------------------------------------- 646 647 int32_t AudioDeviceWindowsWave::SpeakerVolume(uint32_t& volume) const 648 { 649 650 uint32_t level(0); 651 652 if (_mixerManager.SpeakerVolume(level) == -1) 653 { 654 return -1; 655 } 656 657 volume = level; 658 return 0; 659 } 660 661 // ---------------------------------------------------------------------------- 662 // SetWaveOutVolume 663 // 664 // The low-order word contains the left-channel volume setting, and the 665 // high-order word contains the right-channel setting. 666 // A value of 0xFFFF represents full volume, and a value of 0x0000 is silence. 667 // 668 // If a device does not support both left and right volume control, 669 // the low-order word of dwVolume specifies the volume level, 670 // and the high-order word is ignored. 671 // 672 // Most devices do not support the full 16 bits of volume-level control 673 // and will not use the least-significant bits of the requested volume setting. 674 // For example, if a device supports 4 bits of volume control, the values 675 // 0x4000, 0x4FFF, and 0x43BE will all be truncated to 0x4000. 676 // ---------------------------------------------------------------------------- 677 678 int32_t AudioDeviceWindowsWave::SetWaveOutVolume(uint16_t volumeLeft, uint16_t volumeRight) 679 { 680 681 MMRESULT res(0); 682 WAVEOUTCAPS caps; 683 684 CriticalSectionScoped lock(&_critSect); 685 686 if (_hWaveOut == NULL) 687 { 688 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no open playout device exists => using default"); 689 } 690 691 // To determine whether the device supports volume control on both 692 // the left and right channels, use the WAVECAPS_LRVOLUME flag. 693 // 694 res = waveOutGetDevCaps((UINT_PTR)_hWaveOut, &caps, sizeof(WAVEOUTCAPS)); 695 if (MMSYSERR_NOERROR != res) 696 { 697 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "waveOutGetDevCaps() failed (err=%d)", res); 698 TraceWaveOutError(res); 699 } 700 if (!(caps.dwSupport & WAVECAPS_VOLUME)) 701 { 702 // this device does not support volume control using the waveOutSetVolume API 703 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "device does not support volume control using the Wave API"); 704 return -1; 705 } 706 if (!(caps.dwSupport & WAVECAPS_LRVOLUME)) 707 { 708 // high-order word (right channel) is ignored 709 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "device does not support volume control on both channels"); 710 } 711 712 DWORD dwVolume(0x00000000); 713 dwVolume = (DWORD)(((volumeRight & 0xFFFF) << 16) | (volumeLeft & 0xFFFF)); 714 715 res = waveOutSetVolume(_hWaveOut, dwVolume); 716 if (MMSYSERR_NOERROR != res) 717 { 718 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "waveOutSetVolume() failed (err=%d)", res); 719 TraceWaveOutError(res); 720 return -1; 721 } 722 723 return 0; 724 } 725 726 // ---------------------------------------------------------------------------- 727 // WaveOutVolume 728 // 729 // The low-order word of this location contains the left-channel volume setting, 730 // and the high-order word contains the right-channel setting. 731 // A value of 0xFFFF (65535) represents full volume, and a value of 0x0000 732 // is silence. 733 // 734 // If a device does not support both left and right volume control, 735 // the low-order word of the specified location contains the mono volume level. 736 // 737 // The full 16-bit setting(s) set with the waveOutSetVolume function is returned, 738 // regardless of whether the device supports the full 16 bits of volume-level 739 // control. 740 // ---------------------------------------------------------------------------- 741 742 int32_t AudioDeviceWindowsWave::WaveOutVolume(uint16_t& volumeLeft, uint16_t& volumeRight) const 743 { 744 745 MMRESULT res(0); 746 WAVEOUTCAPS caps; 747 748 CriticalSectionScoped lock(&_critSect); 749 750 if (_hWaveOut == NULL) 751 { 752 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no open playout device exists => using default"); 753 } 754 755 // To determine whether the device supports volume control on both 756 // the left and right channels, use the WAVECAPS_LRVOLUME flag. 757 // 758 res = waveOutGetDevCaps((UINT_PTR)_hWaveOut, &caps, sizeof(WAVEOUTCAPS)); 759 if (MMSYSERR_NOERROR != res) 760 { 761 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "waveOutGetDevCaps() failed (err=%d)", res); 762 TraceWaveOutError(res); 763 } 764 if (!(caps.dwSupport & WAVECAPS_VOLUME)) 765 { 766 // this device does not support volume control using the waveOutSetVolume API 767 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "device does not support volume control using the Wave API"); 768 return -1; 769 } 770 if (!(caps.dwSupport & WAVECAPS_LRVOLUME)) 771 { 772 // high-order word (right channel) is ignored 773 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "device does not support volume control on both channels"); 774 } 775 776 DWORD dwVolume(0x00000000); 777 778 res = waveOutGetVolume(_hWaveOut, &dwVolume); 779 if (MMSYSERR_NOERROR != res) 780 { 781 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "waveOutGetVolume() failed (err=%d)", res); 782 TraceWaveOutError(res); 783 return -1; 784 } 785 786 WORD wVolumeLeft = LOWORD(dwVolume); 787 WORD wVolumeRight = HIWORD(dwVolume); 788 789 volumeLeft = static_cast<uint16_t> (wVolumeLeft); 790 volumeRight = static_cast<uint16_t> (wVolumeRight); 791 792 return 0; 793 } 794 795 // ---------------------------------------------------------------------------- 796 // MaxSpeakerVolume 797 // ---------------------------------------------------------------------------- 798 799 int32_t AudioDeviceWindowsWave::MaxSpeakerVolume(uint32_t& maxVolume) const 800 { 801 802 uint32_t maxVol(0); 803 804 if (_mixerManager.MaxSpeakerVolume(maxVol) == -1) 805 { 806 return -1; 807 } 808 809 maxVolume = maxVol; 810 return 0; 811 } 812 813 // ---------------------------------------------------------------------------- 814 // MinSpeakerVolume 815 // ---------------------------------------------------------------------------- 816 817 int32_t AudioDeviceWindowsWave::MinSpeakerVolume(uint32_t& minVolume) const 818 { 819 820 uint32_t minVol(0); 821 822 if (_mixerManager.MinSpeakerVolume(minVol) == -1) 823 { 824 return -1; 825 } 826 827 minVolume = minVol; 828 return 0; 829 } 830 831 // ---------------------------------------------------------------------------- 832 // SpeakerVolumeStepSize 833 // ---------------------------------------------------------------------------- 834 835 int32_t AudioDeviceWindowsWave::SpeakerVolumeStepSize(uint16_t& stepSize) const 836 { 837 838 uint16_t delta(0); 839 840 if (_mixerManager.SpeakerVolumeStepSize(delta) == -1) 841 { 842 return -1; 843 } 844 845 stepSize = delta; 846 return 0; 847 } 848 849 // ---------------------------------------------------------------------------- 850 // SpeakerMuteIsAvailable 851 // ---------------------------------------------------------------------------- 852 853 int32_t AudioDeviceWindowsWave::SpeakerMuteIsAvailable(bool& available) 854 { 855 856 bool isAvailable(false); 857 858 // Enumerate all avaliable speakers and make an attempt to open up the 859 // output mixer corresponding to the currently selected output device. 860 // 861 if (InitSpeaker() == -1) 862 { 863 // If we end up here it means that the selected speaker has no volume 864 // control, hence it is safe to state that there is no mute control 865 // already at this stage. 866 available = false; 867 return 0; 868 } 869 870 // Check if the selected speaker has a mute control 871 // 872 _mixerManager.SpeakerMuteIsAvailable(isAvailable); 873 available = isAvailable; 874 875 // Close the initialized output mixer 876 // 877 _mixerManager.CloseSpeaker(); 878 879 return 0; 880 } 881 882 // ---------------------------------------------------------------------------- 883 // SetSpeakerMute 884 // ---------------------------------------------------------------------------- 885 886 int32_t AudioDeviceWindowsWave::SetSpeakerMute(bool enable) 887 { 888 return (_mixerManager.SetSpeakerMute(enable)); 889 } 890 891 // ---------------------------------------------------------------------------- 892 // SpeakerMute 893 // ---------------------------------------------------------------------------- 894 895 int32_t AudioDeviceWindowsWave::SpeakerMute(bool& enabled) const 896 { 897 898 bool muted(0); 899 900 if (_mixerManager.SpeakerMute(muted) == -1) 901 { 902 return -1; 903 } 904 905 enabled = muted; 906 return 0; 907 } 908 909 // ---------------------------------------------------------------------------- 910 // MicrophoneMuteIsAvailable 911 // ---------------------------------------------------------------------------- 912 913 int32_t AudioDeviceWindowsWave::MicrophoneMuteIsAvailable(bool& available) 914 { 915 916 bool isAvailable(false); 917 918 // Enumerate all avaliable microphones and make an attempt to open up the 919 // input mixer corresponding to the currently selected input device. 920 // 921 if (InitMicrophone() == -1) 922 { 923 // If we end up here it means that the selected microphone has no volume 924 // control, hence it is safe to state that there is no boost control 925 // already at this stage. 926 available = false; 927 return 0; 928 } 929 930 // Check if the selected microphone has a mute control 931 // 932 _mixerManager.MicrophoneMuteIsAvailable(isAvailable); 933 available = isAvailable; 934 935 // Close the initialized input mixer 936 // 937 _mixerManager.CloseMicrophone(); 938 939 return 0; 940 } 941 942 // ---------------------------------------------------------------------------- 943 // SetMicrophoneMute 944 // ---------------------------------------------------------------------------- 945 946 int32_t AudioDeviceWindowsWave::SetMicrophoneMute(bool enable) 947 { 948 return (_mixerManager.SetMicrophoneMute(enable)); 949 } 950 951 // ---------------------------------------------------------------------------- 952 // MicrophoneMute 953 // ---------------------------------------------------------------------------- 954 955 int32_t AudioDeviceWindowsWave::MicrophoneMute(bool& enabled) const 956 { 957 958 bool muted(0); 959 960 if (_mixerManager.MicrophoneMute(muted) == -1) 961 { 962 return -1; 963 } 964 965 enabled = muted; 966 return 0; 967 } 968 969 // ---------------------------------------------------------------------------- 970 // MicrophoneBoostIsAvailable 971 // ---------------------------------------------------------------------------- 972 973 int32_t AudioDeviceWindowsWave::MicrophoneBoostIsAvailable(bool& available) 974 { 975 976 bool isAvailable(false); 977 978 // Enumerate all avaliable microphones and make an attempt to open up the 979 // input mixer corresponding to the currently selected input device. 980 // 981 if (InitMicrophone() == -1) 982 { 983 // If we end up here it means that the selected microphone has no volume 984 // control, hence it is safe to state that there is no boost control 985 // already at this stage. 986 available = false; 987 return 0; 988 } 989 990 // Check if the selected microphone has a boost control 991 // 992 _mixerManager.MicrophoneBoostIsAvailable(isAvailable); 993 available = isAvailable; 994 995 // Close the initialized input mixer 996 // 997 _mixerManager.CloseMicrophone(); 998 999 return 0; 1000 } 1001 1002 // ---------------------------------------------------------------------------- 1003 // SetMicrophoneBoost 1004 // ---------------------------------------------------------------------------- 1005 1006 int32_t AudioDeviceWindowsWave::SetMicrophoneBoost(bool enable) 1007 { 1008 1009 return (_mixerManager.SetMicrophoneBoost(enable)); 1010 } 1011 1012 // ---------------------------------------------------------------------------- 1013 // MicrophoneBoost 1014 // ---------------------------------------------------------------------------- 1015 1016 int32_t AudioDeviceWindowsWave::MicrophoneBoost(bool& enabled) const 1017 { 1018 1019 bool onOff(0); 1020 1021 if (_mixerManager.MicrophoneBoost(onOff) == -1) 1022 { 1023 return -1; 1024 } 1025 1026 enabled = onOff; 1027 return 0; 1028 } 1029 1030 // ---------------------------------------------------------------------------- 1031 // StereoRecordingIsAvailable 1032 // ---------------------------------------------------------------------------- 1033 1034 int32_t AudioDeviceWindowsWave::StereoRecordingIsAvailable(bool& available) 1035 { 1036 available = true; 1037 return 0; 1038 } 1039 1040 // ---------------------------------------------------------------------------- 1041 // SetStereoRecording 1042 // ---------------------------------------------------------------------------- 1043 1044 int32_t AudioDeviceWindowsWave::SetStereoRecording(bool enable) 1045 { 1046 1047 if (enable) 1048 _recChannels = 2; 1049 else 1050 _recChannels = 1; 1051 1052 return 0; 1053 } 1054 1055 // ---------------------------------------------------------------------------- 1056 // StereoRecording 1057 // ---------------------------------------------------------------------------- 1058 1059 int32_t AudioDeviceWindowsWave::StereoRecording(bool& enabled) const 1060 { 1061 1062 if (_recChannels == 2) 1063 enabled = true; 1064 else 1065 enabled = false; 1066 1067 return 0; 1068 } 1069 1070 // ---------------------------------------------------------------------------- 1071 // StereoPlayoutIsAvailable 1072 // ---------------------------------------------------------------------------- 1073 1074 int32_t AudioDeviceWindowsWave::StereoPlayoutIsAvailable(bool& available) 1075 { 1076 available = true; 1077 return 0; 1078 } 1079 1080 // ---------------------------------------------------------------------------- 1081 // SetStereoPlayout 1082 // 1083 // Specifies the number of output channels. 1084 // 1085 // NOTE - the setting will only have an effect after InitPlayout has 1086 // been called. 1087 // 1088 // 16-bit mono: 1089 // 1090 // Each sample is 2 bytes. Sample 1 is followed by samples 2, 3, 4, and so on. 1091 // For each sample, the first byte is the low-order byte of channel 0 and the 1092 // second byte is the high-order byte of channel 0. 1093 // 1094 // 16-bit stereo: 1095 // 1096 // Each sample is 4 bytes. Sample 1 is followed by samples 2, 3, 4, and so on. 1097 // For each sample, the first byte is the low-order byte of channel 0 (left channel); 1098 // the second byte is the high-order byte of channel 0; the third byte is the 1099 // low-order byte of channel 1 (right channel); and the fourth byte is the 1100 // high-order byte of channel 1. 1101 // ---------------------------------------------------------------------------- 1102 1103 int32_t AudioDeviceWindowsWave::SetStereoPlayout(bool enable) 1104 { 1105 1106 if (enable) 1107 _playChannels = 2; 1108 else 1109 _playChannels = 1; 1110 1111 return 0; 1112 } 1113 1114 // ---------------------------------------------------------------------------- 1115 // StereoPlayout 1116 // ---------------------------------------------------------------------------- 1117 1118 int32_t AudioDeviceWindowsWave::StereoPlayout(bool& enabled) const 1119 { 1120 1121 if (_playChannels == 2) 1122 enabled = true; 1123 else 1124 enabled = false; 1125 1126 return 0; 1127 } 1128 1129 // ---------------------------------------------------------------------------- 1130 // SetAGC 1131 // ---------------------------------------------------------------------------- 1132 1133 int32_t AudioDeviceWindowsWave::SetAGC(bool enable) 1134 { 1135 1136 _AGC = enable; 1137 1138 return 0; 1139 } 1140 1141 // ---------------------------------------------------------------------------- 1142 // AGC 1143 // ---------------------------------------------------------------------------- 1144 1145 bool AudioDeviceWindowsWave::AGC() const 1146 { 1147 return _AGC; 1148 } 1149 1150 // ---------------------------------------------------------------------------- 1151 // MicrophoneVolumeIsAvailable 1152 // ---------------------------------------------------------------------------- 1153 1154 int32_t AudioDeviceWindowsWave::MicrophoneVolumeIsAvailable(bool& available) 1155 { 1156 1157 bool isAvailable(false); 1158 1159 // Enumerate all avaliable microphones and make an attempt to open up the 1160 // input mixer corresponding to the currently selected output device. 1161 // 1162 if (InitMicrophone() == -1) 1163 { 1164 // Failed to find valid microphone 1165 available = false; 1166 return 0; 1167 } 1168 1169 // Check if the selected microphone has a volume control 1170 // 1171 _mixerManager.MicrophoneVolumeIsAvailable(isAvailable); 1172 available = isAvailable; 1173 1174 // Close the initialized input mixer 1175 // 1176 _mixerManager.CloseMicrophone(); 1177 1178 return 0; 1179 } 1180 1181 // ---------------------------------------------------------------------------- 1182 // SetMicrophoneVolume 1183 // ---------------------------------------------------------------------------- 1184 1185 int32_t AudioDeviceWindowsWave::SetMicrophoneVolume(uint32_t volume) 1186 { 1187 return (_mixerManager.SetMicrophoneVolume(volume)); 1188 } 1189 1190 // ---------------------------------------------------------------------------- 1191 // MicrophoneVolume 1192 // ---------------------------------------------------------------------------- 1193 1194 int32_t AudioDeviceWindowsWave::MicrophoneVolume(uint32_t& volume) const 1195 { 1196 uint32_t level(0); 1197 1198 if (_mixerManager.MicrophoneVolume(level) == -1) 1199 { 1200 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "failed to retrive current microphone level"); 1201 return -1; 1202 } 1203 1204 volume = level; 1205 return 0; 1206 } 1207 1208 // ---------------------------------------------------------------------------- 1209 // MaxMicrophoneVolume 1210 // ---------------------------------------------------------------------------- 1211 1212 int32_t AudioDeviceWindowsWave::MaxMicrophoneVolume(uint32_t& maxVolume) const 1213 { 1214 // _maxMicVolume can be zero in AudioMixerManager::MaxMicrophoneVolume(): 1215 // (1) API GetLineControl() returns failure at querying the max Mic level. 1216 // (2) API GetLineControl() returns maxVolume as zero in rare cases. 1217 // Both cases show we don't have access to the mixer controls. 1218 // We return -1 here to indicate that. 1219 if (_maxMicVolume == 0) 1220 { 1221 return -1; 1222 } 1223 1224 maxVolume = _maxMicVolume;; 1225 return 0; 1226 } 1227 1228 // ---------------------------------------------------------------------------- 1229 // MinMicrophoneVolume 1230 // ---------------------------------------------------------------------------- 1231 1232 int32_t AudioDeviceWindowsWave::MinMicrophoneVolume(uint32_t& minVolume) const 1233 { 1234 minVolume = _minMicVolume; 1235 return 0; 1236 } 1237 1238 // ---------------------------------------------------------------------------- 1239 // MicrophoneVolumeStepSize 1240 // ---------------------------------------------------------------------------- 1241 1242 int32_t AudioDeviceWindowsWave::MicrophoneVolumeStepSize(uint16_t& stepSize) const 1243 { 1244 1245 uint16_t delta(0); 1246 1247 if (_mixerManager.MicrophoneVolumeStepSize(delta) == -1) 1248 { 1249 return -1; 1250 } 1251 1252 stepSize = delta; 1253 return 0; 1254 } 1255 1256 // ---------------------------------------------------------------------------- 1257 // PlayoutDevices 1258 // ---------------------------------------------------------------------------- 1259 1260 int16_t AudioDeviceWindowsWave::PlayoutDevices() 1261 { 1262 1263 return (waveOutGetNumDevs()); 1264 } 1265 1266 // ---------------------------------------------------------------------------- 1267 // SetPlayoutDevice I (II) 1268 // ---------------------------------------------------------------------------- 1269 1270 int32_t AudioDeviceWindowsWave::SetPlayoutDevice(uint16_t index) 1271 { 1272 1273 if (_playIsInitialized) 1274 { 1275 return -1; 1276 } 1277 1278 UINT nDevices = waveOutGetNumDevs(); 1279 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "number of availiable waveform-audio output devices is %u", nDevices); 1280 1281 if (index < 0 || index > (nDevices-1)) 1282 { 1283 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "device index is out of range [0,%u]", (nDevices-1)); 1284 return -1; 1285 } 1286 1287 _usingOutputDeviceIndex = true; 1288 _outputDeviceIndex = index; 1289 _outputDeviceIsSpecified = true; 1290 1291 return 0; 1292 } 1293 1294 // ---------------------------------------------------------------------------- 1295 // SetPlayoutDevice II (II) 1296 // ---------------------------------------------------------------------------- 1297 1298 int32_t AudioDeviceWindowsWave::SetPlayoutDevice(AudioDeviceModule::WindowsDeviceType device) 1299 { 1300 if (_playIsInitialized) 1301 { 1302 return -1; 1303 } 1304 1305 if (device == AudioDeviceModule::kDefaultDevice) 1306 { 1307 } 1308 else if (device == AudioDeviceModule::kDefaultCommunicationDevice) 1309 { 1310 } 1311 1312 _usingOutputDeviceIndex = false; 1313 _outputDevice = device; 1314 _outputDeviceIsSpecified = true; 1315 1316 return 0; 1317 } 1318 1319 // ---------------------------------------------------------------------------- 1320 // PlayoutDeviceName 1321 // ---------------------------------------------------------------------------- 1322 1323 int32_t AudioDeviceWindowsWave::PlayoutDeviceName( 1324 uint16_t index, 1325 char name[kAdmMaxDeviceNameSize], 1326 char guid[kAdmMaxGuidSize]) 1327 { 1328 1329 uint16_t nDevices(PlayoutDevices()); 1330 1331 // Special fix for the case when the user asks for the name of the default device. 1332 // 1333 if (index == (uint16_t)(-1)) 1334 { 1335 index = 0; 1336 } 1337 1338 if ((index > (nDevices-1)) || (name == NULL)) 1339 { 1340 return -1; 1341 } 1342 1343 memset(name, 0, kAdmMaxDeviceNameSize); 1344 1345 if (guid != NULL) 1346 { 1347 memset(guid, 0, kAdmMaxGuidSize); 1348 } 1349 1350 WAVEOUTCAPSW caps; // szPname member (product name (NULL terminated) is a WCHAR 1351 MMRESULT res; 1352 1353 res = waveOutGetDevCapsW(index, &caps, sizeof(WAVEOUTCAPSW)); 1354 if (res != MMSYSERR_NOERROR) 1355 { 1356 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "waveOutGetDevCapsW() failed (err=%d)", res); 1357 return -1; 1358 } 1359 if (WideCharToMultiByte(CP_UTF8, 0, caps.szPname, -1, name, kAdmMaxDeviceNameSize, NULL, NULL) == 0) 1360 { 1361 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "WideCharToMultiByte(CP_UTF8) failed with error code %d - 1", GetLastError()); 1362 } 1363 1364 if (guid == NULL) 1365 { 1366 return 0; 1367 } 1368 1369 // It is possible to get the unique endpoint ID string using the Wave API. 1370 // However, it is only supported on Windows Vista and Windows 7. 1371 1372 size_t cbEndpointId(0); 1373 1374 // Get the size (including the terminating null) of the endpoint ID string of the waveOut device. 1375 // Windows Vista supports the DRV_QUERYFUNCTIONINSTANCEIDSIZE and DRV_QUERYFUNCTIONINSTANCEID messages. 1376 res = waveOutMessage((HWAVEOUT)IntToPtr(index), 1377 DRV_QUERYFUNCTIONINSTANCEIDSIZE, 1378 (DWORD_PTR)&cbEndpointId, NULL); 1379 if (res != MMSYSERR_NOERROR) 1380 { 1381 // DRV_QUERYFUNCTIONINSTANCEIDSIZE is not supported <=> earlier version of Windows than Vista 1382 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "waveOutMessage(DRV_QUERYFUNCTIONINSTANCEIDSIZE) failed (err=%d)", res); 1383 TraceWaveOutError(res); 1384 // Best we can do is to copy the friendly name and use it as guid 1385 if (WideCharToMultiByte(CP_UTF8, 0, caps.szPname, -1, guid, kAdmMaxGuidSize, NULL, NULL) == 0) 1386 { 1387 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "WideCharToMultiByte(CP_UTF8) failed with error code %d - 2", GetLastError()); 1388 } 1389 return 0; 1390 } 1391 1392 // waveOutMessage(DRV_QUERYFUNCTIONINSTANCEIDSIZE) worked => we are on a Vista or Windows 7 device 1393 1394 WCHAR *pstrEndpointId = NULL; 1395 pstrEndpointId = (WCHAR*)CoTaskMemAlloc(cbEndpointId); 1396 1397 // Get the endpoint ID string for this waveOut device. 1398 res = waveOutMessage((HWAVEOUT)IntToPtr(index), 1399 DRV_QUERYFUNCTIONINSTANCEID, 1400 (DWORD_PTR)pstrEndpointId, 1401 cbEndpointId); 1402 if (res != MMSYSERR_NOERROR) 1403 { 1404 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "waveOutMessage(DRV_QUERYFUNCTIONINSTANCEID) failed (err=%d)", res); 1405 TraceWaveOutError(res); 1406 // Best we can do is to copy the friendly name and use it as guid 1407 if (WideCharToMultiByte(CP_UTF8, 0, caps.szPname, -1, guid, kAdmMaxGuidSize, NULL, NULL) == 0) 1408 { 1409 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "WideCharToMultiByte(CP_UTF8) failed with error code %d - 3", GetLastError()); 1410 } 1411 CoTaskMemFree(pstrEndpointId); 1412 return 0; 1413 } 1414 1415 if (WideCharToMultiByte(CP_UTF8, 0, pstrEndpointId, -1, guid, kAdmMaxGuidSize, NULL, NULL) == 0) 1416 { 1417 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "WideCharToMultiByte(CP_UTF8) failed with error code %d - 4", GetLastError()); 1418 } 1419 CoTaskMemFree(pstrEndpointId); 1420 1421 return 0; 1422 } 1423 1424 // ---------------------------------------------------------------------------- 1425 // RecordingDeviceName 1426 // ---------------------------------------------------------------------------- 1427 1428 int32_t AudioDeviceWindowsWave::RecordingDeviceName( 1429 uint16_t index, 1430 char name[kAdmMaxDeviceNameSize], 1431 char guid[kAdmMaxGuidSize]) 1432 { 1433 1434 uint16_t nDevices(RecordingDevices()); 1435 1436 // Special fix for the case when the user asks for the name of the default device. 1437 // 1438 if (index == (uint16_t)(-1)) 1439 { 1440 index = 0; 1441 } 1442 1443 if ((index > (nDevices-1)) || (name == NULL)) 1444 { 1445 return -1; 1446 } 1447 1448 memset(name, 0, kAdmMaxDeviceNameSize); 1449 1450 if (guid != NULL) 1451 { 1452 memset(guid, 0, kAdmMaxGuidSize); 1453 } 1454 1455 WAVEINCAPSW caps; // szPname member (product name (NULL terminated) is a WCHAR 1456 MMRESULT res; 1457 1458 res = waveInGetDevCapsW(index, &caps, sizeof(WAVEINCAPSW)); 1459 if (res != MMSYSERR_NOERROR) 1460 { 1461 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "waveInGetDevCapsW() failed (err=%d)", res); 1462 return -1; 1463 } 1464 if (WideCharToMultiByte(CP_UTF8, 0, caps.szPname, -1, name, kAdmMaxDeviceNameSize, NULL, NULL) == 0) 1465 { 1466 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "WideCharToMultiByte(CP_UTF8) failed with error code %d - 1", GetLastError()); 1467 } 1468 1469 if (guid == NULL) 1470 { 1471 return 0; 1472 } 1473 1474 // It is possible to get the unique endpoint ID string using the Wave API. 1475 // However, it is only supported on Windows Vista and Windows 7. 1476 1477 size_t cbEndpointId(0); 1478 1479 // Get the size (including the terminating null) of the endpoint ID string of the waveOut device. 1480 // Windows Vista supports the DRV_QUERYFUNCTIONINSTANCEIDSIZE and DRV_QUERYFUNCTIONINSTANCEID messages. 1481 res = waveInMessage((HWAVEIN)IntToPtr(index), 1482 DRV_QUERYFUNCTIONINSTANCEIDSIZE, 1483 (DWORD_PTR)&cbEndpointId, NULL); 1484 if (res != MMSYSERR_NOERROR) 1485 { 1486 // DRV_QUERYFUNCTIONINSTANCEIDSIZE is not supported <=> earlier version of Windows than Vista 1487 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "waveInMessage(DRV_QUERYFUNCTIONINSTANCEIDSIZE) failed (err=%d)", res); 1488 TraceWaveInError(res); 1489 // Best we can do is to copy the friendly name and use it as guid 1490 if (WideCharToMultiByte(CP_UTF8, 0, caps.szPname, -1, guid, kAdmMaxGuidSize, NULL, NULL) == 0) 1491 { 1492 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "WideCharToMultiByte(CP_UTF8) failed with error code %d - 2", GetLastError()); 1493 } 1494 return 0; 1495 } 1496 1497 // waveOutMessage(DRV_QUERYFUNCTIONINSTANCEIDSIZE) worked => we are on a Vista or Windows 7 device 1498 1499 WCHAR *pstrEndpointId = NULL; 1500 pstrEndpointId = (WCHAR*)CoTaskMemAlloc(cbEndpointId); 1501 1502 // Get the endpoint ID string for this waveOut device. 1503 res = waveInMessage((HWAVEIN)IntToPtr(index), 1504 DRV_QUERYFUNCTIONINSTANCEID, 1505 (DWORD_PTR)pstrEndpointId, 1506 cbEndpointId); 1507 if (res != MMSYSERR_NOERROR) 1508 { 1509 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "waveInMessage(DRV_QUERYFUNCTIONINSTANCEID) failed (err=%d)", res); 1510 TraceWaveInError(res); 1511 // Best we can do is to copy the friendly name and use it as guid 1512 if (WideCharToMultiByte(CP_UTF8, 0, caps.szPname, -1, guid, kAdmMaxGuidSize, NULL, NULL) == 0) 1513 { 1514 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "WideCharToMultiByte(CP_UTF8) failed with error code %d - 3", GetLastError()); 1515 } 1516 CoTaskMemFree(pstrEndpointId); 1517 return 0; 1518 } 1519 1520 if (WideCharToMultiByte(CP_UTF8, 0, pstrEndpointId, -1, guid, kAdmMaxGuidSize, NULL, NULL) == 0) 1521 { 1522 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "WideCharToMultiByte(CP_UTF8) failed with error code %d - 4", GetLastError()); 1523 } 1524 CoTaskMemFree(pstrEndpointId); 1525 1526 return 0; 1527 } 1528 1529 // ---------------------------------------------------------------------------- 1530 // RecordingDevices 1531 // ---------------------------------------------------------------------------- 1532 1533 int16_t AudioDeviceWindowsWave::RecordingDevices() 1534 { 1535 1536 return (waveInGetNumDevs()); 1537 } 1538 1539 // ---------------------------------------------------------------------------- 1540 // SetRecordingDevice I (II) 1541 // ---------------------------------------------------------------------------- 1542 1543 int32_t AudioDeviceWindowsWave::SetRecordingDevice(uint16_t index) 1544 { 1545 1546 if (_recIsInitialized) 1547 { 1548 return -1; 1549 } 1550 1551 UINT nDevices = waveInGetNumDevs(); 1552 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "number of availiable waveform-audio input devices is %u", nDevices); 1553 1554 if (index < 0 || index > (nDevices-1)) 1555 { 1556 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "device index is out of range [0,%u]", (nDevices-1)); 1557 return -1; 1558 } 1559 1560 _usingInputDeviceIndex = true; 1561 _inputDeviceIndex = index; 1562 _inputDeviceIsSpecified = true; 1563 1564 return 0; 1565 } 1566 1567 // ---------------------------------------------------------------------------- 1568 // SetRecordingDevice II (II) 1569 // ---------------------------------------------------------------------------- 1570 1571 int32_t AudioDeviceWindowsWave::SetRecordingDevice(AudioDeviceModule::WindowsDeviceType device) 1572 { 1573 if (device == AudioDeviceModule::kDefaultDevice) 1574 { 1575 } 1576 else if (device == AudioDeviceModule::kDefaultCommunicationDevice) 1577 { 1578 } 1579 1580 if (_recIsInitialized) 1581 { 1582 return -1; 1583 } 1584 1585 _usingInputDeviceIndex = false; 1586 _inputDevice = device; 1587 _inputDeviceIsSpecified = true; 1588 1589 return 0; 1590 } 1591 1592 // ---------------------------------------------------------------------------- 1593 // PlayoutIsAvailable 1594 // ---------------------------------------------------------------------------- 1595 1596 int32_t AudioDeviceWindowsWave::PlayoutIsAvailable(bool& available) 1597 { 1598 1599 available = false; 1600 1601 // Try to initialize the playout side 1602 int32_t res = InitPlayout(); 1603 1604 // Cancel effect of initialization 1605 StopPlayout(); 1606 1607 if (res != -1) 1608 { 1609 available = true; 1610 } 1611 1612 return 0; 1613 } 1614 1615 // ---------------------------------------------------------------------------- 1616 // RecordingIsAvailable 1617 // ---------------------------------------------------------------------------- 1618 1619 int32_t AudioDeviceWindowsWave::RecordingIsAvailable(bool& available) 1620 { 1621 1622 available = false; 1623 1624 // Try to initialize the recording side 1625 int32_t res = InitRecording(); 1626 1627 // Cancel effect of initialization 1628 StopRecording(); 1629 1630 if (res != -1) 1631 { 1632 available = true; 1633 } 1634 1635 return 0; 1636 } 1637 1638 // ---------------------------------------------------------------------------- 1639 // InitPlayout 1640 // ---------------------------------------------------------------------------- 1641 1642 int32_t AudioDeviceWindowsWave::InitPlayout() 1643 { 1644 1645 CriticalSectionScoped lock(&_critSect); 1646 1647 if (_playing) 1648 { 1649 return -1; 1650 } 1651 1652 if (!_outputDeviceIsSpecified) 1653 { 1654 return -1; 1655 } 1656 1657 if (_playIsInitialized) 1658 { 1659 return 0; 1660 } 1661 1662 // Initialize the speaker (devices might have been added or removed) 1663 if (InitSpeaker() == -1) 1664 { 1665 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "InitSpeaker() failed"); 1666 } 1667 1668 // Enumerate all availiable output devices 1669 EnumeratePlayoutDevices(); 1670 1671 // Start by closing any existing wave-output devices 1672 // 1673 MMRESULT res(MMSYSERR_ERROR); 1674 1675 if (_hWaveOut != NULL) 1676 { 1677 res = waveOutClose(_hWaveOut); 1678 if (MMSYSERR_NOERROR != res) 1679 { 1680 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "waveOutClose() failed (err=%d)", res); 1681 TraceWaveOutError(res); 1682 } 1683 } 1684 1685 // Set the output wave format 1686 // 1687 WAVEFORMATEX waveFormat; 1688 1689 waveFormat.wFormatTag = WAVE_FORMAT_PCM; 1690 waveFormat.nChannels = _playChannels; // mono <=> 1, stereo <=> 2 1691 waveFormat.nSamplesPerSec = N_PLAY_SAMPLES_PER_SEC; 1692 waveFormat.wBitsPerSample = 16; 1693 waveFormat.nBlockAlign = waveFormat.nChannels * (waveFormat.wBitsPerSample/8); 1694 waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign; 1695 waveFormat.cbSize = 0; 1696 1697 // Open the given waveform-audio output device for playout 1698 // 1699 HWAVEOUT hWaveOut(NULL); 1700 1701 if (IsUsingOutputDeviceIndex()) 1702 { 1703 // verify settings first 1704 res = waveOutOpen(NULL, _outputDeviceIndex, &waveFormat, 0, 0, CALLBACK_NULL | WAVE_FORMAT_QUERY); 1705 if (MMSYSERR_NOERROR == res) 1706 { 1707 // open the given waveform-audio output device for recording 1708 res = waveOutOpen(&hWaveOut, _outputDeviceIndex, &waveFormat, 0, 0, CALLBACK_NULL); 1709 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "opening output device corresponding to device ID %u", _outputDeviceIndex); 1710 } 1711 } 1712 else 1713 { 1714 if (_outputDevice == AudioDeviceModule::kDefaultCommunicationDevice) 1715 { 1716 // check if it is possible to open the default communication device (supported on Windows 7) 1717 res = waveOutOpen(NULL, WAVE_MAPPER, &waveFormat, 0, 0, CALLBACK_NULL | WAVE_MAPPED_DEFAULT_COMMUNICATION_DEVICE | WAVE_FORMAT_QUERY); 1718 if (MMSYSERR_NOERROR == res) 1719 { 1720 // if so, open the default communication device for real 1721 res = waveOutOpen(&hWaveOut, WAVE_MAPPER, &waveFormat, 0, 0, CALLBACK_NULL | WAVE_MAPPED_DEFAULT_COMMUNICATION_DEVICE); 1722 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "opening default communication device"); 1723 } 1724 else 1725 { 1726 // use default device since default communication device was not avaliable 1727 res = waveOutOpen(&hWaveOut, WAVE_MAPPER, &waveFormat, 0, 0, CALLBACK_NULL); 1728 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "unable to open default communication device => using default instead"); 1729 } 1730 } 1731 else if (_outputDevice == AudioDeviceModule::kDefaultDevice) 1732 { 1733 // open default device since it has been requested 1734 res = waveOutOpen(NULL, WAVE_MAPPER, &waveFormat, 0, 0, CALLBACK_NULL | WAVE_FORMAT_QUERY); 1735 if (MMSYSERR_NOERROR == res) 1736 { 1737 res = waveOutOpen(&hWaveOut, WAVE_MAPPER, &waveFormat, 0, 0, CALLBACK_NULL); 1738 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "opening default output device"); 1739 } 1740 } 1741 } 1742 1743 if (MMSYSERR_NOERROR != res) 1744 { 1745 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "waveOutOpen() failed (err=%d)", res); 1746 TraceWaveOutError(res); 1747 return -1; 1748 } 1749 1750 // Log information about the aquired output device 1751 // 1752 WAVEOUTCAPS caps; 1753 1754 res = waveOutGetDevCaps((UINT_PTR)hWaveOut, &caps, sizeof(WAVEOUTCAPS)); 1755 if (res != MMSYSERR_NOERROR) 1756 { 1757 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "waveOutGetDevCaps() failed (err=%d)", res); 1758 TraceWaveOutError(res); 1759 } 1760 1761 UINT deviceID(0); 1762 res = waveOutGetID(hWaveOut, &deviceID); 1763 if (res != MMSYSERR_NOERROR) 1764 { 1765 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "waveOutGetID() failed (err=%d)", res); 1766 TraceWaveOutError(res); 1767 } 1768 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "utilized device ID : %u", deviceID); 1769 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "product name : %s", caps.szPname); 1770 1771 // Store valid handle for the open waveform-audio output device 1772 _hWaveOut = hWaveOut; 1773 1774 // Store the input wave header as well 1775 _waveFormatOut = waveFormat; 1776 1777 // Prepare wave-out headers 1778 // 1779 const uint8_t bytesPerSample = 2*_playChannels; 1780 1781 for (int n = 0; n < N_BUFFERS_OUT; n++) 1782 { 1783 // set up the output wave header 1784 _waveHeaderOut[n].lpData = reinterpret_cast<LPSTR>(&_playBuffer[n]); 1785 _waveHeaderOut[n].dwBufferLength = bytesPerSample*PLAY_BUF_SIZE_IN_SAMPLES; 1786 _waveHeaderOut[n].dwFlags = 0; 1787 _waveHeaderOut[n].dwLoops = 0; 1788 1789 memset(_playBuffer[n], 0, bytesPerSample*PLAY_BUF_SIZE_IN_SAMPLES); 1790 1791 // The waveOutPrepareHeader function prepares a waveform-audio data block for playback. 1792 // The lpData, dwBufferLength, and dwFlags members of the WAVEHDR structure must be set 1793 // before calling this function. 1794 // 1795 res = waveOutPrepareHeader(_hWaveOut, &_waveHeaderOut[n], sizeof(WAVEHDR)); 1796 if (MMSYSERR_NOERROR != res) 1797 { 1798 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "waveOutPrepareHeader(%d) failed (err=%d)", n, res); 1799 TraceWaveOutError(res); 1800 } 1801 1802 // perform extra check to ensure that the header is prepared 1803 if (_waveHeaderOut[n].dwFlags != WHDR_PREPARED) 1804 { 1805 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "waveOutPrepareHeader(%d) failed (dwFlags != WHDR_PREPARED)", n); 1806 } 1807 } 1808 1809 // Mark playout side as initialized 1810 _playIsInitialized = true; 1811 1812 _dTcheckPlayBufDelay = 10; // check playback buffer delay every 10 ms 1813 _playBufCount = 0; // index of active output wave header (<=> output buffer index) 1814 _playBufDelay = 80; // buffer delay/size is initialized to 80 ms and slowly decreased until er < 25 1815 _minPlayBufDelay = 25; // minimum playout buffer delay 1816 _MAX_minBuffer = 65; // adaptive minimum playout buffer delay cannot be larger than this value 1817 _intro = 1; // Used to make sure that adaption starts after (2000-1700)/100 seconds 1818 _waitCounter = 1700; // Counter for start of adaption of playback buffer 1819 _erZeroCounter = 0; // Log how many times er = 0 in consequtive calls to RecTimeProc 1820 _useHeader = 0; // Counts number of "useHeader" detections. Stops at 2. 1821 1822 _writtenSamples = 0; 1823 _writtenSamplesOld = 0; 1824 _playedSamplesOld = 0; 1825 _sndCardPlayDelay = 0; 1826 _sndCardRecDelay = 0; 1827 1828 WEBRTC_TRACE(kTraceInfo, kTraceUtility, _id,"initial playout status: _playBufDelay=%d, _minPlayBufDelay=%d", 1829 _playBufDelay, _minPlayBufDelay); 1830 1831 return 0; 1832 } 1833 1834 // ---------------------------------------------------------------------------- 1835 // InitRecording 1836 // ---------------------------------------------------------------------------- 1837 1838 int32_t AudioDeviceWindowsWave::InitRecording() 1839 { 1840 1841 CriticalSectionScoped lock(&_critSect); 1842 1843 if (_recording) 1844 { 1845 return -1; 1846 } 1847 1848 if (!_inputDeviceIsSpecified) 1849 { 1850 return -1; 1851 } 1852 1853 if (_recIsInitialized) 1854 { 1855 return 0; 1856 } 1857 1858 _avgCPULoad = 0; 1859 _playAcc = 0; 1860 1861 // Initialize the microphone (devices might have been added or removed) 1862 if (InitMicrophone() == -1) 1863 { 1864 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "InitMicrophone() failed"); 1865 } 1866 1867 // Enumerate all availiable input devices 1868 EnumerateRecordingDevices(); 1869 1870 // Start by closing any existing wave-input devices 1871 // 1872 MMRESULT res(MMSYSERR_ERROR); 1873 1874 if (_hWaveIn != NULL) 1875 { 1876 res = waveInClose(_hWaveIn); 1877 if (MMSYSERR_NOERROR != res) 1878 { 1879 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "waveInClose() failed (err=%d)", res); 1880 TraceWaveInError(res); 1881 } 1882 } 1883 1884 // Set the input wave format 1885 // 1886 WAVEFORMATEX waveFormat; 1887 1888 waveFormat.wFormatTag = WAVE_FORMAT_PCM; 1889 waveFormat.nChannels = _recChannels; // mono <=> 1, stereo <=> 2 1890 waveFormat.nSamplesPerSec = N_REC_SAMPLES_PER_SEC; 1891 waveFormat.wBitsPerSample = 16; 1892 waveFormat.nBlockAlign = waveFormat.nChannels * (waveFormat.wBitsPerSample/8); 1893 waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign; 1894 waveFormat.cbSize = 0; 1895 1896 // Open the given waveform-audio input device for recording 1897 // 1898 HWAVEIN hWaveIn(NULL); 1899 1900 if (IsUsingInputDeviceIndex()) 1901 { 1902 // verify settings first 1903 res = waveInOpen(NULL, _inputDeviceIndex, &waveFormat, 0, 0, CALLBACK_NULL | WAVE_FORMAT_QUERY); 1904 if (MMSYSERR_NOERROR == res) 1905 { 1906 // open the given waveform-audio input device for recording 1907 res = waveInOpen(&hWaveIn, _inputDeviceIndex, &waveFormat, 0, 0, CALLBACK_NULL); 1908 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "opening input device corresponding to device ID %u", _inputDeviceIndex); 1909 } 1910 } 1911 else 1912 { 1913 if (_inputDevice == AudioDeviceModule::kDefaultCommunicationDevice) 1914 { 1915 // check if it is possible to open the default communication device (supported on Windows 7) 1916 res = waveInOpen(NULL, WAVE_MAPPER, &waveFormat, 0, 0, CALLBACK_NULL | WAVE_MAPPED_DEFAULT_COMMUNICATION_DEVICE | WAVE_FORMAT_QUERY); 1917 if (MMSYSERR_NOERROR == res) 1918 { 1919 // if so, open the default communication device for real 1920 res = waveInOpen(&hWaveIn, WAVE_MAPPER, &waveFormat, 0, 0, CALLBACK_NULL | WAVE_MAPPED_DEFAULT_COMMUNICATION_DEVICE); 1921 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "opening default communication device"); 1922 } 1923 else 1924 { 1925 // use default device since default communication device was not avaliable 1926 res = waveInOpen(&hWaveIn, WAVE_MAPPER, &waveFormat, 0, 0, CALLBACK_NULL); 1927 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "unable to open default communication device => using default instead"); 1928 } 1929 } 1930 else if (_inputDevice == AudioDeviceModule::kDefaultDevice) 1931 { 1932 // open default device since it has been requested 1933 res = waveInOpen(NULL, WAVE_MAPPER, &waveFormat, 0, 0, CALLBACK_NULL | WAVE_FORMAT_QUERY); 1934 if (MMSYSERR_NOERROR == res) 1935 { 1936 res = waveInOpen(&hWaveIn, WAVE_MAPPER, &waveFormat, 0, 0, CALLBACK_NULL); 1937 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "opening default input device"); 1938 } 1939 } 1940 } 1941 1942 if (MMSYSERR_NOERROR != res) 1943 { 1944 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "waveInOpen() failed (err=%d)", res); 1945 TraceWaveInError(res); 1946 return -1; 1947 } 1948 1949 // Log information about the aquired input device 1950 // 1951 WAVEINCAPS caps; 1952 1953 res = waveInGetDevCaps((UINT_PTR)hWaveIn, &caps, sizeof(WAVEINCAPS)); 1954 if (res != MMSYSERR_NOERROR) 1955 { 1956 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "waveInGetDevCaps() failed (err=%d)", res); 1957 TraceWaveInError(res); 1958 } 1959 1960 UINT deviceID(0); 1961 res = waveInGetID(hWaveIn, &deviceID); 1962 if (res != MMSYSERR_NOERROR) 1963 { 1964 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "waveInGetID() failed (err=%d)", res); 1965 TraceWaveInError(res); 1966 } 1967 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "utilized device ID : %u", deviceID); 1968 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "product name : %s", caps.szPname); 1969 1970 // Store valid handle for the open waveform-audio input device 1971 _hWaveIn = hWaveIn; 1972 1973 // Store the input wave header as well 1974 _waveFormatIn = waveFormat; 1975 1976 // Mark recording side as initialized 1977 _recIsInitialized = true; 1978 1979 _recBufCount = 0; // index of active input wave header (<=> input buffer index) 1980 _recDelayCount = 0; // ensures that input buffers are returned with certain delay 1981 1982 return 0; 1983 } 1984 1985 // ---------------------------------------------------------------------------- 1986 // StartRecording 1987 // ---------------------------------------------------------------------------- 1988 1989 int32_t AudioDeviceWindowsWave::StartRecording() 1990 { 1991 1992 if (!_recIsInitialized) 1993 { 1994 return -1; 1995 } 1996 1997 if (_recording) 1998 { 1999 return 0; 2000 } 2001 2002 // set state to ensure that the recording starts from the audio thread 2003 _startRec = true; 2004 2005 // the audio thread will signal when recording has stopped 2006 if (kEventTimeout == _recStartEvent.Wait(10000)) 2007 { 2008 _startRec = false; 2009 StopRecording(); 2010 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "failed to activate recording"); 2011 return -1; 2012 } 2013 2014 if (_recording) 2015 { 2016 // the recording state is set by the audio thread after recording has started 2017 } 2018 else 2019 { 2020 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "failed to activate recording"); 2021 return -1; 2022 } 2023 2024 return 0; 2025 } 2026 2027 // ---------------------------------------------------------------------------- 2028 // StopRecording 2029 // ---------------------------------------------------------------------------- 2030 2031 int32_t AudioDeviceWindowsWave::StopRecording() 2032 { 2033 2034 CriticalSectionScoped lock(&_critSect); 2035 2036 if (!_recIsInitialized) 2037 { 2038 return 0; 2039 } 2040 2041 if (_hWaveIn == NULL) 2042 { 2043 return -1; 2044 } 2045 2046 bool wasRecording = _recording; 2047 _recIsInitialized = false; 2048 _recording = false; 2049 2050 MMRESULT res; 2051 2052 // Stop waveform-adio input. If there are any buffers in the queue, the 2053 // current buffer will be marked as done (the dwBytesRecorded member in 2054 // the header will contain the length of data), but any empty buffers in 2055 // the queue will remain there. 2056 // 2057 res = waveInStop(_hWaveIn); 2058 if (MMSYSERR_NOERROR != res) 2059 { 2060 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "waveInStop() failed (err=%d)", res); 2061 TraceWaveInError(res); 2062 } 2063 2064 // Stop input on the given waveform-audio input device and resets the current 2065 // position to zero. All pending buffers are marked as done and returned to 2066 // the application. 2067 // 2068 res = waveInReset(_hWaveIn); 2069 if (MMSYSERR_NOERROR != res) 2070 { 2071 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "waveInReset() failed (err=%d)", res); 2072 TraceWaveInError(res); 2073 } 2074 2075 // Clean up the preparation performed by the waveInPrepareHeader function. 2076 // Only unprepare header if recording was ever started (and headers are prepared). 2077 // 2078 if (wasRecording) 2079 { 2080 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "waveInUnprepareHeader() will be performed"); 2081 for (int n = 0; n < N_BUFFERS_IN; n++) 2082 { 2083 res = waveInUnprepareHeader(_hWaveIn, &_waveHeaderIn[n], sizeof(WAVEHDR)); 2084 if (MMSYSERR_NOERROR != res) 2085 { 2086 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "waveInUnprepareHeader() failed (err=%d)", res); 2087 TraceWaveInError(res); 2088 } 2089 } 2090 } 2091 2092 // Close the given waveform-audio input device. 2093 // 2094 res = waveInClose(_hWaveIn); 2095 if (MMSYSERR_NOERROR != res) 2096 { 2097 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "waveInClose() failed (err=%d)", res); 2098 TraceWaveInError(res); 2099 } 2100 2101 // Set the wave input handle to NULL 2102 // 2103 _hWaveIn = NULL; 2104 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "_hWaveIn is now set to NULL"); 2105 2106 return 0; 2107 } 2108 2109 // ---------------------------------------------------------------------------- 2110 // RecordingIsInitialized 2111 // ---------------------------------------------------------------------------- 2112 2113 bool AudioDeviceWindowsWave::RecordingIsInitialized() const 2114 { 2115 return (_recIsInitialized); 2116 } 2117 2118 // ---------------------------------------------------------------------------- 2119 // Recording 2120 // ---------------------------------------------------------------------------- 2121 2122 bool AudioDeviceWindowsWave::Recording() const 2123 { 2124 return (_recording); 2125 } 2126 2127 // ---------------------------------------------------------------------------- 2128 // PlayoutIsInitialized 2129 // ---------------------------------------------------------------------------- 2130 2131 bool AudioDeviceWindowsWave::PlayoutIsInitialized() const 2132 { 2133 return (_playIsInitialized); 2134 } 2135 2136 // ---------------------------------------------------------------------------- 2137 // StartPlayout 2138 // ---------------------------------------------------------------------------- 2139 2140 int32_t AudioDeviceWindowsWave::StartPlayout() 2141 { 2142 2143 if (!_playIsInitialized) 2144 { 2145 return -1; 2146 } 2147 2148 if (_playing) 2149 { 2150 return 0; 2151 } 2152 2153 // set state to ensure that playout starts from the audio thread 2154 _startPlay = true; 2155 2156 // the audio thread will signal when recording has started 2157 if (kEventTimeout == _playStartEvent.Wait(10000)) 2158 { 2159 _startPlay = false; 2160 StopPlayout(); 2161 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "failed to activate playout"); 2162 return -1; 2163 } 2164 2165 if (_playing) 2166 { 2167 // the playing state is set by the audio thread after playout has started 2168 } 2169 else 2170 { 2171 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "failed to activate playing"); 2172 return -1; 2173 } 2174 2175 return 0; 2176 } 2177 2178 // ---------------------------------------------------------------------------- 2179 // StopPlayout 2180 // ---------------------------------------------------------------------------- 2181 2182 int32_t AudioDeviceWindowsWave::StopPlayout() 2183 { 2184 2185 CriticalSectionScoped lock(&_critSect); 2186 2187 if (!_playIsInitialized) 2188 { 2189 return 0; 2190 } 2191 2192 if (_hWaveOut == NULL) 2193 { 2194 return -1; 2195 } 2196 2197 _playIsInitialized = false; 2198 _playing = false; 2199 _sndCardPlayDelay = 0; 2200 _sndCardRecDelay = 0; 2201 2202 MMRESULT res; 2203 2204 // The waveOutReset function stops playback on the given waveform-audio 2205 // output device and resets the current position to zero. All pending 2206 // playback buffers are marked as done (WHDR_DONE) and returned to the application. 2207 // After this function returns, the application can send new playback buffers 2208 // to the device by calling waveOutWrite, or close the device by calling waveOutClose. 2209 // 2210 res = waveOutReset(_hWaveOut); 2211 if (MMSYSERR_NOERROR != res) 2212 { 2213 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "waveOutReset() failed (err=%d)", res); 2214 TraceWaveOutError(res); 2215 } 2216 2217 // The waveOutUnprepareHeader function cleans up the preparation performed 2218 // by the waveOutPrepareHeader function. This function must be called after 2219 // the device driver is finished with a data block. 2220 // You must call this function before freeing the buffer. 2221 // 2222 for (int n = 0; n < N_BUFFERS_OUT; n++) 2223 { 2224 res = waveOutUnprepareHeader(_hWaveOut, &_waveHeaderOut[n], sizeof(WAVEHDR)); 2225 if (MMSYSERR_NOERROR != res) 2226 { 2227 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "waveOutUnprepareHeader() failed (err=%d)", res); 2228 TraceWaveOutError(res); 2229 } 2230 } 2231 2232 // The waveOutClose function closes the given waveform-audio output device. 2233 // The close operation fails if the device is still playing a waveform-audio 2234 // buffer that was previously sent by calling waveOutWrite. Before calling 2235 // waveOutClose, the application must wait for all buffers to finish playing 2236 // or call the waveOutReset function to terminate playback. 2237 // 2238 res = waveOutClose(_hWaveOut); 2239 if (MMSYSERR_NOERROR != res) 2240 { 2241 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "waveOutClose() failed (err=%d)", res); 2242 TraceWaveOutError(res); 2243 } 2244 2245 _hWaveOut = NULL; 2246 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "_hWaveOut is now set to NULL"); 2247 2248 return 0; 2249 } 2250 2251 // ---------------------------------------------------------------------------- 2252 // PlayoutDelay 2253 // ---------------------------------------------------------------------------- 2254 2255 int32_t AudioDeviceWindowsWave::PlayoutDelay(uint16_t& delayMS) const 2256 { 2257 CriticalSectionScoped lock(&_critSect); 2258 delayMS = (uint16_t)_sndCardPlayDelay; 2259 return 0; 2260 } 2261 2262 // ---------------------------------------------------------------------------- 2263 // RecordingDelay 2264 // ---------------------------------------------------------------------------- 2265 2266 int32_t AudioDeviceWindowsWave::RecordingDelay(uint16_t& delayMS) const 2267 { 2268 CriticalSectionScoped lock(&_critSect); 2269 delayMS = (uint16_t)_sndCardRecDelay; 2270 return 0; 2271 } 2272 2273 // ---------------------------------------------------------------------------- 2274 // Playing 2275 // ---------------------------------------------------------------------------- 2276 2277 bool AudioDeviceWindowsWave::Playing() const 2278 { 2279 return (_playing); 2280 } 2281 // ---------------------------------------------------------------------------- 2282 // SetPlayoutBuffer 2283 // ---------------------------------------------------------------------------- 2284 2285 int32_t AudioDeviceWindowsWave::SetPlayoutBuffer(const AudioDeviceModule::BufferType type, uint16_t sizeMS) 2286 { 2287 CriticalSectionScoped lock(&_critSect); 2288 _playBufType = type; 2289 if (type == AudioDeviceModule::kFixedBufferSize) 2290 { 2291 _playBufDelayFixed = sizeMS; 2292 } 2293 return 0; 2294 } 2295 2296 // ---------------------------------------------------------------------------- 2297 // PlayoutBuffer 2298 // ---------------------------------------------------------------------------- 2299 2300 int32_t AudioDeviceWindowsWave::PlayoutBuffer(AudioDeviceModule::BufferType& type, uint16_t& sizeMS) const 2301 { 2302 CriticalSectionScoped lock(&_critSect); 2303 type = _playBufType; 2304 if (type == AudioDeviceModule::kFixedBufferSize) 2305 { 2306 sizeMS = _playBufDelayFixed; 2307 } 2308 else 2309 { 2310 sizeMS = _playBufDelay; 2311 } 2312 2313 return 0; 2314 } 2315 2316 // ---------------------------------------------------------------------------- 2317 // CPULoad 2318 // ---------------------------------------------------------------------------- 2319 2320 int32_t AudioDeviceWindowsWave::CPULoad(uint16_t& load) const 2321 { 2322 2323 load = static_cast<uint16_t>(100*_avgCPULoad); 2324 2325 return 0; 2326 } 2327 2328 // ---------------------------------------------------------------------------- 2329 // PlayoutWarning 2330 // ---------------------------------------------------------------------------- 2331 2332 bool AudioDeviceWindowsWave::PlayoutWarning() const 2333 { 2334 return ( _playWarning > 0); 2335 } 2336 2337 // ---------------------------------------------------------------------------- 2338 // PlayoutError 2339 // ---------------------------------------------------------------------------- 2340 2341 bool AudioDeviceWindowsWave::PlayoutError() const 2342 { 2343 return ( _playError > 0); 2344 } 2345 2346 // ---------------------------------------------------------------------------- 2347 // RecordingWarning 2348 // ---------------------------------------------------------------------------- 2349 2350 bool AudioDeviceWindowsWave::RecordingWarning() const 2351 { 2352 return ( _recWarning > 0); 2353 } 2354 2355 // ---------------------------------------------------------------------------- 2356 // RecordingError 2357 // ---------------------------------------------------------------------------- 2358 2359 bool AudioDeviceWindowsWave::RecordingError() const 2360 { 2361 return ( _recError > 0); 2362 } 2363 2364 // ---------------------------------------------------------------------------- 2365 // ClearPlayoutWarning 2366 // ---------------------------------------------------------------------------- 2367 2368 void AudioDeviceWindowsWave::ClearPlayoutWarning() 2369 { 2370 _playWarning = 0; 2371 } 2372 2373 // ---------------------------------------------------------------------------- 2374 // ClearPlayoutError 2375 // ---------------------------------------------------------------------------- 2376 2377 void AudioDeviceWindowsWave::ClearPlayoutError() 2378 { 2379 _playError = 0; 2380 } 2381 2382 // ---------------------------------------------------------------------------- 2383 // ClearRecordingWarning 2384 // ---------------------------------------------------------------------------- 2385 2386 void AudioDeviceWindowsWave::ClearRecordingWarning() 2387 { 2388 _recWarning = 0; 2389 } 2390 2391 // ---------------------------------------------------------------------------- 2392 // ClearRecordingError 2393 // ---------------------------------------------------------------------------- 2394 2395 void AudioDeviceWindowsWave::ClearRecordingError() 2396 { 2397 _recError = 0; 2398 } 2399 2400 // ============================================================================ 2401 // Private Methods 2402 // ============================================================================ 2403 2404 // ---------------------------------------------------------------------------- 2405 // InputSanityCheckAfterUnlockedPeriod 2406 // ---------------------------------------------------------------------------- 2407 2408 int32_t AudioDeviceWindowsWave::InputSanityCheckAfterUnlockedPeriod() const 2409 { 2410 if (_hWaveIn == NULL) 2411 { 2412 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "input state has been modified during unlocked period"); 2413 return -1; 2414 } 2415 return 0; 2416 } 2417 2418 // ---------------------------------------------------------------------------- 2419 // OutputSanityCheckAfterUnlockedPeriod 2420 // ---------------------------------------------------------------------------- 2421 2422 int32_t AudioDeviceWindowsWave::OutputSanityCheckAfterUnlockedPeriod() const 2423 { 2424 if (_hWaveOut == NULL) 2425 { 2426 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "output state has been modified during unlocked period"); 2427 return -1; 2428 } 2429 return 0; 2430 } 2431 2432 // ---------------------------------------------------------------------------- 2433 // EnumeratePlayoutDevices 2434 // ---------------------------------------------------------------------------- 2435 2436 int32_t AudioDeviceWindowsWave::EnumeratePlayoutDevices() 2437 { 2438 2439 uint16_t nDevices(PlayoutDevices()); 2440 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "==============================================================="); 2441 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "#output devices: %u", nDevices); 2442 2443 WAVEOUTCAPS caps; 2444 MMRESULT res; 2445 2446 for (UINT deviceID = 0; deviceID < nDevices; deviceID++) 2447 { 2448 res = waveOutGetDevCaps(deviceID, &caps, sizeof(WAVEOUTCAPS)); 2449 if (res != MMSYSERR_NOERROR) 2450 { 2451 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "waveOutGetDevCaps() failed (err=%d)", res); 2452 } 2453 2454 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "==============================================================="); 2455 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "Device ID %u:", deviceID); 2456 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "manufacturer ID : %u", caps.wMid); 2457 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "product ID : %u",caps.wPid); 2458 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "version of driver : %u.%u", HIBYTE(caps.vDriverVersion), LOBYTE(caps.vDriverVersion)); 2459 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "product name : %s", caps.szPname); 2460 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "dwFormats : 0x%x", caps.dwFormats); 2461 if (caps.dwFormats & WAVE_FORMAT_48S16) 2462 { 2463 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, " 48kHz,stereo,16bit : SUPPORTED"); 2464 } 2465 else 2466 { 2467 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, " 48kHz,stereo,16bit : *NOT* SUPPORTED"); 2468 } 2469 if (caps.dwFormats & WAVE_FORMAT_48M16) 2470 { 2471 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, " 48kHz,mono,16bit : SUPPORTED"); 2472 } 2473 else 2474 { 2475 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, " 48kHz,mono,16bit : *NOT* SUPPORTED"); 2476 } 2477 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "wChannels : %u", caps.wChannels); 2478 TraceSupportFlags(caps.dwSupport); 2479 } 2480 2481 return 0; 2482 } 2483 2484 // ---------------------------------------------------------------------------- 2485 // EnumerateRecordingDevices 2486 // ---------------------------------------------------------------------------- 2487 2488 int32_t AudioDeviceWindowsWave::EnumerateRecordingDevices() 2489 { 2490 2491 uint16_t nDevices(RecordingDevices()); 2492 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "==============================================================="); 2493 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "#input devices: %u", nDevices); 2494 2495 WAVEINCAPS caps; 2496 MMRESULT res; 2497 2498 for (UINT deviceID = 0; deviceID < nDevices; deviceID++) 2499 { 2500 res = waveInGetDevCaps(deviceID, &caps, sizeof(WAVEINCAPS)); 2501 if (res != MMSYSERR_NOERROR) 2502 { 2503 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "waveInGetDevCaps() failed (err=%d)", res); 2504 } 2505 2506 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "==============================================================="); 2507 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "Device ID %u:", deviceID); 2508 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "manufacturer ID : %u", caps.wMid); 2509 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "product ID : %u",caps.wPid); 2510 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "version of driver : %u.%u", HIBYTE(caps.vDriverVersion), LOBYTE(caps.vDriverVersion)); 2511 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "product name : %s", caps.szPname); 2512 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "dwFormats : 0x%x", caps.dwFormats); 2513 if (caps.dwFormats & WAVE_FORMAT_48S16) 2514 { 2515 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, " 48kHz,stereo,16bit : SUPPORTED"); 2516 } 2517 else 2518 { 2519 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, " 48kHz,stereo,16bit : *NOT* SUPPORTED"); 2520 } 2521 if (caps.dwFormats & WAVE_FORMAT_48M16) 2522 { 2523 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, " 48kHz,mono,16bit : SUPPORTED"); 2524 } 2525 else 2526 { 2527 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, " 48kHz,mono,16bit : *NOT* SUPPORTED"); 2528 } 2529 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "wChannels : %u", caps.wChannels); 2530 } 2531 2532 return 0; 2533 } 2534 2535 // ---------------------------------------------------------------------------- 2536 // TraceSupportFlags 2537 // ---------------------------------------------------------------------------- 2538 2539 void AudioDeviceWindowsWave::TraceSupportFlags(DWORD dwSupport) const 2540 { 2541 TCHAR buf[256]; 2542 2543 StringCchPrintf(buf, 128, TEXT("support flags : 0x%x "), dwSupport); 2544 2545 if (dwSupport & WAVECAPS_PITCH) 2546 { 2547 // supports pitch control 2548 StringCchCat(buf, 256, TEXT("(PITCH)")); 2549 } 2550 if (dwSupport & WAVECAPS_PLAYBACKRATE) 2551 { 2552 // supports playback rate control 2553 StringCchCat(buf, 256, TEXT("(PLAYBACKRATE)")); 2554 } 2555 if (dwSupport & WAVECAPS_VOLUME) 2556 { 2557 // supports volume control 2558 StringCchCat(buf, 256, TEXT("(VOLUME)")); 2559 } 2560 if (dwSupport & WAVECAPS_LRVOLUME) 2561 { 2562 // supports separate left and right volume control 2563 StringCchCat(buf, 256, TEXT("(LRVOLUME)")); 2564 } 2565 if (dwSupport & WAVECAPS_SYNC) 2566 { 2567 // the driver is synchronous and will block while playing a buffer 2568 StringCchCat(buf, 256, TEXT("(SYNC)")); 2569 } 2570 if (dwSupport & WAVECAPS_SAMPLEACCURATE) 2571 { 2572 // returns sample-accurate position information 2573 StringCchCat(buf, 256, TEXT("(SAMPLEACCURATE)")); 2574 } 2575 2576 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%S", buf); 2577 } 2578 2579 // ---------------------------------------------------------------------------- 2580 // TraceWaveInError 2581 // ---------------------------------------------------------------------------- 2582 2583 void AudioDeviceWindowsWave::TraceWaveInError(MMRESULT error) const 2584 { 2585 TCHAR buf[MAXERRORLENGTH]; 2586 TCHAR msg[MAXERRORLENGTH]; 2587 2588 StringCchPrintf(buf, MAXERRORLENGTH, TEXT("Error details: ")); 2589 waveInGetErrorText(error, msg, MAXERRORLENGTH); 2590 StringCchCat(buf, MAXERRORLENGTH, msg); 2591 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%S", buf); 2592 } 2593 2594 // ---------------------------------------------------------------------------- 2595 // TraceWaveOutError 2596 // ---------------------------------------------------------------------------- 2597 2598 void AudioDeviceWindowsWave::TraceWaveOutError(MMRESULT error) const 2599 { 2600 TCHAR buf[MAXERRORLENGTH]; 2601 TCHAR msg[MAXERRORLENGTH]; 2602 2603 StringCchPrintf(buf, MAXERRORLENGTH, TEXT("Error details: ")); 2604 waveOutGetErrorText(error, msg, MAXERRORLENGTH); 2605 StringCchCat(buf, MAXERRORLENGTH, msg); 2606 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%S", buf); 2607 } 2608 2609 // ---------------------------------------------------------------------------- 2610 // PrepareStartPlayout 2611 // ---------------------------------------------------------------------------- 2612 2613 int32_t AudioDeviceWindowsWave::PrepareStartPlayout() 2614 { 2615 2616 CriticalSectionScoped lock(&_critSect); 2617 2618 if (_hWaveOut == NULL) 2619 { 2620 return -1; 2621 } 2622 2623 // A total of 30ms of data is immediately placed in the SC buffer 2624 // 2625 int8_t zeroVec[4*PLAY_BUF_SIZE_IN_SAMPLES]; // max allocation 2626 memset(zeroVec, 0, 4*PLAY_BUF_SIZE_IN_SAMPLES); 2627 2628 { 2629 Write(zeroVec, PLAY_BUF_SIZE_IN_SAMPLES); 2630 Write(zeroVec, PLAY_BUF_SIZE_IN_SAMPLES); 2631 Write(zeroVec, PLAY_BUF_SIZE_IN_SAMPLES); 2632 } 2633 2634 _playAcc = 0; 2635 _playWarning = 0; 2636 _playError = 0; 2637 _dc_diff_mean = 0; 2638 _dc_y_prev = 0; 2639 _dc_penalty_counter = 20; 2640 _dc_prevtime = 0; 2641 _dc_prevplay = 0; 2642 2643 return 0; 2644 } 2645 2646 // ---------------------------------------------------------------------------- 2647 // PrepareStartRecording 2648 // ---------------------------------------------------------------------------- 2649 2650 int32_t AudioDeviceWindowsWave::PrepareStartRecording() 2651 { 2652 2653 CriticalSectionScoped lock(&_critSect); 2654 2655 if (_hWaveIn == NULL) 2656 { 2657 return -1; 2658 } 2659 2660 _playAcc = 0; 2661 _recordedBytes = 0; 2662 _recPutBackDelay = REC_PUT_BACK_DELAY; 2663 2664 MMRESULT res; 2665 MMTIME mmtime; 2666 mmtime.wType = TIME_SAMPLES; 2667 2668 res = waveInGetPosition(_hWaveIn, &mmtime, sizeof(mmtime)); 2669 if (MMSYSERR_NOERROR != res) 2670 { 2671 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "waveInGetPosition(TIME_SAMPLES) failed (err=%d)", res); 2672 TraceWaveInError(res); 2673 } 2674 2675 _read_samples = mmtime.u.sample; 2676 _read_samples_old = _read_samples; 2677 _rec_samples_old = mmtime.u.sample; 2678 _wrapCounter = 0; 2679 2680 for (int n = 0; n < N_BUFFERS_IN; n++) 2681 { 2682 const uint8_t nBytesPerSample = 2*_recChannels; 2683 2684 // set up the input wave header 2685 _waveHeaderIn[n].lpData = reinterpret_cast<LPSTR>(&_recBuffer[n]); 2686 _waveHeaderIn[n].dwBufferLength = nBytesPerSample * REC_BUF_SIZE_IN_SAMPLES; 2687 _waveHeaderIn[n].dwFlags = 0; 2688 _waveHeaderIn[n].dwBytesRecorded = 0; 2689 _waveHeaderIn[n].dwUser = 0; 2690 2691 memset(_recBuffer[n], 0, nBytesPerSample * REC_BUF_SIZE_IN_SAMPLES); 2692 2693 // prepare a buffer for waveform-audio input 2694 res = waveInPrepareHeader(_hWaveIn, &_waveHeaderIn[n], sizeof(WAVEHDR)); 2695 if (MMSYSERR_NOERROR != res) 2696 { 2697 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "waveInPrepareHeader(%d) failed (err=%d)", n, res); 2698 TraceWaveInError(res); 2699 } 2700 2701 // send an input buffer to the given waveform-audio input device 2702 res = waveInAddBuffer(_hWaveIn, &_waveHeaderIn[n], sizeof(WAVEHDR)); 2703 if (MMSYSERR_NOERROR != res) 2704 { 2705 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "waveInAddBuffer(%d) failed (err=%d)", n, res); 2706 TraceWaveInError(res); 2707 } 2708 } 2709 2710 // start input on the given waveform-audio input device 2711 res = waveInStart(_hWaveIn); 2712 if (MMSYSERR_NOERROR != res) 2713 { 2714 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "waveInStart() failed (err=%d)", res); 2715 TraceWaveInError(res); 2716 } 2717 2718 return 0; 2719 } 2720 2721 // ---------------------------------------------------------------------------- 2722 // GetPlayoutBufferDelay 2723 // ---------------------------------------------------------------------------- 2724 2725 int32_t AudioDeviceWindowsWave::GetPlayoutBufferDelay(uint32_t& writtenSamples, uint32_t& playedSamples) 2726 { 2727 int i; 2728 int ms_Header; 2729 long playedDifference; 2730 int msecInPlayoutBuffer(0); // #milliseconds of audio in the playout buffer 2731 2732 const uint16_t nSamplesPerMs = (uint16_t)(N_PLAY_SAMPLES_PER_SEC/1000); // default is 48000/1000 = 48 2733 2734 MMRESULT res; 2735 MMTIME mmtime; 2736 2737 if (!_playing) 2738 { 2739 playedSamples = 0; 2740 return (0); 2741 } 2742 2743 // Retrieve the current playback position. 2744 // 2745 mmtime.wType = TIME_SAMPLES; // number of waveform-audio samples 2746 res = waveOutGetPosition(_hWaveOut, &mmtime, sizeof(mmtime)); 2747 if (MMSYSERR_NOERROR != res) 2748 { 2749 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "waveOutGetPosition() failed (err=%d)", res); 2750 TraceWaveOutError(res); 2751 } 2752 2753 writtenSamples = _writtenSamples; // #samples written to the playout buffer 2754 playedSamples = mmtime.u.sample; // current playout position in the playout buffer 2755 2756 // derive remaining amount (in ms) of data in the playout buffer 2757 msecInPlayoutBuffer = ((writtenSamples - playedSamples)/nSamplesPerMs); 2758 2759 playedDifference = (long) (_playedSamplesOld - playedSamples); 2760 2761 if (playedDifference > 64000) 2762 { 2763 // If the sound cards number-of-played-out-samples variable wraps around before 2764 // written_sampels wraps around this needs to be adjusted. This can happen on 2765 // sound cards that uses less than 32 bits to keep track of number of played out 2766 // sampels. To avoid being fooled by sound cards that sometimes produces false 2767 // output we compare old value minus the new value with a large value. This is 2768 // neccessary because some SC:s produce an output like 153, 198, 175, 230 which 2769 // would trigger the wrap-around function if we didn't compare with a large value. 2770 // The value 64000 is chosen because 2^16=65536 so we allow wrap around at 16 bits. 2771 2772 i = 31; 2773 while((_playedSamplesOld <= (unsigned long)POW2(i)) && (i > 14)) { 2774 i--; 2775 } 2776 2777 if((i < 31) && (i > 14)) { 2778 // Avoid adjusting when there is 32-bit wrap-around since that is 2779 // something neccessary. 2780 // 2781 WEBRTC_TRACE(kTraceDebug, kTraceUtility, _id, "msecleft() => wrap around occured: %d bits used by sound card)", (i+1)); 2782 2783 _writtenSamples = _writtenSamples - POW2(i + 1); 2784 writtenSamples = _writtenSamples; 2785 msecInPlayoutBuffer = ((writtenSamples - playedSamples)/nSamplesPerMs); 2786 } 2787 } 2788 else if ((_writtenSamplesOld > POW2(31)) && (writtenSamples < 96000)) 2789 { 2790 // Wrap around as expected after having used all 32 bits. (But we still 2791 // test if the wrap around happened earlier which it should not) 2792 2793 i = 31; 2794 while (_writtenSamplesOld <= (unsigned long)POW2(i)) { 2795 i--; 2796 } 2797 2798 WEBRTC_TRACE(kTraceDebug, kTraceUtility, _id, " msecleft() (wrap around occured after having used all 32 bits)"); 2799 2800 _writtenSamplesOld = writtenSamples; 2801 _playedSamplesOld = playedSamples; 2802 msecInPlayoutBuffer = (int)((writtenSamples + POW2(i + 1) - playedSamples)/nSamplesPerMs); 2803 2804 } 2805 else if ((writtenSamples < 96000) && (playedSamples > POW2(31))) 2806 { 2807 // Wrap around has, as expected, happened for written_sampels before 2808 // playedSampels so we have to adjust for this until also playedSampels 2809 // has had wrap around. 2810 2811 WEBRTC_TRACE(kTraceDebug, kTraceUtility, _id, " msecleft() (wrap around occured: correction of output is done)"); 2812 2813 _writtenSamplesOld = writtenSamples; 2814 _playedSamplesOld = playedSamples; 2815 msecInPlayoutBuffer = (int)((writtenSamples + POW2(32) - playedSamples)/nSamplesPerMs); 2816 } 2817 2818 _writtenSamplesOld = writtenSamples; 2819 _playedSamplesOld = playedSamples; 2820 2821 2822 // We use the following formaula to track that playout works as it should 2823 // y=playedSamples/48 - timeGetTime(); 2824 // y represent the clock drift between system clock and sound card clock - should be fairly stable 2825 // When the exponential mean value of diff(y) goes away from zero something is wrong 2826 // The exponential formula will accept 1% clock drift but not more 2827 // The driver error means that we will play to little audio and have a high negative clock drift 2828 // We kick in our alternative method when the clock drift reaches 20% 2829 2830 int diff,y; 2831 int unsigned time =0; 2832 2833 // If we have other problems that causes playout glitches 2834 // we don't want to switch playout method. 2835 // Check if playout buffer is extremely low, or if we haven't been able to 2836 // exectue our code in more than 40 ms 2837 2838 time = timeGetTime(); 2839 2840 if ((msecInPlayoutBuffer < 20) || (time - _dc_prevtime > 40)) 2841 { 2842 _dc_penalty_counter = 100; 2843 } 2844 2845 if ((playedSamples != 0)) 2846 { 2847 y = playedSamples/48 - time; 2848 if ((_dc_y_prev != 0) && (_dc_penalty_counter == 0)) 2849 { 2850 diff = y - _dc_y_prev; 2851 _dc_diff_mean = (990*_dc_diff_mean)/1000 + 10*diff; 2852 } 2853 _dc_y_prev = y; 2854 } 2855 2856 if (_dc_penalty_counter) 2857 { 2858 _dc_penalty_counter--; 2859 } 2860 2861 if (_dc_diff_mean < -200) 2862 { 2863 // Always reset the filter 2864 _dc_diff_mean = 0; 2865 2866 // Problem is detected. Switch delay method and set min buffer to 80. 2867 // Reset the filter and keep monitoring the filter output. 2868 // If issue is detected a second time, increase min buffer to 100. 2869 // If that does not help, we must modify this scheme further. 2870 2871 _useHeader++; 2872 if (_useHeader == 1) 2873 { 2874 _minPlayBufDelay = 80; 2875 _playWarning = 1; // only warn first time 2876 WEBRTC_TRACE(kTraceInfo, kTraceUtility, -1, "Modification #1: _useHeader = %d, _minPlayBufDelay = %d", _useHeader, _minPlayBufDelay); 2877 } 2878 else if (_useHeader == 2) 2879 { 2880 _minPlayBufDelay = 100; // add some more safety 2881 WEBRTC_TRACE(kTraceInfo, kTraceUtility, -1, "Modification #2: _useHeader = %d, _minPlayBufDelay = %d", _useHeader, _minPlayBufDelay); 2882 } 2883 else 2884 { 2885 // This state should not be entered... (HA) 2886 WEBRTC_TRACE (kTraceWarning, kTraceUtility, -1, "further actions are required!"); 2887 } 2888 if (_playWarning == 1) 2889 { 2890 WEBRTC_TRACE(kTraceWarning, kTraceUtility, _id, "pending playout warning exists"); 2891 } 2892 _playWarning = 1; // triggers callback from module process thread 2893 WEBRTC_TRACE(kTraceWarning, kTraceUtility, _id, "kPlayoutWarning message posted: switching to alternative playout delay method"); 2894 } 2895 _dc_prevtime = time; 2896 _dc_prevplay = playedSamples; 2897 2898 // Try a very rough method of looking at how many buffers are still playing 2899 ms_Header = 0; 2900 for (i = 0; i < N_BUFFERS_OUT; i++) { 2901 if ((_waveHeaderOut[i].dwFlags & WHDR_INQUEUE)!=0) { 2902 ms_Header += 10; 2903 } 2904 } 2905 2906 if ((ms_Header-50) > msecInPlayoutBuffer) { 2907 // Test for cases when GetPosition appears to be screwed up (currently just log....) 2908 TCHAR infoStr[300]; 2909 if (_no_of_msecleft_warnings%20==0) 2910 { 2911 StringCchPrintf(infoStr, 300, TEXT("writtenSamples=%i, playedSamples=%i, msecInPlayoutBuffer=%i, ms_Header=%i"), writtenSamples, playedSamples, msecInPlayoutBuffer, ms_Header); 2912 WEBRTC_TRACE(kTraceWarning, kTraceUtility, _id, "%S", infoStr); 2913 } 2914 _no_of_msecleft_warnings++; 2915 } 2916 2917 // If this is true we have had a problem with the playout 2918 if (_useHeader > 0) 2919 { 2920 return (ms_Header); 2921 } 2922 2923 2924 if (ms_Header < msecInPlayoutBuffer) 2925 { 2926 if (_no_of_msecleft_warnings % 100 == 0) 2927 { 2928 TCHAR str[300]; 2929 StringCchPrintf(str, 300, TEXT("_no_of_msecleft_warnings=%i, msecInPlayoutBuffer=%i ms_Header=%i (minBuffer=%i buffersize=%i writtenSamples=%i playedSamples=%i)"), 2930 _no_of_msecleft_warnings, msecInPlayoutBuffer, ms_Header, _minPlayBufDelay, _playBufDelay, writtenSamples, playedSamples); 2931 WEBRTC_TRACE(kTraceWarning, kTraceUtility, _id, "%S", str); 2932 } 2933 _no_of_msecleft_warnings++; 2934 ms_Header -= 6; // Round off as we only have 10ms resolution + Header info is usually slightly delayed compared to GetPosition 2935 2936 if (ms_Header < 0) 2937 ms_Header = 0; 2938 2939 return (ms_Header); 2940 } 2941 else 2942 { 2943 return (msecInPlayoutBuffer); 2944 } 2945 } 2946 2947 // ---------------------------------------------------------------------------- 2948 // GetRecordingBufferDelay 2949 // ---------------------------------------------------------------------------- 2950 2951 int32_t AudioDeviceWindowsWave::GetRecordingBufferDelay(uint32_t& readSamples, uint32_t& recSamples) 2952 { 2953 long recDifference; 2954 MMTIME mmtime; 2955 MMRESULT mmr; 2956 2957 const uint16_t nSamplesPerMs = (uint16_t)(N_REC_SAMPLES_PER_SEC/1000); // default is 48000/1000 = 48 2958 2959 // Retrieve the current input position of the given waveform-audio input device 2960 // 2961 mmtime.wType = TIME_SAMPLES; 2962 mmr = waveInGetPosition(_hWaveIn, &mmtime, sizeof(mmtime)); 2963 if (MMSYSERR_NOERROR != mmr) 2964 { 2965 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "waveInGetPosition() failed (err=%d)", mmr); 2966 TraceWaveInError(mmr); 2967 } 2968 2969 readSamples = _read_samples; // updated for each full fram in RecProc() 2970 recSamples = mmtime.u.sample; // remaining time in input queue (recorded but not read yet) 2971 2972 recDifference = (long) (_rec_samples_old - recSamples); 2973 2974 if( recDifference > 64000) { 2975 WEBRTC_TRACE (kTraceDebug, kTraceUtility, -1,"WRAP 1 (recDifference =%d)", recDifference); 2976 // If the sound cards number-of-recorded-samples variable wraps around before 2977 // read_sampels wraps around this needs to be adjusted. This can happen on 2978 // sound cards that uses less than 32 bits to keep track of number of played out 2979 // sampels. To avoid being fooled by sound cards that sometimes produces false 2980 // output we compare old value minus the new value with a large value. This is 2981 // neccessary because some SC:s produce an output like 153, 198, 175, 230 which 2982 // would trigger the wrap-around function if we didn't compare with a large value. 2983 // The value 64000 is chosen because 2^16=65536 so we allow wrap around at 16 bits. 2984 // 2985 int i = 31; 2986 while((_rec_samples_old <= (unsigned long)POW2(i)) && (i > 14)) 2987 i--; 2988 2989 if((i < 31) && (i > 14)) { 2990 // Avoid adjusting when there is 32-bit wrap-around since that is 2991 // somethying neccessary. 2992 // 2993 _read_samples = _read_samples - POW2(i + 1); 2994 readSamples = _read_samples; 2995 _wrapCounter++; 2996 } else { 2997 WEBRTC_TRACE (kTraceWarning, kTraceUtility, -1,"AEC (_rec_samples_old %d recSamples %d)",_rec_samples_old, recSamples); 2998 } 2999 } 3000 3001 if((_wrapCounter>200)){ 3002 // Do nothing, handled later 3003 } 3004 else if((_rec_samples_old > POW2(31)) && (recSamples < 96000)) { 3005 WEBRTC_TRACE (kTraceDebug, kTraceUtility, -1,"WRAP 2 (_rec_samples_old %d recSamples %d)",_rec_samples_old, recSamples); 3006 // Wrap around as expected after having used all 32 bits. 3007 _read_samples_old = readSamples; 3008 _rec_samples_old = recSamples; 3009 _wrapCounter++; 3010 return (int)((recSamples + POW2(32) - readSamples)/nSamplesPerMs); 3011 3012 3013 } else if((recSamples < 96000) && (readSamples > POW2(31))) { 3014 WEBRTC_TRACE (kTraceDebug, kTraceUtility, -1,"WRAP 3 (readSamples %d recSamples %d)",readSamples, recSamples); 3015 // Wrap around has, as expected, happened for rec_sampels before 3016 // readSampels so we have to adjust for this until also readSampels 3017 // has had wrap around. 3018 _read_samples_old = readSamples; 3019 _rec_samples_old = recSamples; 3020 _wrapCounter++; 3021 return (int)((recSamples + POW2(32) - readSamples)/nSamplesPerMs); 3022 } 3023 3024 _read_samples_old = _read_samples; 3025 _rec_samples_old = recSamples; 3026 int res=(((int)_rec_samples_old - (int)_read_samples_old)/nSamplesPerMs); 3027 3028 if((res > 2000)||(res < 0)||(_wrapCounter>200)){ 3029 // Reset everything 3030 WEBRTC_TRACE (kTraceWarning, kTraceUtility, -1,"msec_read error (res %d wrapCounter %d)",res, _wrapCounter); 3031 MMTIME mmtime; 3032 mmtime.wType = TIME_SAMPLES; 3033 3034 mmr=waveInGetPosition(_hWaveIn, &mmtime, sizeof(mmtime)); 3035 if (mmr != MMSYSERR_NOERROR) { 3036 WEBRTC_TRACE (kTraceWarning, kTraceUtility, -1, "waveInGetPosition failed (mmr=%d)", mmr); 3037 } 3038 _read_samples=mmtime.u.sample; 3039 _read_samples_old=_read_samples; 3040 _rec_samples_old=mmtime.u.sample; 3041 3042 // Guess a decent value 3043 res = 20; 3044 } 3045 3046 _wrapCounter = 0; 3047 return res; 3048 } 3049 3050 // ============================================================================ 3051 // Thread Methods 3052 // ============================================================================ 3053 3054 // ---------------------------------------------------------------------------- 3055 // ThreadFunc 3056 // ---------------------------------------------------------------------------- 3057 3058 bool AudioDeviceWindowsWave::ThreadFunc(void* pThis) 3059 { 3060 return (static_cast<AudioDeviceWindowsWave*>(pThis)->ThreadProcess()); 3061 } 3062 3063 // ---------------------------------------------------------------------------- 3064 // ThreadProcess 3065 // ---------------------------------------------------------------------------- 3066 3067 bool AudioDeviceWindowsWave::ThreadProcess() 3068 { 3069 uint32_t time(0); 3070 uint32_t playDiff(0); 3071 uint32_t recDiff(0); 3072 3073 LONGLONG playTime(0); 3074 LONGLONG recTime(0); 3075 3076 switch (_timeEvent.Wait(1000)) 3077 { 3078 case kEventSignaled: 3079 break; 3080 case kEventError: 3081 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "EventWrapper::Wait() failed => restarting timer"); 3082 _timeEvent.StopTimer(); 3083 _timeEvent.StartTimer(true, TIMER_PERIOD_MS); 3084 return true; 3085 case kEventTimeout: 3086 return true; 3087 } 3088 3089 time = AudioDeviceUtility::GetTimeInMS(); 3090 3091 if (_startPlay) 3092 { 3093 if (PrepareStartPlayout() == 0) 3094 { 3095 _prevTimerCheckTime = time; 3096 _prevPlayTime = time; 3097 _startPlay = false; 3098 _playing = true; 3099 _playStartEvent.Set(); 3100 } 3101 } 3102 3103 if (_startRec) 3104 { 3105 if (PrepareStartRecording() == 0) 3106 { 3107 _prevTimerCheckTime = time; 3108 _prevRecTime = time; 3109 _prevRecByteCheckTime = time; 3110 _startRec = false; 3111 _recording = true; 3112 _recStartEvent.Set(); 3113 } 3114 } 3115 3116 if (_playing) 3117 { 3118 playDiff = time - _prevPlayTime; 3119 } 3120 3121 if (_recording) 3122 { 3123 recDiff = time - _prevRecTime; 3124 } 3125 3126 if (_playing || _recording) 3127 { 3128 RestartTimerIfNeeded(time); 3129 } 3130 3131 if (_playing && 3132 (playDiff > (uint32_t)(_dTcheckPlayBufDelay - 1)) || 3133 (playDiff < 0)) 3134 { 3135 Lock(); 3136 if (_playing) 3137 { 3138 if (PlayProc(playTime) == -1) 3139 { 3140 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "PlayProc() failed"); 3141 } 3142 _prevPlayTime = time; 3143 if (playTime != 0) 3144 _playAcc += playTime; 3145 } 3146 UnLock(); 3147 } 3148 3149 if (_playing && (playDiff > 12)) 3150 { 3151 // It has been a long time since we were able to play out, try to 3152 // compensate by calling PlayProc again. 3153 // 3154 Lock(); 3155 if (_playing) 3156 { 3157 if (PlayProc(playTime)) 3158 { 3159 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "PlayProc() failed"); 3160 } 3161 _prevPlayTime = time; 3162 if (playTime != 0) 3163 _playAcc += playTime; 3164 } 3165 UnLock(); 3166 } 3167 3168 if (_recording && 3169 (recDiff > REC_CHECK_TIME_PERIOD_MS) || 3170 (recDiff < 0)) 3171 { 3172 Lock(); 3173 if (_recording) 3174 { 3175 int32_t nRecordedBytes(0); 3176 uint16_t maxIter(10); 3177 3178 // Deliver all availiable recorded buffers and update the CPU load measurement. 3179 // We use a while loop here to compensate for the fact that the multi-media timer 3180 // can sometimed enter a "bad state" after hibernation where the resolution is 3181 // reduced from ~1ms to ~10-15 ms. 3182 // 3183 while ((nRecordedBytes = RecProc(recTime)) > 0) 3184 { 3185 maxIter--; 3186 _recordedBytes += nRecordedBytes; 3187 if (recTime && _perfFreq.QuadPart) 3188 { 3189 // Measure the average CPU load: 3190 // This is a simplified expression where an exponential filter is used: 3191 // _avgCPULoad = 0.99 * _avgCPULoad + 0.01 * newCPU, 3192 // newCPU = (recTime+playAcc)/f is time in seconds 3193 // newCPU / 0.01 is the fraction of a 10 ms period 3194 // The two 0.01 cancels each other. 3195 // NOTE - assumes 10ms audio buffers. 3196 // 3197 _avgCPULoad = (float)(_avgCPULoad*.99 + (recTime+_playAcc)/(double)(_perfFreq.QuadPart)); 3198 _playAcc = 0; 3199 } 3200 if (maxIter == 0) 3201 { 3202 // If we get this message ofte, our compensation scheme is not sufficient. 3203 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "failed to compensate for reduced MM-timer resolution"); 3204 } 3205 } 3206 3207 if (nRecordedBytes == -1) 3208 { 3209 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "RecProc() failed"); 3210 } 3211 3212 _prevRecTime = time; 3213 3214 // Monitor the recording process and generate error/warning callbacks if needed 3215 MonitorRecording(time); 3216 } 3217 UnLock(); 3218 } 3219 3220 if (!_recording) 3221 { 3222 _prevRecByteCheckTime = time; 3223 _avgCPULoad = 0; 3224 } 3225 3226 return true; 3227 } 3228 3229 // ---------------------------------------------------------------------------- 3230 // RecProc 3231 // ---------------------------------------------------------------------------- 3232 3233 int32_t AudioDeviceWindowsWave::RecProc(LONGLONG& consumedTime) 3234 { 3235 MMRESULT res; 3236 uint32_t bufCount(0); 3237 uint32_t nBytesRecorded(0); 3238 3239 consumedTime = 0; 3240 3241 // count modulo N_BUFFERS_IN (0,1,2,...,(N_BUFFERS_IN-1),0,1,2,..) 3242 if (_recBufCount == N_BUFFERS_IN) 3243 { 3244 _recBufCount = 0; 3245 } 3246 3247 bufCount = _recBufCount; 3248 3249 // take mono/stereo mode into account when deriving size of a full buffer 3250 const uint16_t bytesPerSample = 2*_recChannels; 3251 const uint32_t fullBufferSizeInBytes = bytesPerSample * REC_BUF_SIZE_IN_SAMPLES; 3252 3253 // read number of recorded bytes for the given input-buffer 3254 nBytesRecorded = _waveHeaderIn[bufCount].dwBytesRecorded; 3255 3256 if (nBytesRecorded == fullBufferSizeInBytes || 3257 (nBytesRecorded > 0)) 3258 { 3259 int32_t msecOnPlaySide; 3260 int32_t msecOnRecordSide; 3261 uint32_t writtenSamples; 3262 uint32_t playedSamples; 3263 uint32_t readSamples, recSamples; 3264 bool send = true; 3265 3266 uint32_t nSamplesRecorded = (nBytesRecorded/bytesPerSample); // divide by 2 or 4 depending on mono or stereo 3267 3268 if (nBytesRecorded == fullBufferSizeInBytes) 3269 { 3270 _timesdwBytes = 0; 3271 } 3272 else 3273 { 3274 // Test if it is stuck on this buffer 3275 _timesdwBytes++; 3276 if (_timesdwBytes < 5) 3277 { 3278 // keep trying 3279 return (0); 3280 } 3281 else 3282 { 3283 WEBRTC_TRACE(kTraceDebug, kTraceUtility, _id,"nBytesRecorded=%d => don't use", nBytesRecorded); 3284 _timesdwBytes = 0; 3285 send = false; 3286 } 3287 } 3288 3289 // store the recorded buffer (no action will be taken if the #recorded samples is not a full buffer) 3290 _ptrAudioBuffer->SetRecordedBuffer(_waveHeaderIn[bufCount].lpData, nSamplesRecorded); 3291 3292 // update #samples read 3293 _read_samples += nSamplesRecorded; 3294 3295 // Check how large the playout and recording buffers are on the sound card. 3296 // This info is needed by the AEC. 3297 // 3298 msecOnPlaySide = GetPlayoutBufferDelay(writtenSamples, playedSamples); 3299 msecOnRecordSide = GetRecordingBufferDelay(readSamples, recSamples); 3300 3301 // If we use the alternative playout delay method, skip the clock drift compensation 3302 // since it will be an unreliable estimate and might degrade AEC performance. 3303 int32_t drift = (_useHeader > 0) ? 0 : GetClockDrift(playedSamples, recSamples); 3304 3305 _ptrAudioBuffer->SetVQEData(msecOnPlaySide, msecOnRecordSide, drift); 3306 3307 _ptrAudioBuffer->SetTypingStatus(KeyPressed()); 3308 3309 // Store the play and rec delay values for video synchronization 3310 _sndCardPlayDelay = msecOnPlaySide; 3311 _sndCardRecDelay = msecOnRecordSide; 3312 3313 LARGE_INTEGER t1,t2; 3314 3315 if (send) 3316 { 3317 QueryPerformanceCounter(&t1); 3318 3319 // deliver recorded samples at specified sample rate, mic level etc. to the observer using callback 3320 UnLock(); 3321 _ptrAudioBuffer->DeliverRecordedData(); 3322 Lock(); 3323 3324 QueryPerformanceCounter(&t2); 3325 3326 if (InputSanityCheckAfterUnlockedPeriod() == -1) 3327 { 3328 // assert(false); 3329 return -1; 3330 } 3331 } 3332 3333 if (_AGC) 3334 { 3335 uint32_t newMicLevel = _ptrAudioBuffer->NewMicLevel(); 3336 if (newMicLevel != 0) 3337 { 3338 // The VQE will only deliver non-zero microphone levels when a change is needed. 3339 WEBRTC_TRACE(kTraceStream, kTraceUtility, _id,"AGC change of volume: => new=%u", newMicLevel); 3340 3341 // We store this outside of the audio buffer to avoid 3342 // having it overwritten by the getter thread. 3343 _newMicLevel = newMicLevel; 3344 SetEvent(_hSetCaptureVolumeEvent); 3345 } 3346 } 3347 3348 // return utilized buffer to queue after specified delay (default is 4) 3349 if (_recDelayCount > (_recPutBackDelay-1)) 3350 { 3351 // deley buffer counter to compensate for "put-back-delay" 3352 bufCount = (bufCount + N_BUFFERS_IN - _recPutBackDelay) % N_BUFFERS_IN; 3353 3354 // reset counter so we can make new detection 3355 _waveHeaderIn[bufCount].dwBytesRecorded = 0; 3356 3357 // return the utilized wave-header after certain delay (given by _recPutBackDelay) 3358 res = waveInUnprepareHeader(_hWaveIn, &(_waveHeaderIn[bufCount]), sizeof(WAVEHDR)); 3359 if (MMSYSERR_NOERROR != res) 3360 { 3361 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "waveInUnprepareHeader(%d) failed (err=%d)", bufCount, res); 3362 TraceWaveInError(res); 3363 } 3364 3365 // ensure that the utilized header can be used again 3366 res = waveInPrepareHeader(_hWaveIn, &(_waveHeaderIn[bufCount]), sizeof(WAVEHDR)); 3367 if (res != MMSYSERR_NOERROR) 3368 { 3369 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "waveInPrepareHeader(%d) failed (err=%d)", bufCount, res); 3370 TraceWaveInError(res); 3371 return -1; 3372 } 3373 3374 // add the utilized buffer to the queue again 3375 res = waveInAddBuffer(_hWaveIn, &(_waveHeaderIn[bufCount]), sizeof(WAVEHDR)); 3376 if (res != MMSYSERR_NOERROR) 3377 { 3378 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "waveInAddBuffer(%d) failed (err=%d)", bufCount, res); 3379 TraceWaveInError(res); 3380 if (_recPutBackDelay < 50) 3381 { 3382 _recPutBackDelay++; 3383 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "_recPutBackDelay increased to %d", _recPutBackDelay); 3384 } 3385 else 3386 { 3387 if (_recError == 1) 3388 { 3389 WEBRTC_TRACE(kTraceWarning, kTraceUtility, _id, "pending recording error exists"); 3390 } 3391 _recError = 1; // triggers callback from module process thread 3392 WEBRTC_TRACE(kTraceError, kTraceUtility, _id, "kRecordingError message posted: _recPutBackDelay=%u", _recPutBackDelay); 3393 } 3394 } 3395 } // if (_recDelayCount > (_recPutBackDelay-1)) 3396 3397 if (_recDelayCount < (_recPutBackDelay+1)) 3398 { 3399 _recDelayCount++; 3400 } 3401 3402 // increase main buffer count since one complete buffer has now been delivered 3403 _recBufCount++; 3404 3405 if (send) { 3406 // Calculate processing time 3407 consumedTime = (int)(t2.QuadPart-t1.QuadPart); 3408 // handle wraps, time should not be higher than a second 3409 if ((consumedTime > _perfFreq.QuadPart) || (consumedTime < 0)) 3410 consumedTime = 0; 3411 } 3412 3413 } // if ((nBytesRecorded == fullBufferSizeInBytes)) 3414 3415 return nBytesRecorded; 3416 } 3417 3418 // ---------------------------------------------------------------------------- 3419 // PlayProc 3420 // ---------------------------------------------------------------------------- 3421 3422 int AudioDeviceWindowsWave::PlayProc(LONGLONG& consumedTime) 3423 { 3424 int32_t remTimeMS(0); 3425 int8_t playBuffer[4*PLAY_BUF_SIZE_IN_SAMPLES]; 3426 uint32_t writtenSamples(0); 3427 uint32_t playedSamples(0); 3428 3429 LARGE_INTEGER t1; 3430 LARGE_INTEGER t2; 3431 3432 consumedTime = 0; 3433 _waitCounter++; 3434 3435 // Get number of ms of sound that remains in the sound card buffer for playback. 3436 // 3437 remTimeMS = GetPlayoutBufferDelay(writtenSamples, playedSamples); 3438 3439 // The threshold can be adaptive or fixed. The adaptive scheme is updated 3440 // also for fixed mode but the updated threshold is not utilized. 3441 // 3442 const uint16_t thresholdMS = 3443 (_playBufType == AudioDeviceModule::kAdaptiveBufferSize) ? _playBufDelay : _playBufDelayFixed; 3444 3445 if (remTimeMS < thresholdMS + 9) 3446 { 3447 _dTcheckPlayBufDelay = 5; 3448 3449 if (remTimeMS == 0) 3450 { 3451 WEBRTC_TRACE(kTraceInfo, kTraceUtility, _id, "playout buffer is empty => we must adapt..."); 3452 if (_waitCounter > 30) 3453 { 3454 _erZeroCounter++; 3455 if (_erZeroCounter == 2) 3456 { 3457 _playBufDelay += 15; 3458 _minPlayBufDelay += 20; 3459 _waitCounter = 50; 3460 WEBRTC_TRACE(kTraceDebug, kTraceUtility, _id, "New playout states (er=0,erZero=2): minPlayBufDelay=%u, playBufDelay=%u", _minPlayBufDelay, _playBufDelay); 3461 } 3462 else if (_erZeroCounter == 3) 3463 { 3464 _erZeroCounter = 0; 3465 _playBufDelay += 30; 3466 _minPlayBufDelay += 25; 3467 _waitCounter = 0; 3468 WEBRTC_TRACE(kTraceDebug, kTraceUtility, _id, "New playout states (er=0, erZero=3): minPlayBufDelay=%u, playBufDelay=%u", _minPlayBufDelay, _playBufDelay); 3469 } 3470 else 3471 { 3472 _minPlayBufDelay += 10; 3473 _playBufDelay += 15; 3474 _waitCounter = 50; 3475 WEBRTC_TRACE(kTraceDebug, kTraceUtility, _id, "New playout states (er=0, erZero=1): minPlayBufDelay=%u, playBufDelay=%u", _minPlayBufDelay, _playBufDelay); 3476 } 3477 } 3478 } 3479 else if (remTimeMS < _minPlayBufDelay) 3480 { 3481 // If there is less than 25 ms of audio in the play out buffer 3482 // increase the buffersize limit value. _waitCounter prevents 3483 // _playBufDelay to be increased every time this function is called. 3484 3485 if (_waitCounter > 30) 3486 { 3487 _playBufDelay += 10; 3488 if (_intro == 0) 3489 _waitCounter = 0; 3490 WEBRTC_TRACE(kTraceDebug, kTraceUtility, _id, "Playout threshold is increased: playBufDelay=%u", _playBufDelay); 3491 } 3492 } 3493 else if (remTimeMS < thresholdMS - 9) 3494 { 3495 _erZeroCounter = 0; 3496 } 3497 else 3498 { 3499 _erZeroCounter = 0; 3500 _dTcheckPlayBufDelay = 10; 3501 } 3502 3503 QueryPerformanceCounter(&t1); // measure time: START 3504 3505 // Ask for new PCM data to be played out using the AudioDeviceBuffer. 3506 // Ensure that this callback is executed without taking the audio-thread lock. 3507 // 3508 UnLock(); 3509 uint32_t nSamples = _ptrAudioBuffer->RequestPlayoutData(PLAY_BUF_SIZE_IN_SAMPLES); 3510 Lock(); 3511 3512 if (OutputSanityCheckAfterUnlockedPeriod() == -1) 3513 { 3514 // assert(false); 3515 return -1; 3516 } 3517 3518 nSamples = _ptrAudioBuffer->GetPlayoutData(playBuffer); 3519 if (nSamples != PLAY_BUF_SIZE_IN_SAMPLES) 3520 { 3521 WEBRTC_TRACE(kTraceError, kTraceUtility, _id, "invalid number of output samples(%d)", nSamples); 3522 } 3523 3524 QueryPerformanceCounter(&t2); // measure time: STOP 3525 consumedTime = (int)(t2.QuadPart - t1.QuadPart); 3526 3527 Write(playBuffer, PLAY_BUF_SIZE_IN_SAMPLES); 3528 3529 } // if (er < thresholdMS + 9) 3530 else if (thresholdMS + 9 < remTimeMS ) 3531 { 3532 _erZeroCounter = 0; 3533 _dTcheckPlayBufDelay = 2; // check buffer more often 3534 WEBRTC_TRACE(kTraceDebug, kTraceUtility, _id, "Need to check playout buffer more often (dT=%u, remTimeMS=%u)", _dTcheckPlayBufDelay, remTimeMS); 3535 } 3536 3537 // If the buffersize has been stable for 20 seconds try to decrease the buffer size 3538 if (_waitCounter > 2000) 3539 { 3540 _intro = 0; 3541 _playBufDelay--; 3542 _waitCounter = 1990; 3543 WEBRTC_TRACE(kTraceDebug, kTraceUtility, _id, "Playout threshold is decreased: playBufDelay=%u", _playBufDelay); 3544 } 3545 3546 // Limit the minimum sound card (playback) delay to adaptive minimum delay 3547 if (_playBufDelay < _minPlayBufDelay) 3548 { 3549 _playBufDelay = _minPlayBufDelay; 3550 WEBRTC_TRACE(kTraceDebug, kTraceUtility, _id, "Playout threshold is limited to %u", _minPlayBufDelay); 3551 } 3552 3553 // Limit the maximum sound card (playback) delay to 150 ms 3554 if (_playBufDelay > 150) 3555 { 3556 _playBufDelay = 150; 3557 WEBRTC_TRACE(kTraceDebug, kTraceUtility, _id, "Playout threshold is limited to %d", _playBufDelay); 3558 } 3559 3560 // Upper limit of the minimum sound card (playback) delay to 65 ms. 3561 // Deactivated during "useHeader mode" (_useHeader > 0). 3562 if (_minPlayBufDelay > _MAX_minBuffer && 3563 (_useHeader == 0)) 3564 { 3565 _minPlayBufDelay = _MAX_minBuffer; 3566 WEBRTC_TRACE(kTraceDebug, kTraceUtility, _id, "Minimum playout threshold is limited to %d", _MAX_minBuffer); 3567 } 3568 3569 return (0); 3570 } 3571 3572 // ---------------------------------------------------------------------------- 3573 // Write 3574 // ---------------------------------------------------------------------------- 3575 3576 int32_t AudioDeviceWindowsWave::Write(int8_t* data, uint16_t nSamples) 3577 { 3578 if (_hWaveOut == NULL) 3579 { 3580 return -1; 3581 } 3582 3583 if (_playIsInitialized) 3584 { 3585 MMRESULT res; 3586 3587 const uint16_t bufCount(_playBufCount); 3588 3589 // Place data in the memory associated with _waveHeaderOut[bufCount] 3590 // 3591 const int16_t nBytes = (2*_playChannels)*nSamples; 3592 memcpy(&_playBuffer[bufCount][0], &data[0], nBytes); 3593 3594 // Send a data block to the given waveform-audio output device. 3595 // 3596 // When the buffer is finished, the WHDR_DONE bit is set in the dwFlags 3597 // member of the WAVEHDR structure. The buffer must be prepared with the 3598 // waveOutPrepareHeader function before it is passed to waveOutWrite. 3599 // Unless the device is paused by calling the waveOutPause function, 3600 // playback begins when the first data block is sent to the device. 3601 // 3602 res = waveOutWrite(_hWaveOut, &_waveHeaderOut[bufCount], sizeof(_waveHeaderOut[bufCount])); 3603 if (MMSYSERR_NOERROR != res) 3604 { 3605 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "waveOutWrite(%d) failed (err=%d)", bufCount, res); 3606 TraceWaveOutError(res); 3607 3608 _writeErrors++; 3609 if (_writeErrors > 10) 3610 { 3611 if (_playError == 1) 3612 { 3613 WEBRTC_TRACE(kTraceWarning, kTraceUtility, _id, "pending playout error exists"); 3614 } 3615 _playError = 1; // triggers callback from module process thread 3616 WEBRTC_TRACE(kTraceError, kTraceUtility, _id, "kPlayoutError message posted: _writeErrors=%u", _writeErrors); 3617 } 3618 3619 return -1; 3620 } 3621 3622 _playBufCount = (_playBufCount+1) % N_BUFFERS_OUT; // increase buffer counter modulo size of total buffer 3623 _writtenSamples += nSamples; // each sample is 2 or 4 bytes 3624 _writeErrors = 0; 3625 } 3626 3627 return 0; 3628 } 3629 3630 // ---------------------------------------------------------------------------- 3631 // GetClockDrift 3632 // ---------------------------------------------------------------------------- 3633 3634 int32_t AudioDeviceWindowsWave::GetClockDrift(const uint32_t plSamp, const uint32_t rcSamp) 3635 { 3636 int drift = 0; 3637 unsigned int plSampDiff = 0, rcSampDiff = 0; 3638 3639 if (plSamp >= _plSampOld) 3640 { 3641 plSampDiff = plSamp - _plSampOld; 3642 } 3643 else 3644 { 3645 // Wrap 3646 int i = 31; 3647 while(_plSampOld <= (unsigned int)POW2(i)) 3648 { 3649 i--; 3650 } 3651 3652 // Add the amount remaining prior to wrapping 3653 plSampDiff = plSamp + POW2(i + 1) - _plSampOld; 3654 } 3655 3656 if (rcSamp >= _rcSampOld) 3657 { 3658 rcSampDiff = rcSamp - _rcSampOld; 3659 } 3660 else 3661 { // Wrap 3662 int i = 31; 3663 while(_rcSampOld <= (unsigned int)POW2(i)) 3664 { 3665 i--; 3666 } 3667 3668 rcSampDiff = rcSamp + POW2(i + 1) - _rcSampOld; 3669 } 3670 3671 drift = plSampDiff - rcSampDiff; 3672 3673 _plSampOld = plSamp; 3674 _rcSampOld = rcSamp; 3675 3676 return drift; 3677 } 3678 3679 // ---------------------------------------------------------------------------- 3680 // MonitorRecording 3681 // ---------------------------------------------------------------------------- 3682 3683 int32_t AudioDeviceWindowsWave::MonitorRecording(const uint32_t time) 3684 { 3685 const uint16_t bytesPerSample = 2*_recChannels; 3686 const uint32_t nRecordedSamples = _recordedBytes/bytesPerSample; 3687 3688 if (nRecordedSamples > 5*N_REC_SAMPLES_PER_SEC) 3689 { 3690 // 5 seconds of audio has been recorded... 3691 if ((time - _prevRecByteCheckTime) > 5700) 3692 { 3693 // ...and it was more than 5.7 seconds since we last did this check <=> 3694 // we have not been able to record 5 seconds of audio in 5.7 seconds, 3695 // hence a problem should be reported. 3696 // This problem can be related to USB overload. 3697 // 3698 if (_recWarning == 1) 3699 { 3700 WEBRTC_TRACE(kTraceWarning, kTraceUtility, _id, "pending recording warning exists"); 3701 } 3702 _recWarning = 1; // triggers callback from module process thread 3703 WEBRTC_TRACE(kTraceWarning, kTraceUtility, _id, "kRecordingWarning message posted: time-_prevRecByteCheckTime=%d", time - _prevRecByteCheckTime); 3704 } 3705 3706 _recordedBytes = 0; // restart "check again when 5 seconds are recorded" 3707 _prevRecByteCheckTime = time; // reset timer to measure time for recording of 5 seconds 3708 } 3709 3710 if ((time - _prevRecByteCheckTime) > 8000) 3711 { 3712 // It has been more than 8 seconds since we able to confirm that 5 seconds of 3713 // audio was recorded, hence we have not been able to record 5 seconds in 3714 // 8 seconds => the complete recording process is most likely dead. 3715 // 3716 if (_recError == 1) 3717 { 3718 WEBRTC_TRACE(kTraceWarning, kTraceUtility, _id, "pending recording error exists"); 3719 } 3720 _recError = 1; // triggers callback from module process thread 3721 WEBRTC_TRACE(kTraceError, kTraceUtility, _id, "kRecordingError message posted: time-_prevRecByteCheckTime=%d", time - _prevRecByteCheckTime); 3722 3723 _prevRecByteCheckTime = time; 3724 } 3725 3726 return 0; 3727 } 3728 3729 // ---------------------------------------------------------------------------- 3730 // MonitorRecording 3731 // 3732 // Restart timer if needed (they seem to be messed up after a hibernate). 3733 // ---------------------------------------------------------------------------- 3734 3735 int32_t AudioDeviceWindowsWave::RestartTimerIfNeeded(const uint32_t time) 3736 { 3737 const uint32_t diffMS = time - _prevTimerCheckTime; 3738 _prevTimerCheckTime = time; 3739 3740 if (diffMS > 7) 3741 { 3742 // one timer-issue detected... 3743 _timerFaults++; 3744 if (_timerFaults > 5 && _timerRestartAttempts < 2) 3745 { 3746 // Reinitialize timer event if event fails to execute at least every 5ms. 3747 // On some machines it helps and the timer starts working as it should again; 3748 // however, not all machines (we have seen issues on e.g. IBM T60). 3749 // Therefore, the scheme below ensures that we do max 2 attempts to restart the timer. 3750 // For the cases where restart does not do the trick, we compensate for the reduced 3751 // resolution on both the recording and playout sides. 3752 WEBRTC_TRACE(kTraceWarning, kTraceUtility, _id, " timer issue detected => timer is restarted"); 3753 _timeEvent.StopTimer(); 3754 _timeEvent.StartTimer(true, TIMER_PERIOD_MS); 3755 // make sure timer gets time to start up and we don't kill/start timer serveral times over and over again 3756 _timerFaults = -20; 3757 _timerRestartAttempts++; 3758 } 3759 } 3760 else 3761 { 3762 // restart timer-check scheme since we are OK 3763 _timerFaults = 0; 3764 _timerRestartAttempts = 0; 3765 } 3766 3767 return 0; 3768 } 3769 3770 3771 bool AudioDeviceWindowsWave::KeyPressed() const{ 3772 3773 int key_down = 0; 3774 for (int key = VK_SPACE; key < VK_NUMLOCK; key++) { 3775 short res = GetAsyncKeyState(key); 3776 key_down |= res & 0x1; // Get the LSB 3777 } 3778 return (key_down > 0); 3779 } 3780 } // namespace webrtc 3781