mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-24 01:04:02 +02:00
WASAPI: Don't stop the device while in the middle of rerouting.
Public issue https://github.com/mackron/miniaudio/issues/582
This commit is contained in:
+41
-36
@@ -41247,54 +41247,59 @@ MA_API ma_result ma_device_stop(ma_device* pDevice)
|
|||||||
return MA_SUCCESS; /* Already stopped. */
|
return MA_SUCCESS; /* Already stopped. */
|
||||||
}
|
}
|
||||||
|
|
||||||
ma_mutex_lock(&pDevice->startStopLock);
|
/* Wait for any rerouting to finish before attempting to stop the device. */
|
||||||
|
ma_mutex_lock(&pDevice->wasapi.rerouteLock);
|
||||||
{
|
{
|
||||||
/* Starting and stopping are wrapped in a mutex which means we can assert that the device is in a started or paused state. */
|
ma_mutex_lock(&pDevice->startStopLock);
|
||||||
MA_ASSERT(ma_device_get_state(pDevice) == ma_device_state_started);
|
{
|
||||||
|
/* Starting and stopping are wrapped in a mutex which means we can assert that the device is in a started or paused state. */
|
||||||
|
MA_ASSERT(ma_device_get_state(pDevice) == ma_device_state_started);
|
||||||
|
|
||||||
ma_device__set_state(pDevice, ma_device_state_stopping);
|
ma_device__set_state(pDevice, ma_device_state_stopping);
|
||||||
|
|
||||||
/* Asynchronous backends need to be handled differently. */
|
/* Asynchronous backends need to be handled differently. */
|
||||||
if (ma_context_is_backend_asynchronous(pDevice->pContext)) {
|
if (ma_context_is_backend_asynchronous(pDevice->pContext)) {
|
||||||
/* Asynchronous backends must have a stop operation. */
|
/* Asynchronous backends must have a stop operation. */
|
||||||
if (pDevice->pContext->callbacks.onDeviceStop != NULL) {
|
if (pDevice->pContext->callbacks.onDeviceStop != NULL) {
|
||||||
result = pDevice->pContext->callbacks.onDeviceStop(pDevice);
|
result = pDevice->pContext->callbacks.onDeviceStop(pDevice);
|
||||||
|
} else {
|
||||||
|
result = MA_INVALID_OPERATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
ma_device__set_state(pDevice, ma_device_state_stopped);
|
||||||
} else {
|
} else {
|
||||||
result = MA_INVALID_OPERATION;
|
/*
|
||||||
}
|
Synchronous backends. The stop callback is always called from the worker thread. Do not call the stop callback here. If
|
||||||
|
the backend is implementing it's own audio thread loop we'll need to wake it up if required. Note that we need to make
|
||||||
|
sure the state of the device is *not* playing right now, which it shouldn't be since we set it above. This is super
|
||||||
|
important though, so I'm asserting it here as well for extra safety in case we accidentally change something later.
|
||||||
|
*/
|
||||||
|
MA_ASSERT(ma_device_get_state(pDevice) != ma_device_state_started);
|
||||||
|
|
||||||
ma_device__set_state(pDevice, ma_device_state_stopped);
|
if (pDevice->pContext->callbacks.onDeviceDataLoopWakeup != NULL) {
|
||||||
} else {
|
pDevice->pContext->callbacks.onDeviceDataLoopWakeup(pDevice);
|
||||||
/*
|
}
|
||||||
Synchronous backends. The stop callback is always called from the worker thread. Do not call the stop callback here. If
|
|
||||||
the backend is implementing it's own audio thread loop we'll need to wake it up if required. Note that we need to make
|
|
||||||
sure the state of the device is *not* playing right now, which it shouldn't be since we set it above. This is super
|
|
||||||
important though, so I'm asserting it here as well for extra safety in case we accidentally change something later.
|
|
||||||
*/
|
|
||||||
MA_ASSERT(ma_device_get_state(pDevice) != ma_device_state_started);
|
|
||||||
|
|
||||||
if (pDevice->pContext->callbacks.onDeviceDataLoopWakeup != NULL) {
|
/*
|
||||||
pDevice->pContext->callbacks.onDeviceDataLoopWakeup(pDevice);
|
We need to wait for the worker thread to become available for work before returning. Note that the worker thread will be
|
||||||
|
the one who puts the device into the stopped state. Don't call ma_device__set_state() here.
|
||||||
|
*/
|
||||||
|
ma_event_wait(&pDevice->stopEvent);
|
||||||
|
result = MA_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
We need to wait for the worker thread to become available for work before returning. Note that the worker thread will be
|
This is a safety measure to ensure the internal buffer has been cleared so any leftover
|
||||||
the one who puts the device into the stopped state. Don't call ma_device__set_state() here.
|
does not get played the next time the device starts. Ideally this should be drained by
|
||||||
|
the backend first.
|
||||||
*/
|
*/
|
||||||
ma_event_wait(&pDevice->stopEvent);
|
pDevice->playback.intermediaryBufferLen = 0;
|
||||||
result = MA_SUCCESS;
|
pDevice->playback.inputCacheConsumed = 0;
|
||||||
|
pDevice->playback.inputCacheRemaining = 0;
|
||||||
}
|
}
|
||||||
|
ma_mutex_unlock(&pDevice->startStopLock);
|
||||||
/*
|
|
||||||
This is a safety measure to ensure the internal buffer has been cleared so any leftover
|
|
||||||
does not get played the next time the device starts. Ideally this should be drained by
|
|
||||||
the backend first.
|
|
||||||
*/
|
|
||||||
pDevice->playback.intermediaryBufferLen = 0;
|
|
||||||
pDevice->playback.inputCacheConsumed = 0;
|
|
||||||
pDevice->playback.inputCacheRemaining = 0;
|
|
||||||
}
|
}
|
||||||
ma_mutex_unlock(&pDevice->startStopLock);
|
ma_mutex_unlock(&pDevice->wasapi.rerouteLock);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user