mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-21 15:56:58 +02:00
Re-route lock moved outside ma_device_reinit__aaudio
Re-route lock moved outside ma_device_reinit__aaudio call to avoid potential race condition. Also cleaned up the reroute code a bit.
This commit is contained in:
+52
-46
@@ -38176,7 +38176,7 @@ static ma_result ma_close_streams__aaudio(ma_device* pDevice)
|
|||||||
{
|
{
|
||||||
MA_ASSERT(pDevice != NULL);
|
MA_ASSERT(pDevice != NULL);
|
||||||
|
|
||||||
/* When re-routing, streams may have been closed and never re-opened. Hence the extra checks below. */
|
/* When rerouting, streams may have been closed and never re-opened. Hence the extra checks below. */
|
||||||
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
|
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
|
||||||
ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture);
|
ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture);
|
||||||
pDevice->aaudio.pStreamCapture = NULL;
|
pDevice->aaudio.pStreamCapture = NULL;
|
||||||
@@ -38193,8 +38193,8 @@ static ma_result ma_device_uninit__aaudio(ma_device* pDevice)
|
|||||||
{
|
{
|
||||||
MA_ASSERT(pDevice != NULL);
|
MA_ASSERT(pDevice != NULL);
|
||||||
|
|
||||||
/* Note: Closing the streams may cause a timeout error, which would then trigger re-routing in our error callback.
|
/* Note: Closing the streams may cause a timeout error, which would then trigger rerouting in our error callback.
|
||||||
We must not schedule a re-route when device is getting destroyed.
|
We must not schedule a reroute when device is getting destroyed.
|
||||||
*/
|
*/
|
||||||
ma_atomic_bool32_set(&pDevice->aaudio.isTearingDown, MA_TRUE);
|
ma_atomic_bool32_set(&pDevice->aaudio.isTearingDown, MA_TRUE);
|
||||||
|
|
||||||
@@ -38205,7 +38205,7 @@ static ma_result ma_device_uninit__aaudio(ma_device* pDevice)
|
|||||||
}
|
}
|
||||||
ma_mutex_unlock(&pDevice->aaudio.rerouteLock);
|
ma_mutex_unlock(&pDevice->aaudio.rerouteLock);
|
||||||
|
|
||||||
/* Destroy re-routing lock. */
|
/* Destroy rerouting lock. */
|
||||||
ma_mutex_uninit(&pDevice->aaudio.rerouteLock);
|
ma_mutex_uninit(&pDevice->aaudio.rerouteLock);
|
||||||
|
|
||||||
return MA_SUCCESS;
|
return MA_SUCCESS;
|
||||||
@@ -38441,18 +38441,20 @@ static ma_result ma_device_stop__aaudio(ma_device* pDevice)
|
|||||||
|
|
||||||
static ma_result ma_device_reinit__aaudio(ma_device* pDevice, ma_device_type deviceType)
|
static ma_result ma_device_reinit__aaudio(ma_device* pDevice, ma_device_type deviceType)
|
||||||
{
|
{
|
||||||
|
const ma_int32 maxAttempts = 4; /* Reasonable retry limit. */
|
||||||
|
|
||||||
ma_result result;
|
ma_result result;
|
||||||
int32_t retries = 0;
|
ma_int32 iAttempt;
|
||||||
|
|
||||||
MA_ASSERT(pDevice != NULL);
|
MA_ASSERT(pDevice != NULL);
|
||||||
|
|
||||||
ma_mutex_lock(&pDevice->aaudio.rerouteLock);
|
/* We got disconnected! Retry a few times, until we find a connected device! */
|
||||||
{
|
iAttempt = 0;
|
||||||
error_disconnected:
|
while (iAttempt++ < maxAttempts) {
|
||||||
|
/* Device tearing down? No need to reroute! Callers should continue as normal. */
|
||||||
if (ma_atomic_bool32_get(&pDevice->aaudio.isTearingDown)) {
|
if (ma_atomic_bool32_get(&pDevice->aaudio.isTearingDown)) {
|
||||||
/* Device is tearing down. No need to re-route. Callers should continue as normal. */
|
|
||||||
result = MA_SUCCESS;
|
result = MA_SUCCESS;
|
||||||
goto done;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The first thing to do is close the streams. */
|
/* The first thing to do is close the streams. */
|
||||||
@@ -38510,44 +38512,45 @@ error_disconnected:
|
|||||||
result = ma_device_init_streams__aaudio(pDevice, &deviceConfig, &descriptorPlayback, &descriptorCapture);
|
result = ma_device_init_streams__aaudio(pDevice, &deviceConfig, &descriptorPlayback, &descriptorCapture);
|
||||||
if (result != MA_SUCCESS) {
|
if (result != MA_SUCCESS) {
|
||||||
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[AAudio] Failed to create stream after route change.");
|
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[AAudio] Failed to create stream after route change.");
|
||||||
goto done;
|
/* Reroute failed! */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = ma_device_post_init(pDevice, deviceType, &descriptorPlayback, &descriptorCapture);
|
result = ma_device_post_init(pDevice, deviceType, &descriptorPlayback, &descriptorCapture);
|
||||||
if (result != MA_SUCCESS) {
|
if (result != MA_SUCCESS) {
|
||||||
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[AAudio] Failed to initialize device after route change.");
|
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[AAudio] Failed to initialize device after route change.");
|
||||||
ma_close_streams__aaudio(pDevice);
|
ma_close_streams__aaudio(pDevice);
|
||||||
goto done;
|
/* Reroute failed! */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We'll only ever do this in response to a reroute. */
|
if (result == MA_SUCCESS) {
|
||||||
ma_device__on_notification_rerouted(pDevice);
|
/* We'll only ever do this in response to a reroute. */
|
||||||
|
ma_device__on_notification_rerouted(pDevice);
|
||||||
|
|
||||||
/* If the device is started, start the streams. Maybe make this configurable? */
|
/* If the device is started, start the streams. Maybe make this configurable? */
|
||||||
if (ma_device_get_state(pDevice) == ma_device_state_started) {
|
if (ma_device_get_state(pDevice) == ma_device_state_started) {
|
||||||
if (pDevice->aaudio.noAutoStartAfterReroute == MA_FALSE) {
|
if (pDevice->aaudio.noAutoStartAfterReroute == MA_FALSE) {
|
||||||
result = ma_device_start__aaudio(pDevice);
|
result = ma_device_start__aaudio(pDevice);
|
||||||
if (result != MA_SUCCESS) {
|
if (result != MA_SUCCESS) {
|
||||||
/* We got disconnected! Retry a few times, until we find a connected device! */
|
if (iAttempt < maxAttempts) {
|
||||||
retries += 1;
|
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Failed to start stream after route change, retrying(%d)", iAttempt);
|
||||||
if (retries <= 3) {
|
} else {
|
||||||
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Failed to start stream after route change, retrying(%d)", retries);
|
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Failed to start stream after route change, giving up.");
|
||||||
goto error_disconnected;
|
}
|
||||||
}
|
}
|
||||||
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Failed to start stream after route change.");
|
} else {
|
||||||
goto done;
|
ma_device_stop(pDevice); /* Do a full device stop so we set internal state correctly. */
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
ma_device_stop(pDevice); /* Do a full device stop so we set internal state correctly. */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result = MA_SUCCESS;
|
|
||||||
}
|
|
||||||
done:
|
|
||||||
/* Re-routing done */
|
|
||||||
ma_mutex_unlock(&pDevice->aaudio.rerouteLock);
|
|
||||||
|
|
||||||
|
if (result == MA_SUCCESS) {
|
||||||
|
/* Reroute successful! */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38713,7 +38716,7 @@ static ma_result ma_context_init__aaudio(ma_context* pContext, const ma_context_
|
|||||||
|
|
||||||
static ma_result ma_job_process__device__aaudio_reroute(ma_job* pJob)
|
static ma_result ma_job_process__device__aaudio_reroute(ma_job* pJob)
|
||||||
{
|
{
|
||||||
ma_result result;
|
ma_result result = MA_SUCCESS;
|
||||||
ma_device* pDevice;
|
ma_device* pDevice;
|
||||||
|
|
||||||
MA_ASSERT(pJob != NULL);
|
MA_ASSERT(pJob != NULL);
|
||||||
@@ -38721,19 +38724,22 @@ static ma_result ma_job_process__device__aaudio_reroute(ma_job* pJob)
|
|||||||
pDevice = (ma_device*)pJob->data.device.aaudio.reroute.pDevice;
|
pDevice = (ma_device*)pJob->data.device.aaudio.reroute.pDevice;
|
||||||
MA_ASSERT(pDevice != NULL);
|
MA_ASSERT(pDevice != NULL);
|
||||||
|
|
||||||
/* Here is where we need to reroute the device. To do this we need to uninitialize the stream and reinitialize it. */
|
ma_mutex_lock(&pDevice->aaudio.rerouteLock);
|
||||||
result = ma_device_reinit__aaudio(pDevice, (ma_device_type)pJob->data.device.aaudio.reroute.deviceType);
|
{
|
||||||
if (result != MA_SUCCESS) {
|
/* Here is where we need to reroute the device. To do this we need to uninitialize the stream and reinitialize it. */
|
||||||
/*
|
result = ma_device_reinit__aaudio(pDevice, (ma_device_type)pJob->data.device.aaudio.reroute.deviceType);
|
||||||
Getting here means we failed to reroute the device. The best thing I can think of here is to
|
if (result != MA_SUCCESS) {
|
||||||
just stop the device.
|
/*
|
||||||
*/
|
Getting here means we failed to reroute the device. The best thing I can think of here is to
|
||||||
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[AAudio] Stopping device due to reroute failure.");
|
just stop the device.
|
||||||
ma_device_stop(pDevice);
|
*/
|
||||||
return result;
|
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[AAudio] Stopping device due to reroute failure.");
|
||||||
|
ma_device_stop(pDevice);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
ma_mutex_unlock(&pDevice->aaudio.rerouteLock);
|
||||||
|
|
||||||
return MA_SUCCESS;
|
return result;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
/* Getting here means there is no AAudio backend so we need a no-op job implementation. */
|
/* Getting here means there is no AAudio backend so we need a no-op job implementation. */
|
||||||
|
|||||||
Reference in New Issue
Block a user