Skip to content

Commit 0e68e35

Browse files
Merge pull request #16 from secondlife/roxie/fix-audio-dropout
Switch WASAPI playout to timer-driven mode with AUTOCONVERTPCM
2 parents 4d2b05e + b1bcea2 commit 0e68e35

File tree

1 file changed

+65
-15
lines changed

1 file changed

+65
-15
lines changed

build/patches/windows_add_192k.patch

Lines changed: 65 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
diff --git a/modules/audio_device/win/audio_device_core_win.cc b/modules/audio_device/win/audio_device_core_win.cc
2-
index f1cc0474fc..f8e4f25bb9 100644
2+
index f1cc0474fc..2aacd1d309 100644
33
--- a/modules/audio_device/win/audio_device_core_win.cc
44
+++ b/modules/audio_device/win/audio_device_core_win.cc
55
@@ -1845,8 +1845,8 @@ int32_t AudioDeviceWindowsCore::InitPlayout() {
@@ -142,14 +142,13 @@ index f1cc0474fc..f8e4f25bb9 100644
142142
RTC_LOG(LS_VERBOSE) << "Additional settings:";
143143
RTC_LOG(LS_VERBOSE) << "_playAudioFrameSize: " << _playAudioFrameSize;
144144
RTC_LOG(LS_VERBOSE) << "_playBlockSize : " << _playBlockSize;
145-
@@ -1980,12 +2007,14 @@ int32_t AudioDeviceWindowsCore::InitPlayout() {
145+
@@ -1980,12 +2007,12 @@ int32_t AudioDeviceWindowsCore::InitPlayout() {
146146
}
147147
hr = _ptrClientOut->Initialize(
148148
AUDCLNT_SHAREMODE_SHARED, // share Audio Engine with other applications
149149
- AUDCLNT_STREAMFLAGS_EVENTCALLBACK, // processing of the audio buffer by
150-
+ AUDCLNT_STREAMFLAGS_EVENTCALLBACK | // processing of the audio buffer by
151-
// the client will be event driven
152-
+ AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM |
150+
- // the client will be event driven
151+
+ AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | // let WASAPI handle format conversion
153152
+ AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY,
154153
hnsBufferDuration, // requested buffer capacity as a time value (in
155154
// 100-nanosecond units)
@@ -159,7 +158,19 @@ index f1cc0474fc..f8e4f25bb9 100644
159158
NULL); // session GUID
160159

161160
if (FAILED(hr)) {
162-
@@ -2031,7 +2060,7 @@ int32_t AudioDeviceWindowsCore::InitPlayout() {
161+
@@ -2016,11 +2043,6 @@ int32_t AudioDeviceWindowsCore::InitPlayout() {
162+
<< bufferFrameCount * _playAudioFrameSize << " bytes)";
163+
}
164+
165+
- // Set the event handle that the system signals when an audio buffer is ready
166+
- // to be processed by the client.
167+
- hr = _ptrClientOut->SetEventHandle(_hRenderSamplesReadyEvent);
168+
- EXIT_ON_ERROR(hr);
169+
-
170+
// Get an IAudioRenderClient interface.
171+
SAFE_RELEASE(_ptrRenderClient);
172+
hr = _ptrClientOut->GetService(__uuidof(IAudioRenderClient),
173+
@@ -2031,7 +2053,7 @@ int32_t AudioDeviceWindowsCore::InitPlayout() {
163174
_playIsInitialized = true;
164175

165176
CoTaskMemFree(pWfxOut);
@@ -168,7 +179,7 @@ index f1cc0474fc..f8e4f25bb9 100644
168179

169180
RTC_LOG(LS_VERBOSE) << "render side is now initialized";
170181
return 0;
171-
@@ -2039,7 +2068,7 @@ int32_t AudioDeviceWindowsCore::InitPlayout() {
182+
@@ -2039,7 +2061,7 @@ int32_t AudioDeviceWindowsCore::InitPlayout() {
172183
Exit:
173184
_TraceCOMError(hr);
174185
CoTaskMemFree(pWfxOut);
@@ -177,7 +188,7 @@ index f1cc0474fc..f8e4f25bb9 100644
177188
SAFE_RELEASE(_ptrClientOut);
178189
SAFE_RELEASE(_ptrRenderClient);
179190
return -1;
180-
@@ -2163,7 +2192,7 @@ int32_t AudioDeviceWindowsCore::InitRecording() {
191+
@@ -2163,7 +2185,7 @@ int32_t AudioDeviceWindowsCore::InitRecording() {
181192
HRESULT hr = S_OK;
182193
WAVEFORMATEX* pWfxIn = NULL;
183194
WAVEFORMATEXTENSIBLE Wfx = WAVEFORMATEXTENSIBLE();
@@ -186,7 +197,7 @@ index f1cc0474fc..f8e4f25bb9 100644
186197

187198
// Create COM object with IAudioClient interface.
188199
SAFE_RELEASE(_ptrClientIn);
189-
@@ -2201,7 +2230,7 @@ int32_t AudioDeviceWindowsCore::InitRecording() {
200+
@@ -2201,7 +2223,7 @@ int32_t AudioDeviceWindowsCore::InitRecording() {
190201
Wfx.Samples.wValidBitsPerSample = Wfx.Format.wBitsPerSample;
191202
Wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
192203

@@ -195,7 +206,7 @@ index f1cc0474fc..f8e4f25bb9 100644
195206
hr = S_FALSE;
196207

197208
// Iterate over frequencies and channels, in order of priority
198-
@@ -2218,8 +2247,10 @@ int32_t AudioDeviceWindowsCore::InitRecording() {
209+
@@ -2218,8 +2240,10 @@ int32_t AudioDeviceWindowsCore::InitRecording() {
199210
// If the method succeeds and the audio endpoint device supports the
200211
// specified stream format, it returns S_OK. If the method succeeds and
201212
// provides a closest match to the specified format, it returns S_FALSE.
@@ -208,7 +219,7 @@ index f1cc0474fc..f8e4f25bb9 100644
208219
if (hr == S_OK) {
209220
break;
210221
} else {
211-
@@ -2228,10 +2259,14 @@ int32_t AudioDeviceWindowsCore::InitRecording() {
222+
@@ -2228,10 +2252,14 @@ int32_t AudioDeviceWindowsCore::InitRecording() {
212223
<< ", nSamplesPerSec=" << Wfx.Format.nSamplesPerSec
213224
<< " is not supported. Closest match: "
214225
"nChannels="
@@ -227,7 +238,7 @@ index f1cc0474fc..f8e4f25bb9 100644
227238
} else {
228239
RTC_LOG(LS_INFO) << "nChannels=" << Wfx.Format.nChannels
229240
<< ", nSamplesPerSec=" << Wfx.Format.nSamplesPerSec
230-
@@ -2242,7 +2277,20 @@ int32_t AudioDeviceWindowsCore::InitRecording() {
241+
@@ -2242,7 +2270,20 @@ int32_t AudioDeviceWindowsCore::InitRecording() {
231242
if (hr == S_OK)
232243
break;
233244
}
@@ -249,7 +260,7 @@ index f1cc0474fc..f8e4f25bb9 100644
249260
if (hr == S_OK) {
250261
_recAudioFrameSize = Wfx.Format.nBlockAlign;
251262
_recSampleRate = Wfx.Format.nSamplesPerSec;
252-
@@ -2270,6 +2318,8 @@ int32_t AudioDeviceWindowsCore::InitRecording() {
263+
@@ -2270,6 +2311,8 @@ int32_t AudioDeviceWindowsCore::InitRecording() {
253264
AUDCLNT_SHAREMODE_SHARED, // share Audio Engine with other applications
254265
AUDCLNT_STREAMFLAGS_EVENTCALLBACK | // processing of the audio buffer by
255266
// the client will be event driven
@@ -258,7 +269,7 @@ index f1cc0474fc..f8e4f25bb9 100644
258269
AUDCLNT_STREAMFLAGS_NOPERSIST, // volume and mute settings for an
259270
// audio session will not persist
260271
// across system restarts
261-
@@ -2321,7 +2371,7 @@ int32_t AudioDeviceWindowsCore::InitRecording() {
272+
@@ -2321,7 +2364,7 @@ int32_t AudioDeviceWindowsCore::InitRecording() {
262273
_recIsInitialized = true;
263274

264275
CoTaskMemFree(pWfxIn);
@@ -267,7 +278,7 @@ index f1cc0474fc..f8e4f25bb9 100644
267278

268279
RTC_LOG(LS_VERBOSE) << "capture side is now initialized";
269280
return 0;
270-
@@ -2329,7 +2379,7 @@ int32_t AudioDeviceWindowsCore::InitRecording() {
281+
@@ -2329,7 +2372,7 @@ int32_t AudioDeviceWindowsCore::InitRecording() {
271282
Exit:
272283
_TraceCOMError(hr);
273284
CoTaskMemFree(pWfxIn);
@@ -276,3 +287,42 @@ index f1cc0474fc..f8e4f25bb9 100644
276287
SAFE_RELEASE(_ptrClientIn);
277288
SAFE_RELEASE(_ptrCaptureClient);
278289
return -1;
290+
@@ -2661,7 +2704,6 @@ DWORD WINAPI AudioDeviceWindowsCore::WSAPICaptureThreadPollDMO(LPVOID context) {
291+
292+
DWORD AudioDeviceWindowsCore::DoRenderThread() {
293+
bool keepPlaying = true;
294+
- HANDLE waitArray[2] = {_hShutdownRenderEvent, _hRenderSamplesReadyEvent};
295+
HRESULT hr = S_OK;
296+
HANDLE hMmTask = NULL;
297+
298+
@@ -2777,20 +2819,16 @@ DWORD AudioDeviceWindowsCore::DoRenderThread() {
299+
// >> ------------------ THREAD LOOP ------------------
300+
301+
while (keepPlaying) {
302+
- // Wait for a render notification event or a shutdown event
303+
- DWORD waitResult = WaitForMultipleObjects(2, waitArray, FALSE, 500);
304+
- switch (waitResult) {
305+
- case WAIT_OBJECT_0 + 0: // _hShutdownRenderEvent
306+
- keepPlaying = false;
307+
- break;
308+
- case WAIT_OBJECT_0 + 1: // _hRenderSamplesReadyEvent
309+
- break;
310+
- case WAIT_TIMEOUT: // timeout notification
311+
- RTC_LOG(LS_WARNING) << "render event timed out after 0.5 seconds";
312+
- goto Exit;
313+
- default: // unexpected error
314+
- RTC_LOG(LS_WARNING) << "unknown wait termination on render side";
315+
- goto Exit;
316+
+ // Sleep for half the device period, then poll for available buffer space.
317+
+ // We use the shutdown event wait as the sleep mechanism so we can still
318+
+ // wake immediately on shutdown.
319+
+ DWORD sleepMs = static_cast<DWORD>(devPeriod / 10000 / 2);
320+
+ if (sleepMs < 1)
321+
+ sleepMs = 1;
322+
+ DWORD waitResult = WaitForSingleObject(_hShutdownRenderEvent, sleepMs);
323+
+ if (waitResult == WAIT_OBJECT_0) {
324+
+ keepPlaying = false;
325+
+ break;
326+
}
327+
328+
while (keepPlaying) {

0 commit comments

Comments
 (0)