Skip to content
This repository has been archived by the owner on Feb 15, 2024. It is now read-only.

Commit

Permalink
switch audio input capture to event based
Browse files Browse the repository at this point in the history
  • Loading branch information
ToadKing committed Aug 3, 2020
1 parent d28d70d commit 57e3d0a
Showing 1 changed file with 80 additions and 113 deletions.
193 changes: 80 additions & 113 deletions mono-to-stereo/mono-to-stereo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,26 +101,13 @@ HRESULT LoopbackCapture(

pwfx->nBlockAlign = pwfx->nChannels * pwfx->wBitsPerSample / 8;

// create a periodic waitable timer
HANDLE hWakeUp = CreateWaitableTimer(NULL, FALSE, NULL);
if (NULL == hWakeUp) {
DWORD dwErr = GetLastError();
ERR(L"CreateWaitableTimer failed: last error = %u", dwErr);
return HRESULT_FROM_WIN32(dwErr);
}
CloseHandleOnExit closeWakeUp(hWakeUp);

UINT32 nBlockAlign = pwfx->nBlockAlign;
*pnFrames = 0;

// call IAudioClient::Initialize
// note that AUDCLNT_STREAMFLAGS_LOOPBACK and AUDCLNT_STREAMFLAGS_EVENTCALLBACK
// do not work together...
// the "data ready" event never gets set
// so we're going to do a timer-driven loop
hr = pAudioClient->Initialize(
AUDCLNT_SHAREMODE_SHARED,
0,
AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
0, 0, pwfx, 0
);
if (FAILED(hr)) {
Expand Down Expand Up @@ -150,22 +137,17 @@ HRESULT LoopbackCapture(
}
AvRevertMmThreadCharacteristicsOnExit unregisterMmcss(hTask);

// set the waitable timer
LARGE_INTEGER liFirstFire;
liFirstFire.QuadPart = -hnsDefaultDevicePeriod / 2; // negative means relative time
LONG lTimeBetweenFires = (LONG)hnsDefaultDevicePeriod / 2 / (10 * 1000); // convert to milliseconds
BOOL bOK = SetWaitableTimer(
hWakeUp,
&liFirstFire,
lTimeBetweenFires,
NULL, NULL, FALSE
);
if (!bOK) {
// create the event timer
HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (hEvent == NULL)
{
DWORD dwErr = GetLastError();
ERR(L"SetWaitableTimer failed: last error = %u", dwErr);
ERR(L"CreateEvent failed: last error = %u", dwErr);
return HRESULT_FROM_WIN32(dwErr);
}
CancelWaitableTimerOnExit cancelWakeUp(hWakeUp);
CloseHandleOnExit closeEvent(hEvent);

pAudioClient->SetEventHandle(hEvent);

// call IAudioClient::Start
hr = pAudioClient->Start();
Expand Down Expand Up @@ -193,8 +175,8 @@ HRESULT LoopbackCapture(
hr = pAudioOutClient->Initialize(
AUDCLNT_SHAREMODE_SHARED,
0,
iBufferMs * 10000,
iBufferMs * 10000,
(REFERENCE_TIME)iBufferMs * 10000,
0,
pwfx,
NULL);
if (FAILED(hr)) {
Expand Down Expand Up @@ -238,112 +220,97 @@ HRESULT LoopbackCapture(
SetEvent(hStartedEvent);

// loopback capture loop
HANDLE waitArray[2] = { hStopEvent, hWakeUp };
HANDLE waitArray[2] = { hStopEvent, hEvent };
DWORD dwWaitResult;

bool bDone = false;
bool bFirstPacket = true;
for (UINT32 nPasses = 0; !bDone; nPasses++) {
// drain data while it is available
UINT32 nNextPacketSize;
for (
hr = pAudioCaptureClient->GetNextPacketSize(&nNextPacketSize);
SUCCEEDED(hr) && nNextPacketSize > 0;
hr = pAudioCaptureClient->GetNextPacketSize(&nNextPacketSize)
) {
// get the captured data
BYTE *pData;
BYTE *pOutData;
UINT32 nNumFramesToRead;
DWORD dwFlags;

hr = pAudioCaptureClient->GetBuffer(
&pData,
&nNumFramesToRead,
&dwFlags,
NULL,
NULL
);
if (FAILED(hr)) {
ERR(L"IAudioCaptureClient::GetBuffer failed on pass %u after %u frames: hr = 0x%08x", nPasses, *pnFrames, hr);
return hr;
}

if (AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY == dwFlags) {
LOG(L"Probably spurious glitch reported on pass %u after %u frames", nPasses, *pnFrames);
}
else if (0 != dwFlags) {
LOG(L"IAudioCaptureClient::GetBuffer set flags to 0x%08x on pass %u after %u frames", dwFlags, nPasses, *pnFrames);
return E_UNEXPECTED;
}
while (!bDone) {
dwWaitResult = WaitForMultipleObjects(
ARRAYSIZE(waitArray), waitArray,
FALSE, INFINITE
);

nNumFramesToRead &= ~1;
if (WAIT_OBJECT_0 == dwWaitResult) {
LOG(L"Received stop event after %u frames", *pnFrames);
bDone = true;
continue; // exits loop
}

if (0 == nNumFramesToRead) {
ERR(L"IAudioCaptureClient::GetBuffer said to read 0 frames on pass %u after %u frames", nPasses, *pnFrames);
return E_UNEXPECTED;
}
if (WAIT_OBJECT_0 + 1 != dwWaitResult) {
ERR(L"Unexpected WaitForMultipleObjects return value %u after %u frames", dwWaitResult, *pnFrames);
return E_UNEXPECTED;
}

LONG lBytesToWrite = nNumFramesToRead * nBlockAlign;

for (;;) {
hr = pRenderClient->GetBuffer(nNumFramesToRead / 2, &pOutData);
if (hr == AUDCLNT_E_BUFFER_TOO_LARGE) {
ERR(L"%s", L"buffer overflow!");
Sleep(1);
continue;
}
if (FAILED(hr)) {
ERR(L"IAudioCaptureClient::GetBuffer failed (output) on pass %u after %u frames: hr = 0x%08x", nPasses, *pnFrames, hr);
return hr;
}
break;
}
// get the captured data
BYTE *pData;
BYTE *pOutData;
UINT32 nNumFramesToRead;
DWORD dwFlags;

hr = pAudioCaptureClient->GetBuffer(
&pData,
&nNumFramesToRead,
&dwFlags,
NULL,
NULL
);
if (FAILED(hr)) {
ERR(L"IAudioCaptureClient::GetBuffer failed after %u frames: hr = 0x%08x", *pnFrames, hr);
return hr;
}

if (bSwapChannels) {
swapMemcpy(pOutData, pData, lBytesToWrite, nBlockAlign);
}
else {
memcpy(pOutData, pData, lBytesToWrite);
}
if (AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY == dwFlags) {
LOG(L"Probably spurious glitch reported after %u frames", *pnFrames);
}
else if (0 != dwFlags) {
LOG(L"IAudioCaptureClient::GetBuffer set flags to 0x%08x after %u frames", dwFlags, *pnFrames);
return E_UNEXPECTED;
}

hr = pRenderClient->ReleaseBuffer(nNumFramesToRead / 2, 0);
if (FAILED(hr)) {
ERR(L"IAudioCaptureClient::ReleaseBuffer failed (output) on pass %u after %u frames: hr = 0x%08x", nPasses, *pnFrames, hr);
return hr;
}
nNumFramesToRead &= ~1;

if (0 == nNumFramesToRead) {
LOG(L"IAudioCaptureClient::GetBuffer said to read 0 frames after %u frames", *pnFrames);
continue;
}

LONG lBytesToWrite = nNumFramesToRead * nBlockAlign;

hr = pAudioCaptureClient->ReleaseBuffer(nNumFramesToRead);
for (;;) {
hr = pRenderClient->GetBuffer(nNumFramesToRead / 2, &pOutData);
if (hr == AUDCLNT_E_BUFFER_TOO_LARGE) {
ERR(L"%s", L"buffer overflow!");
Sleep(1);
continue;
}
if (FAILED(hr)) {
ERR(L"IAudioCaptureClient::ReleaseBuffer failed on pass %u after %u frames: hr = 0x%08x", nPasses, *pnFrames, hr);
ERR(L"IAudioCaptureClient::GetBuffer failed (output) after %u frames: hr = 0x%08x", *pnFrames, hr);
return hr;
}
break;
}

*pnFrames += nNumFramesToRead;

bFirstPacket = false;
if (bSwapChannels) {
swapMemcpy(pOutData, pData, lBytesToWrite, pwfx->wBitsPerSample / 8);
}
else {
memcpy(pOutData, pData, lBytesToWrite);
}

hr = pRenderClient->ReleaseBuffer(nNumFramesToRead / 2, 0);
if (FAILED(hr)) {
ERR(L"IAudioCaptureClient::GetNextPacketSize failed on pass %u after %u frames: hr = 0x%08x", nPasses, *pnFrames, hr);
ERR(L"IAudioCaptureClient::ReleaseBuffer failed (output) after %u frames: hr = 0x%08x", *pnFrames, hr);
return hr;
}

dwWaitResult = WaitForMultipleObjects(
ARRAYSIZE(waitArray), waitArray,
FALSE, INFINITE
);

if (WAIT_OBJECT_0 == dwWaitResult) {
LOG(L"Received stop event after %u passes and %u frames", nPasses, *pnFrames);
bDone = true;
continue; // exits loop
hr = pAudioCaptureClient->ReleaseBuffer(nNumFramesToRead);
if (FAILED(hr)) {
ERR(L"IAudioCaptureClient::ReleaseBuffer failed after %u frames: hr = 0x%08x", *pnFrames, hr);
return hr;
}

if (WAIT_OBJECT_0 + 1 != dwWaitResult) {
ERR(L"Unexpected WaitForMultipleObjects return value %u on pass %u after %u frames", dwWaitResult, nPasses, *pnFrames);
return E_UNEXPECTED;
}
*pnFrames += nNumFramesToRead;
} // capture loop

return hr;
Expand Down

0 comments on commit 57e3d0a

Please sign in to comment.