Note: We no longer publish the latest version of our code here. We primarily use a kumc-bmi github organization. The heron ETL repository, in particular, is not public. Peers in the informatics community should see MultiSiteDev for details on requesting access.

source: webrtc/webrtc/modules/audio_device/win/audio_device_wave_win.cc @ 0:4bda6873e34c

pub_scrub_3792 tip
Last change on this file since 0:4bda6873e34c was 0:4bda6873e34c, checked in by Michael Prittie <mprittie@…>, 6 years ago

Scrubbed password for publication.

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