3
3
#include " common.h"
4
4
5
5
HRESULT LoopbackCapture (
6
- IMMDevice * pMMInDevice,
7
- IMMDevice * pMMOutDevice,
6
+ IMMDevice* pMMInDevice,
7
+ IMMDevice* pMMOutDevice,
8
8
int iBufferMs,
9
9
bool bSwapChannels,
10
10
HANDLE hStartedEvent,
@@ -13,7 +13,7 @@ HRESULT LoopbackCapture(
13
13
);
14
14
15
15
DWORD WINAPI LoopbackCaptureThreadFunction (LPVOID pContext) {
16
- LoopbackCaptureThreadFunctionArguments * pArgs =
16
+ LoopbackCaptureThreadFunctionArguments* pArgs =
17
17
(LoopbackCaptureThreadFunctionArguments*)pContext;
18
18
19
19
pArgs->hr = CoInitialize (NULL );
@@ -36,7 +36,12 @@ DWORD WINAPI LoopbackCaptureThreadFunction(LPVOID pContext) {
36
36
return 0 ;
37
37
}
38
38
39
- void swapMemcpy (void *_dst, void *_src, size_t size, size_t chunkSize) {
39
+ void swapMemcpy (void * _dst, const void * _src, size_t size, bool doSwap, size_t chunkSize) {
40
+ if (!doSwap) {
41
+ memcpy (_dst, _src, size);
42
+ return ;
43
+ }
44
+
40
45
size_t blockSize = chunkSize * 2 ;
41
46
42
47
if (size % blockSize != 0 ) {
@@ -45,7 +50,7 @@ void swapMemcpy(void *_dst, void *_src, size_t size, size_t chunkSize) {
45
50
}
46
51
47
52
BYTE* dst = (BYTE*)_dst;
48
- BYTE* src = (BYTE*)_src;
53
+ const BYTE* src = (BYTE*)_src;
49
54
50
55
for (size_t i = 0 ; i < size / blockSize; i++) {
51
56
memcpy (dst + i * blockSize, src + i * blockSize + chunkSize, chunkSize);
@@ -54,8 +59,8 @@ void swapMemcpy(void *_dst, void *_src, size_t size, size_t chunkSize) {
54
59
}
55
60
56
61
HRESULT LoopbackCapture (
57
- IMMDevice * pMMInDevice,
58
- IMMDevice * pMMOutDevice,
62
+ IMMDevice* pMMInDevice,
63
+ IMMDevice* pMMOutDevice,
59
64
int iBufferMs,
60
65
bool bSwapChannels,
61
66
HANDLE hStartedEvent,
@@ -65,7 +70,7 @@ HRESULT LoopbackCapture(
65
70
HRESULT hr;
66
71
67
72
// activate an IAudioClient
68
- IAudioClient * pAudioClient;
73
+ IAudioClient* pAudioClient;
69
74
hr = pMMInDevice->Activate (
70
75
__uuidof (IAudioClient),
71
76
CLSCTX_ALL, NULL ,
@@ -86,7 +91,7 @@ HRESULT LoopbackCapture(
86
91
}
87
92
88
93
// get the default device format
89
- WAVEFORMATEX * pwfx;
94
+ WAVEFORMATEX* pwfx;
90
95
hr = pAudioClient->GetMixFormat (&pwfx);
91
96
if (FAILED (hr)) {
92
97
ERR (L" IAudioClient::GetMixFormat failed: hr = 0x%08x" , hr);
@@ -96,7 +101,21 @@ HRESULT LoopbackCapture(
96
101
97
102
if (pwfx->nChannels != 1 ) {
98
103
ERR (L" device doesn't have 1 channel, has %d" , pwfx->nChannels );
99
- return hr;
104
+ return E_UNEXPECTED;
105
+ }
106
+
107
+ if (pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
108
+ auto pwfxExtensible = reinterpret_cast <PWAVEFORMATEXTENSIBLE>(pwfx);
109
+ if (!IsEqualGUID (KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, pwfxExtensible->SubFormat ) && !IsEqualGUID (KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, pwfxExtensible->SubFormat )) {
110
+ OLECHAR subFormatGUID[39 ];
111
+ StringFromGUID2 (pwfxExtensible->SubFormat , subFormatGUID, _countof (subFormatGUID));
112
+ ERR (L" extensible input format not PCM, got %s" , subFormatGUID);
113
+ return E_UNEXPECTED;
114
+ }
115
+ }
116
+ else if (pwfx->wFormatTag != WAVE_FORMAT_PCM && pwfx->wFormatTag != WAVE_FORMAT_IEEE_FLOAT) {
117
+ ERR (L" input format not PCM, got %d" , pwfx->wFormatTag );
118
+ return E_UNEXPECTED;
100
119
}
101
120
102
121
pwfx->nBlockAlign = pwfx->nChannels * pwfx->wBitsPerSample / 8 ;
@@ -116,7 +135,7 @@ HRESULT LoopbackCapture(
116
135
}
117
136
118
137
// activate an IAudioCaptureClient
119
- IAudioCaptureClient * pAudioCaptureClient;
138
+ IAudioCaptureClient* pAudioCaptureClient;
120
139
hr = pAudioClient->GetService (
121
140
__uuidof (IAudioCaptureClient),
122
141
(void **)&pAudioCaptureClient
@@ -161,9 +180,10 @@ HRESULT LoopbackCapture(
161
180
pwfx->nChannels *= 2 ;
162
181
pwfx->nSamplesPerSec /= 2 ;
163
182
pwfx->nBlockAlign *= 2 ;
183
+ UINT32 OutputBlockAlign = pwfx->nBlockAlign ;
164
184
165
185
// set up output device
166
- IAudioClient * pAudioOutClient;
186
+ IAudioClient* pAudioOutClient;
167
187
hr = pMMOutDevice->Activate (
168
188
__uuidof (IAudioClient), CLSCTX_ALL,
169
189
NULL , (void **)&pAudioOutClient);
@@ -175,7 +195,7 @@ HRESULT LoopbackCapture(
175
195
hr = pAudioOutClient->Initialize (
176
196
AUDCLNT_SHAREMODE_SHARED,
177
197
0 ,
178
- ( REFERENCE_TIME) iBufferMs * 10000 ,
198
+ static_cast < REFERENCE_TIME>( iBufferMs) * 10000 ,
179
199
0 ,
180
200
pwfx,
181
201
NULL );
@@ -184,7 +204,7 @@ HRESULT LoopbackCapture(
184
204
return hr;
185
205
}
186
206
187
- IAudioRenderClient * pRenderClient;
207
+ IAudioRenderClient* pRenderClient;
188
208
hr = pAudioOutClient->GetService (
189
209
__uuidof (IAudioRenderClient),
190
210
(void **)&pRenderClient);
@@ -197,8 +217,8 @@ HRESULT LoopbackCapture(
197
217
return hr;
198
218
}
199
219
200
- // Grab the entire buffer for the initial fill operation.
201
- BYTE * tmp;
220
+ // Grab half the buffer for the initial fill operation.
221
+ BYTE* tmp;
202
222
hr = pRenderClient->GetBuffer (clientBufferFrameCount / 2 , &tmp);
203
223
if (FAILED (hr)) {
204
224
ERR (L" IAudioClient::GetBuffer failed (output): hr = 0x%08x" , hr);
@@ -242,75 +262,89 @@ HRESULT LoopbackCapture(
242
262
return E_UNEXPECTED;
243
263
}
244
264
245
- // get the captured data
246
- BYTE *pData;
247
- BYTE *pOutData;
248
- UINT32 nNumFramesToRead;
249
- DWORD dwFlags;
250
-
251
- hr = pAudioCaptureClient->GetBuffer (
252
- &pData,
253
- &nNumFramesToRead,
254
- &dwFlags,
255
- NULL ,
256
- NULL
257
- );
258
- if (FAILED (hr)) {
259
- ERR (L" IAudioCaptureClient::GetBuffer failed after %u frames: hr = 0x%08x" , *pnFrames, hr);
260
- return hr;
261
- }
265
+ for (;;) {
266
+ // get the captured data
267
+ BYTE* pData;
268
+ BYTE* pOutData;
269
+ UINT32 nNextPacketSize;
270
+ UINT32 nNumFramesToRead;
271
+ DWORD dwFlags;
272
+
273
+ hr = pAudioCaptureClient->GetNextPacketSize (&nNextPacketSize);
274
+ if (FAILED (hr)) {
275
+ ERR (L" IAudioCaptureClient::GetNextPacketSize failed after %u frames: hr = 0x%08x" , *pnFrames, hr);
276
+ return hr;
277
+ }
262
278
263
- if (AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY == dwFlags) {
264
- LOG (L" Probably spurious glitch reported after %u frames" , *pnFrames);
265
- }
266
- else if (0 != dwFlags) {
267
- LOG (L" IAudioCaptureClient::GetBuffer set flags to 0x%08x after %u frames" , dwFlags, *pnFrames);
268
- return E_UNEXPECTED;
269
- }
279
+ if (nNextPacketSize == 0 ) {
280
+ break ;
281
+ }
282
+
283
+ hr = pAudioCaptureClient->GetBuffer (
284
+ &pData,
285
+ &nNumFramesToRead,
286
+ &dwFlags,
287
+ NULL ,
288
+ NULL
289
+ );
290
+ if (FAILED (hr)) {
291
+ ERR (L" IAudioCaptureClient::GetBuffer failed after %u frames: hr = 0x%08x" , *pnFrames, hr);
292
+ return hr;
293
+ }
270
294
271
- nNumFramesToRead &= ~1 ;
295
+ if (nNextPacketSize != nNumFramesToRead) {
296
+ ERR (L" GetNextPacketSize and GetBuffer values don't match (%u and %u) after %u frames" , nNextPacketSize, nNumFramesToRead, *pnFrames);
297
+ return E_UNEXPECTED;
298
+ }
272
299
273
- if (0 == nNumFramesToRead) {
274
- LOG (L" IAudioCaptureClient::GetBuffer said to read 0 frames after %u frames" , *pnFrames);
275
- continue ;
276
- }
300
+ if (AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY == dwFlags) {
301
+ if (*pnFrames != 0 ) {
302
+ LOG (L" Probably spurious glitch reported after %u frames" , *pnFrames);
303
+ }
304
+ }
305
+ else if (0 != dwFlags) {
306
+ LOG (L" IAudioCaptureClient::GetBuffer set flags to 0x%08x after %u frames" , dwFlags, *pnFrames);
307
+ return E_UNEXPECTED;
308
+ }
277
309
278
- LONG lBytesToWrite = nNumFramesToRead * nBlockAlign;
310
+ if (nNumFramesToRead % 1 != 0 ) {
311
+ ERR (" frames to output is odd (%u), will miss the last sample after %u frames" , nNumFramesToRead, *pnFrames);
312
+ }
279
313
280
- for (;;) {
281
- hr = pRenderClient->GetBuffer (nNumFramesToRead / 2 , &pOutData);
282
- if (hr == AUDCLNT_E_BUFFER_TOO_LARGE) {
283
- ERR (L" %s" , L" buffer overflow!" );
284
- Sleep (1 );
285
- continue ;
314
+ UINT32 output_frames_to_write = nNumFramesToRead / 2 ;
315
+
316
+ LONG lBytesToWrite = output_frames_to_write * OutputBlockAlign;
317
+
318
+ for (;;) {
319
+ hr = pRenderClient->GetBuffer (output_frames_to_write, &pOutData);
320
+ if (hr == AUDCLNT_E_BUFFER_TOO_LARGE) {
321
+ ERR (L" %s" , L" buffer overflow!" );
322
+ Sleep (1 );
323
+ continue ;
324
+ }
325
+ if (FAILED (hr)) {
326
+ ERR (L" IAudioCaptureClient::GetBuffer failed (output) after %u frames: hr = 0x%08x" , *pnFrames, hr);
327
+ return hr;
328
+ }
329
+ break ;
286
330
}
331
+
332
+ swapMemcpy (pOutData, pData, lBytesToWrite, bSwapChannels, nBlockAlign);
333
+
334
+ hr = pRenderClient->ReleaseBuffer (output_frames_to_write, 0 );
287
335
if (FAILED (hr)) {
288
- ERR (L" IAudioCaptureClient::GetBuffer failed (output) after %u frames: hr = 0x%08x" , *pnFrames, hr);
336
+ ERR (L" IAudioCaptureClient::ReleaseBuffer failed (output) after %u frames: hr = 0x%08x" , *pnFrames, hr);
289
337
return hr;
290
338
}
291
- break ;
292
- }
293
-
294
- if (bSwapChannels) {
295
- swapMemcpy (pOutData, pData, lBytesToWrite, pwfx->wBitsPerSample / 8 );
296
- }
297
- else {
298
- memcpy (pOutData, pData, lBytesToWrite);
299
- }
300
339
301
- hr = pRenderClient ->ReleaseBuffer (nNumFramesToRead / 2 , 0 );
302
- if (FAILED (hr)) {
303
- ERR (L" IAudioCaptureClient::ReleaseBuffer failed (output) after %u frames: hr = 0x%08x" , *pnFrames, hr);
304
- return hr;
305
- }
340
+ hr = pAudioCaptureClient ->ReleaseBuffer (nNumFramesToRead);
341
+ if (FAILED (hr)) {
342
+ ERR (L" IAudioCaptureClient::ReleaseBuffer failed after %u frames: hr = 0x%08x" , *pnFrames, hr);
343
+ return hr;
344
+ }
306
345
307
- hr = pAudioCaptureClient->ReleaseBuffer (nNumFramesToRead);
308
- if (FAILED (hr)) {
309
- ERR (L" IAudioCaptureClient::ReleaseBuffer failed after %u frames: hr = 0x%08x" , *pnFrames, hr);
310
- return hr;
346
+ *pnFrames += nNumFramesToRead;
311
347
}
312
-
313
- *pnFrames += nNumFramesToRead;
314
348
} // capture loop
315
349
316
350
return hr;
0 commit comments