/*HANDLE*/ mal_handle hEventPlayback; /* Auto reset. Initialized to signaled. */
/*HANDLE*/ mal_handle hEventCapture; /* Auto reset. Initialized to unsignaled. */
void* pDeviceBufferPlayback;
void* pDeviceBufferCapture;
mal_uint32 deviceBufferFramesRemainingPlayback;
mal_uint32 deviceBufferFramesRemainingCapture;
mal_uint32 deviceBufferFramesCapacityPlayback;
mal_uint32 deviceBufferFramesCapacityCapture;
mal_uint32 periodSizeInFramesPlayback;
mal_uint32 periodSizeInFramesCapture;
mal_uint32 actualBufferSizeInFramesPlayback; /* Value from GetBufferSize(). internalBufferSizeInFrames is not set to the _actual_ buffer size when low-latency shared mode is being used due to the way the IAudioClient3 API works. */
mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[WASAPI] Failed to release internal buffer from playback device after writing to the device.", result);
break;
}
ResetEvent(pDevice->wasapi.hEventPlayback);
/*
After releasing the buffer, if the device is not started we need to do so. Note from MSDN:
The event handle should be in the nonsignaled state at the time that the client calls the Start method.
This means we should start the device only after setting the event to non-signaled (after the call to ResetEvent()).
*/
if (!pDevice->wasapi.isStarted && !wasStartedOnEntry) {
result = mal_device_start__wasapi(pDevice);
if (result != MAL_SUCCESS) {
break;
}
}
}
mal_assert(totalFramesWritten <= frameCount);
if (totalFramesWritten == frameCount) {
break;
}
/* Wait for data to become available. Exclusive mode is slightly different. We always wait and then use the exact frame count returned by GetCurrentPadding(). */
for (;;) {
if (pDevice->playback.shareMode == mal_share_mode_exclusive) {
break; /* An error occurred while waiting for the event. */
}
}
/* If the device has been stopped don't continue. */
if (!pDevice->wasapi.isStarted && wasStartedOnEntry) {
exitOuterLoop = MAL_TRUE;
break;
}
/* We may need to reroute the device. */
if (mal_device_is_reroute_required__wasapi(pDevice, mal_device_type_playback)) {
result = mal_device_reroute__wasapi(pDevice, mal_device_type_playback);
if (result != MAL_SUCCESS) {
exitOuterLoop = MAL_TRUE;
break;
}
}
/*
Check what's available. If there's not enough data available we need to wait. How much data must be available depends on whether or not the
device is in playback-only mode or duplex mode. In playback-only mode we only care about a period being available. In duplex mode we want at
least a whole period in the buffer ready for playback in addition to a whole period being available.
*/
result = mal_device__get_available_frames__wasapi(pDevice, (mal_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &pDevice->wasapi.deviceBufferFramesCapacityPlayback);
if (result != MAL_SUCCESS) {
exitOuterLoop = MAL_TRUE;
break;
}
/* In exclusive mode, the frame count needs to exactly match the value returned by GetCurrentPadding(). */
if (pDevice->playback.shareMode == mal_share_mode_exclusive && pDevice->wasapi.deviceBufferFramesCapacityPlayback > 0) {
mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from playback device in preparation for writing to the device.", result);
waitResult = WaitForSingleObject(pDevice->wasapi.hEventPlayback, INFINITE); /* Wait on the exclusive-mode playback event instead. */
}
}
if (waitResult == WAIT_FAILED) {
result = MAL_ERROR;
break; /* An error occurred while waiting for the event. */
}
/* If the device has been stopped don't continue. */
if (!pDevice->wasapi.isStarted) {
break;
}
/* We may need to reroute the device. */
if (mal_device_is_reroute_required__wasapi(pDevice, mal_device_type_capture)) {
result = mal_device_reroute__wasapi(pDevice, mal_device_type_capture);
if (result != MAL_SUCCESS) {
break;
}
}
/* The device buffer has become available, so now we need to get a pointer to it. */
result = mal_device__get_available_frames__wasapi(pDevice, (mal_IAudioClient*)pDevice->wasapi.pAudioClientCapture, &pDevice->wasapi.deviceBufferFramesCapacityCapture);
mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from capture device in preparation for writing to the device.", result);