Commit ca7284fd authored by David Reid's avatar David Reid

ALSA: Fix an error where restarting a device can fail.

parent 22129652
...@@ -28024,6 +28024,12 @@ static ma_result ma_device_start__alsa(ma_device* pDevice) ...@@ -28024,6 +28024,12 @@ static ma_result ma_device_start__alsa(ma_device* pDevice)
static ma_result ma_device_stop__alsa(ma_device* pDevice) static ma_result ma_device_stop__alsa(ma_device* pDevice)
{ {
/*
The stop callback will get called on the worker thread after read/write__alsa() has returned. At this point there is
a small chance that our wakeupfd has not been cleared. We'll clear that out now if applicable.
*/
int resultPoll;
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_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Dropping capture device...\n"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Dropping capture device...\n");
((ma_snd_pcm_drop_proc)pDevice->pContext->alsa.snd_pcm_drop)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture); ((ma_snd_pcm_drop_proc)pDevice->pContext->alsa.snd_pcm_drop)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture);
...@@ -28036,6 +28042,13 @@ static ma_result ma_device_stop__alsa(ma_device* pDevice) ...@@ -28036,6 +28042,13 @@ static ma_result ma_device_stop__alsa(ma_device* pDevice)
} else { } else {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Preparing capture device successful.\n"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Preparing capture device successful.\n");
} }
/* Clear the wakeupfd. */
resultPoll = poll((struct pollfd*)pDevice->alsa.pPollDescriptorsCapture, 1, 0);
if (resultPoll > 0) {
ma_uint64 t;
read(((struct pollfd*)pDevice->alsa.pPollDescriptorsCapture)[0].fd, &t, sizeof(t));
}
} }
if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
...@@ -28050,6 +28063,14 @@ static ma_result ma_device_stop__alsa(ma_device* pDevice) ...@@ -28050,6 +28063,14 @@ static ma_result ma_device_stop__alsa(ma_device* pDevice)
} else { } else {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Preparing playback device successful.\n"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Preparing playback device successful.\n");
} }
/* Clear the wakeupfd. */
resultPoll = poll((struct pollfd*)pDevice->alsa.pPollDescriptorsPlayback, 1, 0);
if (resultPoll > 0) {
ma_uint64 t;
read(((struct pollfd*)pDevice->alsa.pPollDescriptorsPlayback)[0].fd, &t, sizeof(t));
}
} }
return MA_SUCCESS; return MA_SUCCESS;
...@@ -28062,7 +28083,7 @@ static ma_result ma_device_wait__alsa(ma_device* pDevice, ma_snd_pcm_t* pPCM, st ...@@ -28062,7 +28083,7 @@ static ma_result ma_device_wait__alsa(ma_device* pDevice, ma_snd_pcm_t* pPCM, st
int resultALSA; int resultALSA;
int resultPoll = poll(pPollDescriptors, pollDescriptorCount, -1); int resultPoll = poll(pPollDescriptors, pollDescriptorCount, -1);
if (resultPoll < 0) { if (resultPoll < 0) {
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] poll() failed."); ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] poll() failed.\n");
return ma_result_from_errno(errno); return ma_result_from_errno(errno);
} }
...@@ -28075,7 +28096,7 @@ static ma_result ma_device_wait__alsa(ma_device* pDevice, ma_snd_pcm_t* pPCM, st ...@@ -28075,7 +28096,7 @@ static ma_result ma_device_wait__alsa(ma_device* pDevice, ma_snd_pcm_t* pPCM, st
ma_uint64 t; ma_uint64 t;
int resultRead = read(pPollDescriptors[0].fd, &t, sizeof(t)); /* <-- Important that we read here so that the next write() does not block. */ int resultRead = read(pPollDescriptors[0].fd, &t, sizeof(t)); /* <-- Important that we read here so that the next write() does not block. */
if (resultRead < 0) { if (resultRead < 0) {
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] read() failed."); ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] read() failed.\n");
return ma_result_from_errno(errno); return ma_result_from_errno(errno);
} }
...@@ -28089,13 +28110,17 @@ static ma_result ma_device_wait__alsa(ma_device* pDevice, ma_snd_pcm_t* pPCM, st ...@@ -28089,13 +28110,17 @@ static ma_result ma_device_wait__alsa(ma_device* pDevice, ma_snd_pcm_t* pPCM, st
*/ */
resultALSA = ((ma_snd_pcm_poll_descriptors_revents_proc)pDevice->pContext->alsa.snd_pcm_poll_descriptors_revents)(pPCM, pPollDescriptors + 1, pollDescriptorCount - 1, &revents); /* +1, -1 to ignore the wakeup descriptor. */ resultALSA = ((ma_snd_pcm_poll_descriptors_revents_proc)pDevice->pContext->alsa.snd_pcm_poll_descriptors_revents)(pPCM, pPollDescriptors + 1, pollDescriptorCount - 1, &revents); /* +1, -1 to ignore the wakeup descriptor. */
if (resultALSA < 0) { if (resultALSA < 0) {
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_poll_descriptors_revents() failed."); ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_poll_descriptors_revents() failed.\n");
return ma_result_from_errno(-resultALSA); return ma_result_from_errno(-resultALSA);
} }
if ((revents & POLLERR) != 0) { if ((revents & POLLERR) != 0) {
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] POLLERR detected."); ma_snd_pcm_state_t state = ((ma_snd_pcm_state_proc)pDevice->pContext->alsa.snd_pcm_state)(pPCM);
return ma_result_from_errno(errno); if (state == MA_SND_PCM_STATE_XRUN) {
/* The PCM is in a xrun state. This will be recovered from at a higher level. We can disregard this. */
} else {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[ALSA] POLLERR detected. status = %d\n", ((ma_snd_pcm_state_proc)pDevice->pContext->alsa.snd_pcm_state)(pPCM));
}
} }
if ((revents & requiredEvent) == requiredEvent) { if ((revents & requiredEvent) == requiredEvent) {
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment