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