Commit 50c9081b authored by David Reid's avatar David Reid

Fix some data race errors in the PulseAudio backend.

Public issue https://github.com/mackron/miniaudio/issues/235
parent 6ac68d44
...@@ -21480,9 +21480,7 @@ static ma_result ma_wait_for_operation__pulse(ma_context* pContext, ma_pa_operat ...@@ -21480,9 +21480,7 @@ static ma_result ma_wait_for_operation__pulse(ma_context* pContext, ma_pa_operat
for (;;) { for (;;) {
ma_mainloop_lock__pulse(pContext, "ma_wait_for_operation__pulse"); ma_mainloop_lock__pulse(pContext, "ma_wait_for_operation__pulse");
{
state = ((ma_pa_operation_get_state_proc)pContext->pulse.pa_operation_get_state)(pOP); state = ((ma_pa_operation_get_state_proc)pContext->pulse.pa_operation_get_state)(pOP);
}
ma_mainloop_unlock__pulse(pContext, "ma_wait_for_operation__pulse"); ma_mainloop_unlock__pulse(pContext, "ma_wait_for_operation__pulse");
if (state != MA_PA_OPERATION_RUNNING) { if (state != MA_PA_OPERATION_RUNNING) {
...@@ -21515,9 +21513,7 @@ static ma_result ma_context_wait_for_pa_context_to_connect__pulse(ma_context* pC ...@@ -21515,9 +21513,7 @@ static ma_result ma_context_wait_for_pa_context_to_connect__pulse(ma_context* pC
for (;;) { for (;;) {
ma_mainloop_lock__pulse(pContext, "ma_context_wait_for_pa_context_to_connect__pulse"); ma_mainloop_lock__pulse(pContext, "ma_context_wait_for_pa_context_to_connect__pulse");
{
state = ((ma_pa_context_get_state_proc)pContext->pulse.pa_context_get_state)((ma_pa_context*)pContext->pulse.pPulseContext); state = ((ma_pa_context_get_state_proc)pContext->pulse.pa_context_get_state)((ma_pa_context*)pContext->pulse.pPulseContext);
}
ma_mainloop_unlock__pulse(pContext, "ma_context_wait_for_pa_context_to_connect__pulse"); ma_mainloop_unlock__pulse(pContext, "ma_context_wait_for_pa_context_to_connect__pulse");
if (state == MA_PA_CONTEXT_READY) { if (state == MA_PA_CONTEXT_READY) {
...@@ -21541,9 +21537,7 @@ static ma_result ma_context_wait_for_pa_stream_to_connect__pulse(ma_context* pCo ...@@ -21541,9 +21537,7 @@ static ma_result ma_context_wait_for_pa_stream_to_connect__pulse(ma_context* pCo
for (;;) { for (;;) {
ma_mainloop_lock__pulse(pContext, "ma_context_wait_for_pa_stream_to_connect__pulse"); ma_mainloop_lock__pulse(pContext, "ma_context_wait_for_pa_stream_to_connect__pulse");
{
state = ((ma_pa_stream_get_state_proc)pContext->pulse.pa_stream_get_state)(pStream); state = ((ma_pa_stream_get_state_proc)pContext->pulse.pa_stream_get_state)(pStream);
}
ma_mainloop_unlock__pulse(pContext, "ma_context_wait_for_pa_stream_to_connect__pulse"); ma_mainloop_unlock__pulse(pContext, "ma_context_wait_for_pa_stream_to_connect__pulse");
if (state == MA_PA_STREAM_READY) { if (state == MA_PA_STREAM_READY) {
...@@ -21630,7 +21624,10 @@ static ma_result ma_context_get_sink_info__pulse(ma_context* pContext, const cha ...@@ -21630,7 +21624,10 @@ static ma_result ma_context_get_sink_info__pulse(ma_context* pContext, const cha
{ {
ma_pa_operation* pOP; ma_pa_operation* pOP;
ma_mainloop_lock__pulse(pContext, "ma_context_get_sink_info__pulse");
pOP = ((ma_pa_context_get_sink_info_by_name_proc)pContext->pulse.pa_context_get_sink_info_by_name)((ma_pa_context*)pContext->pulse.pPulseContext, pDeviceName, ma_device_sink_info_callback, pSinkInfo); pOP = ((ma_pa_context_get_sink_info_by_name_proc)pContext->pulse.pa_context_get_sink_info_by_name)((ma_pa_context*)pContext->pulse.pPulseContext, pDeviceName, ma_device_sink_info_callback, pSinkInfo);
ma_mainloop_unlock__pulse(pContext, "ma_context_get_sink_info__pulse");
if (pOP == NULL) { if (pOP == NULL) {
return MA_ERROR; return MA_ERROR;
} }
...@@ -21643,7 +21640,10 @@ static ma_result ma_context_get_source_info__pulse(ma_context* pContext, const c ...@@ -21643,7 +21640,10 @@ static ma_result ma_context_get_source_info__pulse(ma_context* pContext, const c
{ {
ma_pa_operation* pOP; ma_pa_operation* pOP;
ma_mainloop_lock__pulse(pContext, "ma_context_get_source_info__pulse");
pOP = ((ma_pa_context_get_source_info_by_name_proc)pContext->pulse.pa_context_get_source_info_by_name)((ma_pa_context*)pContext->pulse.pPulseContext, pDeviceName, ma_device_source_info_callback, pSourceInfo); pOP = ((ma_pa_context_get_source_info_by_name_proc)pContext->pulse.pa_context_get_source_info_by_name)((ma_pa_context*)pContext->pulse.pPulseContext, pDeviceName, ma_device_source_info_callback, pSourceInfo);
ma_mainloop_unlock__pulse(pContext, "ma_context_get_source_info__pulse");
if (pOP == NULL) { if (pOP == NULL) {
return MA_ERROR; return MA_ERROR;
} }
...@@ -21787,7 +21787,10 @@ static ma_result ma_context_enumerate_devices__pulse(ma_context* pContext, ma_en ...@@ -21787,7 +21787,10 @@ static ma_result ma_context_enumerate_devices__pulse(ma_context* pContext, ma_en
/* Playback. */ /* Playback. */
if (!callbackData.isTerminated) { if (!callbackData.isTerminated) {
ma_mainloop_lock__pulse(pContext, "ma_context_enumerate_devices__pulse");
pOP = ((ma_pa_context_get_sink_info_list_proc)pContext->pulse.pa_context_get_sink_info_list)((ma_pa_context*)(pContext->pulse.pPulseContext), ma_context_enumerate_devices_sink_callback__pulse, &callbackData); pOP = ((ma_pa_context_get_sink_info_list_proc)pContext->pulse.pa_context_get_sink_info_list)((ma_pa_context*)(pContext->pulse.pPulseContext), ma_context_enumerate_devices_sink_callback__pulse, &callbackData);
ma_mainloop_unlock__pulse(pContext, "ma_context_enumerate_devices__pulse");
if (pOP == NULL) { if (pOP == NULL) {
result = MA_ERROR; result = MA_ERROR;
goto done; goto done;
...@@ -21803,7 +21806,10 @@ static ma_result ma_context_enumerate_devices__pulse(ma_context* pContext, ma_en ...@@ -21803,7 +21806,10 @@ static ma_result ma_context_enumerate_devices__pulse(ma_context* pContext, ma_en
/* Capture. */ /* Capture. */
if (!callbackData.isTerminated) { if (!callbackData.isTerminated) {
ma_mainloop_lock__pulse(pContext, "ma_context_enumerate_devices__pulse");
pOP = ((ma_pa_context_get_source_info_list_proc)pContext->pulse.pa_context_get_source_info_list)((ma_pa_context*)(pContext->pulse.pPulseContext), ma_context_enumerate_devices_source_callback__pulse, &callbackData); pOP = ((ma_pa_context_get_source_info_list_proc)pContext->pulse.pa_context_get_source_info_list)((ma_pa_context*)(pContext->pulse.pPulseContext), ma_context_enumerate_devices_source_callback__pulse, &callbackData);
ma_mainloop_unlock__pulse(pContext, "ma_context_enumerate_devices__pulse");
if (pOP == NULL) { if (pOP == NULL) {
result = MA_ERROR; result = MA_ERROR;
goto done; goto done;
...@@ -21912,11 +21918,13 @@ static ma_result ma_context_get_device_info__pulse(ma_context* pContext, ma_devi ...@@ -21912,11 +21918,13 @@ static ma_result ma_context_get_device_info__pulse(ma_context* pContext, ma_devi
result = ma_context_get_default_device_index__pulse(pContext, deviceType, &callbackData.defaultDeviceIndex); result = ma_context_get_default_device_index__pulse(pContext, deviceType, &callbackData.defaultDeviceIndex);
ma_mainloop_lock__pulse(pContext, "ma_context_get_device_info__pulse");
if (deviceType == ma_device_type_playback) { if (deviceType == ma_device_type_playback) {
pOP = ((ma_pa_context_get_sink_info_by_name_proc)pContext->pulse.pa_context_get_sink_info_by_name)((ma_pa_context*)(pContext->pulse.pPulseContext), pDeviceID->pulse, ma_context_get_device_info_sink_callback__pulse, &callbackData); pOP = ((ma_pa_context_get_sink_info_by_name_proc)pContext->pulse.pa_context_get_sink_info_by_name)((ma_pa_context*)(pContext->pulse.pPulseContext), pDeviceID->pulse, ma_context_get_device_info_sink_callback__pulse, &callbackData);
} else { } else {
pOP = ((ma_pa_context_get_source_info_by_name_proc)pContext->pulse.pa_context_get_source_info_by_name)((ma_pa_context*)(pContext->pulse.pPulseContext), pDeviceID->pulse, ma_context_get_device_info_source_callback__pulse, &callbackData); pOP = ((ma_pa_context_get_source_info_by_name_proc)pContext->pulse.pa_context_get_source_info_by_name)((ma_pa_context*)(pContext->pulse.pPulseContext), pDeviceID->pulse, ma_context_get_device_info_source_callback__pulse, &callbackData);
} }
ma_mainloop_unlock__pulse(pContext, "ma_context_get_device_info__pulse");
if (pOP != NULL) { if (pOP != NULL) {
ma_wait_for_operation_and_unref__pulse(pContext, pOP); ma_wait_for_operation_and_unref__pulse(pContext, pOP);
...@@ -21943,6 +21951,8 @@ static void ma_device_uninit__pulse(ma_device* pDevice) ...@@ -21943,6 +21951,8 @@ static void ma_device_uninit__pulse(ma_device* pDevice)
pContext = pDevice->pContext; pContext = pDevice->pContext;
MA_ASSERT(pContext != NULL); MA_ASSERT(pContext != NULL);
ma_mainloop_lock__pulse(pContext, "ma_device_uninit__pulse");
{
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_pa_stream_disconnect_proc)pContext->pulse.pa_stream_disconnect)((ma_pa_stream*)pDevice->pulse.pStreamCapture); ((ma_pa_stream_disconnect_proc)pContext->pulse.pa_stream_disconnect)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
((ma_pa_stream_unref_proc)pContext->pulse.pa_stream_unref)((ma_pa_stream*)pDevice->pulse.pStreamCapture); ((ma_pa_stream_unref_proc)pContext->pulse.pa_stream_unref)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
...@@ -21952,6 +21962,8 @@ static void ma_device_uninit__pulse(ma_device* pDevice) ...@@ -21952,6 +21962,8 @@ static void ma_device_uninit__pulse(ma_device* pDevice)
((ma_pa_stream_disconnect_proc)pContext->pulse.pa_stream_disconnect)((ma_pa_stream*)pDevice->pulse.pStreamPlayback); ((ma_pa_stream_disconnect_proc)pContext->pulse.pa_stream_disconnect)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
((ma_pa_stream_unref_proc)pContext->pulse.pa_stream_unref)((ma_pa_stream*)pDevice->pulse.pStreamPlayback); ((ma_pa_stream_unref_proc)pContext->pulse.pa_stream_unref)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
} }
}
ma_mainloop_unlock__pulse(pContext, "ma_device_uninit__pulse");
if (pDevice->type == ma_device_type_duplex) { if (pDevice->type == ma_device_type_duplex) {
ma_pcm_rb_uninit(&pDevice->pulse.duplexRB); ma_pcm_rb_uninit(&pDevice->pulse.duplexRB);
...@@ -21972,6 +21984,7 @@ static ma_pa_buffer_attr ma_device__pa_buffer_attr_new(ma_uint32 periodSizeInFra ...@@ -21972,6 +21984,7 @@ static ma_pa_buffer_attr ma_device__pa_buffer_attr_new(ma_uint32 periodSizeInFra
static ma_pa_stream* ma_context__pa_stream_new__pulse(ma_context* pContext, const char* pStreamName, const ma_pa_sample_spec* ss, const ma_pa_channel_map* cmap) static ma_pa_stream* ma_context__pa_stream_new__pulse(ma_context* pContext, const char* pStreamName, const ma_pa_sample_spec* ss, const ma_pa_channel_map* cmap)
{ {
ma_pa_stream* pStream;
static int g_StreamCounter = 0; static int g_StreamCounter = 0;
char actualStreamName[256]; char actualStreamName[256];
...@@ -21983,7 +21996,11 @@ static ma_pa_stream* ma_context__pa_stream_new__pulse(ma_context* pContext, cons ...@@ -21983,7 +21996,11 @@ static ma_pa_stream* ma_context__pa_stream_new__pulse(ma_context* pContext, cons
} }
g_StreamCounter += 1; g_StreamCounter += 1;
return ((ma_pa_stream_new_proc)pContext->pulse.pa_stream_new)((ma_pa_context*)pContext->pulse.pPulseContext, actualStreamName, ss, cmap); ma_mainloop_lock__pulse(pContext, "ma_context__pa_stream_new__pulse");
pStream = ((ma_pa_stream_new_proc)pContext->pulse.pa_stream_new)((ma_pa_context*)pContext->pulse.pPulseContext, actualStreamName, ss, cmap);
ma_mainloop_unlock__pulse(pContext, "ma_context__pa_stream_new__pulse");
return pStream;
} }
...@@ -22208,7 +22225,9 @@ static ma_result ma_device_init__pulse(ma_context* pContext, const ma_device_con ...@@ -22208,7 +22225,9 @@ static ma_result ma_device_init__pulse(ma_context* pContext, const ma_device_con
/* The callback needs to be set before connecting the stream. */ /* The callback needs to be set before connecting the stream. */
ma_mainloop_lock__pulse(pContext, "ma_device_init__pulse");
((ma_pa_stream_set_read_callback_proc)pContext->pulse.pa_stream_set_read_callback)((ma_pa_stream*)pDevice->pulse.pStreamCapture, ma_device_on_read__pulse, pDevice); ((ma_pa_stream_set_read_callback_proc)pContext->pulse.pa_stream_set_read_callback)((ma_pa_stream*)pDevice->pulse.pStreamCapture, ma_device_on_read__pulse, pDevice);
ma_mainloop_unlock__pulse(pContext, "ma_device_init__pulse");
/* Connect after we've got all of our internal state set up. */ /* Connect after we've got all of our internal state set up. */
...@@ -22217,7 +22236,9 @@ static ma_result ma_device_init__pulse(ma_context* pContext, const ma_device_con ...@@ -22217,7 +22236,9 @@ static ma_result ma_device_init__pulse(ma_context* pContext, const ma_device_con
streamFlags |= MA_PA_STREAM_DONT_MOVE; streamFlags |= MA_PA_STREAM_DONT_MOVE;
} }
ma_mainloop_lock__pulse(pContext, "ma_device_init__pulse");
error = ((ma_pa_stream_connect_record_proc)pContext->pulse.pa_stream_connect_record)((ma_pa_stream*)pDevice->pulse.pStreamCapture, devCapture, &attr, streamFlags); error = ((ma_pa_stream_connect_record_proc)pContext->pulse.pa_stream_connect_record)((ma_pa_stream*)pDevice->pulse.pStreamCapture, devCapture, &attr, streamFlags);
ma_mainloop_unlock__pulse(pContext, "ma_device_init__pulse");
if (error != MA_PA_OK) { if (error != MA_PA_OK) {
result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio capture stream.", ma_result_from_pulse(error)); result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio capture stream.", ma_result_from_pulse(error));
goto on_error1; goto on_error1;
...@@ -22229,6 +22250,8 @@ static ma_result ma_device_init__pulse(ma_context* pContext, const ma_device_con ...@@ -22229,6 +22250,8 @@ static ma_result ma_device_init__pulse(ma_context* pContext, const ma_device_con
} }
ma_mainloop_lock__pulse(pContext, "ma_device_init__pulse");
{
/* Internal format. */ /* Internal format. */
pActualSS = ((ma_pa_stream_get_sample_spec_proc)pContext->pulse.pa_stream_get_sample_spec)((ma_pa_stream*)pDevice->pulse.pStreamCapture); pActualSS = ((ma_pa_stream_get_sample_spec_proc)pContext->pulse.pa_stream_get_sample_spec)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
if (pActualSS != NULL) { if (pActualSS != NULL) {
...@@ -22258,9 +22281,13 @@ static ma_result ma_device_init__pulse(ma_context* pContext, const ma_device_con ...@@ -22258,9 +22281,13 @@ static ma_result ma_device_init__pulse(ma_context* pContext, const ma_device_con
#ifdef MA_DEBUG_OUTPUT #ifdef MA_DEBUG_OUTPUT
printf("[PulseAudio] Capture actual attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; internalPeriodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDevice->capture.internalPeriodSizeInFrames); printf("[PulseAudio] Capture actual attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; internalPeriodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDevice->capture.internalPeriodSizeInFrames);
#endif #endif
}
ma_mainloop_unlock__pulse(pContext, "ma_device_init__pulse");
/* Name. */ /* Name. */
ma_mainloop_lock__pulse(pContext, "ma_device_init__pulse");
devCapture = ((ma_pa_stream_get_device_name_proc)pContext->pulse.pa_stream_get_device_name)((ma_pa_stream*)pDevice->pulse.pStreamCapture); devCapture = ((ma_pa_stream_get_device_name_proc)pContext->pulse.pa_stream_get_device_name)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
ma_mainloop_unlock__pulse(pContext, "ma_device_init__pulse");
if (devCapture != NULL) { if (devCapture != NULL) {
ma_wait_for_operation_and_unref__pulse(pContext, ((ma_pa_context_get_source_info_by_name_proc)pContext->pulse.pa_context_get_source_info_by_name)((ma_pa_context*)pContext->pulse.pPulseContext, devCapture, ma_device_source_name_callback, pDevice)); ma_wait_for_operation_and_unref__pulse(pContext, ((ma_pa_context_get_source_info_by_name_proc)pContext->pulse.pa_context_get_source_info_by_name)((ma_pa_context*)pContext->pulse.pPulseContext, devCapture, ma_device_source_name_callback, pDevice));
} }
...@@ -22295,7 +22322,9 @@ static ma_result ma_device_init__pulse(ma_context* pContext, const ma_device_con ...@@ -22295,7 +22322,9 @@ static ma_result ma_device_init__pulse(ma_context* pContext, const ma_device_con
Note that this callback will be fired as soon as the stream is connected, even though it's started as corked. The callback needs to handle a Note that this callback will be fired as soon as the stream is connected, even though it's started as corked. The callback needs to handle a
device state of MA_STATE_UNINITIALIZED. device state of MA_STATE_UNINITIALIZED.
*/ */
ma_mainloop_lock__pulse(pContext, "ma_device_init__pulse");
((ma_pa_stream_set_write_callback_proc)pContext->pulse.pa_stream_set_write_callback)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, ma_device_on_write__pulse, pDevice); ((ma_pa_stream_set_write_callback_proc)pContext->pulse.pa_stream_set_write_callback)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, ma_device_on_write__pulse, pDevice);
ma_mainloop_unlock__pulse(pContext, "ma_device_init__pulse");
/* Connect after we've got all of our internal state set up. */ /* Connect after we've got all of our internal state set up. */
...@@ -22304,7 +22333,9 @@ static ma_result ma_device_init__pulse(ma_context* pContext, const ma_device_con ...@@ -22304,7 +22333,9 @@ static ma_result ma_device_init__pulse(ma_context* pContext, const ma_device_con
streamFlags |= MA_PA_STREAM_DONT_MOVE; streamFlags |= MA_PA_STREAM_DONT_MOVE;
} }
ma_mainloop_lock__pulse(pContext, "ma_device_init__pulse");
error = ((ma_pa_stream_connect_playback_proc)pContext->pulse.pa_stream_connect_playback)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, devPlayback, &attr, streamFlags, NULL, NULL); error = ((ma_pa_stream_connect_playback_proc)pContext->pulse.pa_stream_connect_playback)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, devPlayback, &attr, streamFlags, NULL, NULL);
ma_mainloop_unlock__pulse(pContext, "ma_device_init__pulse");
if (error != MA_PA_OK) { if (error != MA_PA_OK) {
result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio playback stream.", ma_result_from_pulse(error)); result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio playback stream.", ma_result_from_pulse(error));
goto on_error3; goto on_error3;
...@@ -22316,6 +22347,8 @@ static ma_result ma_device_init__pulse(ma_context* pContext, const ma_device_con ...@@ -22316,6 +22347,8 @@ static ma_result ma_device_init__pulse(ma_context* pContext, const ma_device_con
} }
ma_mainloop_lock__pulse(pContext, "ma_device_init__pulse");
{
/* Internal format. */ /* Internal format. */
pActualSS = ((ma_pa_stream_get_sample_spec_proc)pContext->pulse.pa_stream_get_sample_spec)((ma_pa_stream*)pDevice->pulse.pStreamPlayback); pActualSS = ((ma_pa_stream_get_sample_spec_proc)pContext->pulse.pa_stream_get_sample_spec)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
if (pActualSS != NULL) { if (pActualSS != NULL) {
...@@ -22345,9 +22378,13 @@ static ma_result ma_device_init__pulse(ma_context* pContext, const ma_device_con ...@@ -22345,9 +22378,13 @@ static ma_result ma_device_init__pulse(ma_context* pContext, const ma_device_con
#ifdef MA_DEBUG_OUTPUT #ifdef MA_DEBUG_OUTPUT
printf("[PulseAudio] Playback actual attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; internalPeriodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDevice->playback.internalPeriodSizeInFrames); printf("[PulseAudio] Playback actual attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; internalPeriodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDevice->playback.internalPeriodSizeInFrames);
#endif #endif
}
ma_mainloop_unlock__pulse(pContext, "ma_device_init__pulse");
/* Name. */ /* Name. */
ma_mainloop_lock__pulse(pContext, "ma_device_init__pulse");
devPlayback = ((ma_pa_stream_get_device_name_proc)pContext->pulse.pa_stream_get_device_name)((ma_pa_stream*)pDevice->pulse.pStreamPlayback); devPlayback = ((ma_pa_stream_get_device_name_proc)pContext->pulse.pa_stream_get_device_name)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
ma_mainloop_unlock__pulse(pContext, "ma_device_init__pulse");
if (devPlayback != NULL) { if (devPlayback != NULL) {
ma_wait_for_operation_and_unref__pulse(pContext, ((ma_pa_context_get_sink_info_by_name_proc)pContext->pulse.pa_context_get_sink_info_by_name)((ma_pa_context*)pContext->pulse.pPulseContext, devPlayback, ma_device_sink_name_callback, pDevice)); ma_wait_for_operation_and_unref__pulse(pContext, ((ma_pa_context_get_sink_info_by_name_proc)pContext->pulse.pa_context_get_sink_info_by_name)((ma_pa_context*)pContext->pulse.pPulseContext, devPlayback, ma_device_sink_name_callback, pDevice));
} }
...@@ -22380,19 +22417,27 @@ static ma_result ma_device_init__pulse(ma_context* pContext, const ma_device_con ...@@ -22380,19 +22417,27 @@ static ma_result ma_device_init__pulse(ma_context* pContext, const ma_device_con
on_error4: on_error4:
if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
ma_mainloop_lock__pulse(pContext, "ma_device_init__pulse");
((ma_pa_stream_disconnect_proc)pContext->pulse.pa_stream_disconnect)((ma_pa_stream*)pDevice->pulse.pStreamPlayback); ((ma_pa_stream_disconnect_proc)pContext->pulse.pa_stream_disconnect)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
ma_mainloop_unlock__pulse(pContext, "ma_device_init__pulse");
} }
on_error3: on_error3:
if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) { if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
ma_mainloop_lock__pulse(pContext, "ma_device_init__pulse");
((ma_pa_stream_unref_proc)pContext->pulse.pa_stream_unref)((ma_pa_stream*)pDevice->pulse.pStreamPlayback); ((ma_pa_stream_unref_proc)pContext->pulse.pa_stream_unref)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
ma_mainloop_unlock__pulse(pContext, "ma_device_init__pulse");
} }
on_error2: on_error2:
if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
ma_mainloop_lock__pulse(pContext, "ma_device_init__pulse");
((ma_pa_stream_disconnect_proc)pContext->pulse.pa_stream_disconnect)((ma_pa_stream*)pDevice->pulse.pStreamCapture); ((ma_pa_stream_disconnect_proc)pContext->pulse.pa_stream_disconnect)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
ma_mainloop_unlock__pulse(pContext, "ma_device_init__pulse");
} }
on_error1: on_error1:
if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
ma_mainloop_lock__pulse(pContext, "ma_device_init__pulse");
((ma_pa_stream_unref_proc)pContext->pulse.pa_stream_unref)((ma_pa_stream*)pDevice->pulse.pStreamCapture); ((ma_pa_stream_unref_proc)pContext->pulse.pa_stream_unref)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
ma_mainloop_unlock__pulse(pContext, "ma_device_init__pulse");
} }
on_error0: on_error0:
return result; return result;
...@@ -22427,7 +22472,10 @@ static ma_result ma_device__cork_stream__pulse(ma_device* pDevice, ma_device_typ ...@@ -22427,7 +22472,10 @@ static ma_result ma_device__cork_stream__pulse(ma_device* pDevice, ma_device_typ
pStream = (ma_pa_stream*)((deviceType == ma_device_type_capture) ? pDevice->pulse.pStreamCapture : pDevice->pulse.pStreamPlayback); pStream = (ma_pa_stream*)((deviceType == ma_device_type_capture) ? pDevice->pulse.pStreamCapture : pDevice->pulse.pStreamPlayback);
MA_ASSERT(pStream != NULL); MA_ASSERT(pStream != NULL);
ma_mainloop_lock__pulse(pContext, "ma_device__cork_stream__pulse");
pOP = ((ma_pa_stream_cork_proc)pContext->pulse.pa_stream_cork)(pStream, cork, ma_pulse_operation_complete_callback, &wasSuccessful); pOP = ((ma_pa_stream_cork_proc)pContext->pulse.pa_stream_cork)(pStream, cork, ma_pulse_operation_complete_callback, &wasSuccessful);
ma_mainloop_unlock__pulse(pContext, "ma_device__cork_stream__pulse");
if (pOP == NULL) { if (pOP == NULL) {
return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to cork PulseAudio stream.", (cork == 0) ? MA_FAILED_TO_START_BACKEND_DEVICE : MA_FAILED_TO_STOP_BACKEND_DEVICE); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to cork PulseAudio stream.", (cork == 0) ? MA_FAILED_TO_START_BACKEND_DEVICE : MA_FAILED_TO_STOP_BACKEND_DEVICE);
} }
...@@ -22464,9 +22512,7 @@ static ma_result ma_device_start__pulse(ma_device* pDevice) ...@@ -22464,9 +22512,7 @@ static ma_result ma_device_start__pulse(ma_device* pDevice)
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) {
/* We need to fill some data before uncorking. Not doing this will result in the write callback never getting fired. */ /* We need to fill some data before uncorking. Not doing this will result in the write callback never getting fired. */
ma_mainloop_lock__pulse(pDevice->pContext, "ma_device_start__pulse"); ma_mainloop_lock__pulse(pDevice->pContext, "ma_device_start__pulse");
{
result = ma_device_write_to_stream__pulse(pDevice, (ma_pa_stream*)(pDevice->pulse.pStreamPlayback), NULL); result = ma_device_write_to_stream__pulse(pDevice, (ma_pa_stream*)(pDevice->pulse.pStreamPlayback), NULL);
}
ma_mainloop_unlock__pulse(pDevice->pContext, "ma_device_start__pulse"); ma_mainloop_unlock__pulse(pDevice->pContext, "ma_device_start__pulse");
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
...@@ -22498,7 +22544,13 @@ static ma_result ma_device_stop__pulse(ma_device* pDevice) ...@@ -22498,7 +22544,13 @@ static ma_result ma_device_stop__pulse(ma_device* pDevice)
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) {
/* The stream needs to be drained if it's a playback device. */ /* The stream needs to be drained if it's a playback device. */
ma_wait_for_operation_and_unref__pulse(pDevice->pContext, ((ma_pa_stream_drain_proc)pDevice->pContext->pulse.pa_stream_drain)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, ma_pulse_operation_complete_callback, &wasSuccessful)); ma_pa_operation* pOP;
ma_mainloop_lock__pulse(pDevice->pContext, "ma_device_stop__pulse");
pOP = ((ma_pa_stream_drain_proc)pDevice->pContext->pulse.pa_stream_drain)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, ma_pulse_operation_complete_callback, &wasSuccessful);
ma_mainloop_unlock__pulse(pDevice->pContext, "ma_device_stop__pulse");
ma_wait_for_operation_and_unref__pulse(pDevice->pContext, pOP);
result = ma_device__cork_stream__pulse(pDevice, ma_device_type_playback, 1); result = ma_device__cork_stream__pulse(pDevice, ma_device_type_playback, 1);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
...@@ -22518,8 +22570,12 @@ static ma_result ma_context_uninit__pulse(ma_context* pContext) ...@@ -22518,8 +22570,12 @@ static ma_result ma_context_uninit__pulse(ma_context* pContext)
MA_ASSERT(pContext != NULL); MA_ASSERT(pContext != NULL);
MA_ASSERT(pContext->backend == ma_backend_pulseaudio); MA_ASSERT(pContext->backend == ma_backend_pulseaudio);
ma_mainloop_lock__pulse(pContext, "ma_context_uninit__pulse");
{
((ma_pa_context_disconnect_proc)pContext->pulse.pa_context_disconnect)((ma_pa_context*)pContext->pulse.pPulseContext); ((ma_pa_context_disconnect_proc)pContext->pulse.pa_context_disconnect)((ma_pa_context*)pContext->pulse.pPulseContext);
((ma_pa_context_unref_proc)pContext->pulse.pa_context_unref)((ma_pa_context*)pContext->pulse.pPulseContext); ((ma_pa_context_unref_proc)pContext->pulse.pa_context_unref)((ma_pa_context*)pContext->pulse.pPulseContext);
}
ma_mainloop_unlock__pulse(pContext, "ma_context_uninit__pulse");
/* The mainloop needs to be stopped before freeing. */ /* The mainloop needs to be stopped before freeing. */
((ma_pa_threaded_mainloop_stop_proc)pContext->pulse.pa_threaded_mainloop_stop)((ma_pa_threaded_mainloop*)pContext->pulse.pMainLoop); ((ma_pa_threaded_mainloop_stop_proc)pContext->pulse.pa_threaded_mainloop_stop)((ma_pa_threaded_mainloop*)pContext->pulse.pMainLoop);
...@@ -33519,7 +33575,7 @@ MA_API ma_uint32 ma_device_get_state(const ma_device* pDevice) ...@@ -33519,7 +33575,7 @@ MA_API ma_uint32 ma_device_get_state(const ma_device* pDevice)
return MA_STATE_UNINITIALIZED; return MA_STATE_UNINITIALIZED;
} }
return pDevice->state; return c89atomic_load_32((ma_uint32*)&pDevice->state); /* Naughty cast to get rid of a const warning. */
} }
MA_API ma_result ma_device_set_master_volume(ma_device* pDevice, float volume) MA_API ma_result ma_device_set_master_volume(ma_device* pDevice, float volume)
...@@ -64456,6 +64512,7 @@ v0.10.27 - TBD ...@@ -64456,6 +64512,7 @@ v0.10.27 - TBD
- Add support for configuring the channel mixing mode in the device config. - Add support for configuring the channel mixing mode in the device config.
- Fix a bug with simple channel mixing mode (drop or silence excess channels). - Fix a bug with simple channel mixing mode (drop or silence excess channels).
- Fix some bugs with trying to access uninitialized variables. - Fix some bugs with trying to access uninitialized variables.
- PulseAudio: Fix some data race errors.
v0.10.26 - 2020-11-24 v0.10.26 - 2020-11-24
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