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