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