ALSA: Fix a bug where a playback device can fail to start.

This commit is contained in:
David Reid
2025-02-24 14:41:45 +10:00
parent 2a79d124c1
commit a65a7d139f
2 changed files with 18 additions and 4 deletions
+1
View File
@@ -21,6 +21,7 @@ v0.11.22 - TBD
* WASAPI: Fix an error when stopping the device where it was possible miniaudio would not wait for the device to be drained due to an error with the wait time calculation.
* WASAPI: Fix a COM related crash with device rerouting.
* DirectSound: Add support for specifying an explicit window handle for SetCooperativeLevel().
* ALSA: Fix a bug where a playback device can fail to start.
* ALSA: Fix some warnings relating to unhandled return value of `read()`.
* Web: Fix ScriptProcessorNode path when compiling with `--closure=1`. Note that the Audio Worklets path is not currently working due to the callback specified in `emscripten_create_wasm_audio_worklet_processor_async` never getting fired.
* Web: Fix an error with the unlocked notification when compiling as C++.
+16 -3
View File
@@ -28227,7 +28227,21 @@ static ma_result ma_device_start__alsa(ma_device* pDevice)
}
if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
/* Don't need to do anything for playback because it'll be started automatically when enough data has been written. */
/*
When data is written to the device we wait for the device to get ready to receive data with poll(). In my testing
I have observed that poll() can sometimes block forever unless the device is started explicitly with snd_pcm_start()
or some data is written with snd_pcm_writei().
To resolve this I've decided to do an explicit start with snd_pcm_start(). The problem with this is that the device
is started without any data in the internal buffer which will result in an immediate underrun. If instead we were
to call into snd_pcm_writei() in an attempt to prevent the underrun, we would run the risk of a weird deadlock
issue as documented inside ma_device_write__alsa().
*/
resultALSA = ((ma_snd_pcm_start_proc)pDevice->pContext->alsa.snd_pcm_start)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback);
if (resultALSA < 0) {
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to start playback device.");
return ma_result_from_errno(-resultALSA);
}
}
return MA_SUCCESS;
@@ -28288,7 +28302,6 @@ static ma_result ma_device_stop__alsa(ma_device* pDevice)
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Failed to read from playback wakeupfd. read() = %d\n", resultRead);
}
}
}
return MA_SUCCESS;
@@ -28314,7 +28327,7 @@ static ma_result ma_device_wait__alsa(ma_device* pDevice, ma_snd_pcm_t* pPCM, st
/*
Before checking the ALSA poll descriptor flag we need to check if the wakeup descriptor
has had it's POLLIN flag set. If so, we need to actually read the data and then exit
has had it's POLLIN flag set. If so, we need to actually read the data and then exit the
function. The wakeup descriptor will be the first item in the descriptors buffer.
*/
if ((pPollDescriptors[0].revents & POLLIN) != 0) {