Skip to content

Commit a65a7d1

Browse files
committed
ALSA: Fix a bug where a playback device can fail to start.
1 parent 2a79d12 commit a65a7d1

File tree

2 files changed

+18
-4
lines changed

2 files changed

+18
-4
lines changed

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ v0.11.22 - TBD
2121
* 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.
2222
* WASAPI: Fix a COM related crash with device rerouting.
2323
* DirectSound: Add support for specifying an explicit window handle for SetCooperativeLevel().
24+
* ALSA: Fix a bug where a playback device can fail to start.
2425
* ALSA: Fix some warnings relating to unhandled return value of `read()`.
2526
* 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.
2627
* Web: Fix an error with the unlocked notification when compiling as C++.

miniaudio.h

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28227,7 +28227,21 @@ static ma_result ma_device_start__alsa(ma_device* pDevice)
2822728227
}
2822828228

2822928229
if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
28230-
/* Don't need to do anything for playback because it'll be started automatically when enough data has been written. */
28230+
/*
28231+
When data is written to the device we wait for the device to get ready to receive data with poll(). In my testing
28232+
I have observed that poll() can sometimes block forever unless the device is started explicitly with snd_pcm_start()
28233+
or some data is written with snd_pcm_writei().
28234+
28235+
To resolve this I've decided to do an explicit start with snd_pcm_start(). The problem with this is that the device
28236+
is started without any data in the internal buffer which will result in an immediate underrun. If instead we were
28237+
to call into snd_pcm_writei() in an attempt to prevent the underrun, we would run the risk of a weird deadlock
28238+
issue as documented inside ma_device_write__alsa().
28239+
*/
28240+
resultALSA = ((ma_snd_pcm_start_proc)pDevice->pContext->alsa.snd_pcm_start)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback);
28241+
if (resultALSA < 0) {
28242+
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to start playback device.");
28243+
return ma_result_from_errno(-resultALSA);
28244+
}
2823128245
}
2823228246

2823328247
return MA_SUCCESS;
@@ -28288,7 +28302,6 @@ static ma_result ma_device_stop__alsa(ma_device* pDevice)
2828828302
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Failed to read from playback wakeupfd. read() = %d\n", resultRead);
2828928303
}
2829028304
}
28291-
2829228305
}
2829328306

2829428307
return MA_SUCCESS;
@@ -28314,7 +28327,7 @@ static ma_result ma_device_wait__alsa(ma_device* pDevice, ma_snd_pcm_t* pPCM, st
2831428327

2831528328
/*
2831628329
Before checking the ALSA poll descriptor flag we need to check if the wakeup descriptor
28317-
has had it's POLLIN flag set. If so, we need to actually read the data and then exit
28330+
has had it's POLLIN flag set. If so, we need to actually read the data and then exit the
2831828331
function. The wakeup descriptor will be the first item in the descriptors buffer.
2831928332
*/
2832028333
if ((pPollDescriptors[0].revents & POLLIN) != 0) {
@@ -28343,7 +28356,7 @@ static ma_result ma_device_wait__alsa(ma_device* pDevice, ma_snd_pcm_t* pPCM, st
2834328356
ma_snd_pcm_state_t state = ((ma_snd_pcm_state_proc)pDevice->pContext->alsa.snd_pcm_state)(pPCM);
2834428357
if (state == MA_SND_PCM_STATE_XRUN) {
2834528358
/* The PCM is in a xrun state. This will be recovered from at a higher level. We can disregard this. */
28346-
} else {
28359+
} else {
2834728360
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));
2834828361
}
2834928362
}

0 commit comments

Comments
 (0)