ALSA: Experiment with snd_pcm_link().

This commit is contained in:
David Reid
2026-01-08 17:41:58 +10:00
parent 597654dcf6
commit 0b4a861d94
+19 -5
View File
@@ -27982,6 +27982,7 @@ typedef void (* ma_snd_lib_error_handler_t)(const char* file, int line, const ch
typedef int (* ma_snd_lib_error_set_handler_proc) (ma_snd_lib_error_handler_t handler);
typedef int (* ma_snd_pcm_open_proc) (ma_snd_pcm_t **pcm, const char *name, ma_snd_pcm_stream_t stream, int mode);
typedef int (* ma_snd_pcm_close_proc) (ma_snd_pcm_t *pcm);
typedef int (* ma_snd_pcm_link_proc) (ma_snd_pcm_t* pcm1, ma_snd_pcm_t* pcm2);
typedef size_t (* ma_snd_pcm_hw_params_sizeof_proc) (void);
typedef int (* ma_snd_pcm_hw_params_any_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params);
typedef int (* ma_snd_pcm_hw_params_current_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params);
@@ -28077,6 +28078,7 @@ typedef struct ma_context_state_alsa
ma_snd_lib_error_set_handler_proc snd_lib_error_set_handler;
ma_snd_pcm_open_proc snd_pcm_open;
ma_snd_pcm_close_proc snd_pcm_close;
ma_snd_pcm_link_proc snd_pcm_link;
ma_snd_pcm_hw_params_sizeof_proc snd_pcm_hw_params_sizeof;
ma_snd_pcm_hw_params_any_proc snd_pcm_hw_params_any;
ma_snd_pcm_hw_params_current_proc snd_pcm_hw_params_current;
@@ -28157,6 +28159,7 @@ typedef struct ma_device_state_alsa
int pollDescriptorCountCapture;
ma_bool8 isUsingMMapPlayback;
ma_bool8 isUsingMMapCapture;
ma_bool8 isLinked; /* Only relevant for duplex mode. Used to indicate that the capture and playback PCMs are linked with snd_pcm_link(). */
} ma_device_state_alsa;
@@ -28506,6 +28509,7 @@ static ma_result ma_context_init__alsa(ma_context* pContext, const void* pContex
pContextStateALSA->snd_lib_error_set_handler = (ma_snd_lib_error_set_handler_proc )ma_dlsym(pLog, pContextStateALSA->asoundSO, "snd_lib_error_set_handler");
pContextStateALSA->snd_pcm_open = (ma_snd_pcm_open_proc )ma_dlsym(pLog, pContextStateALSA->asoundSO, "snd_pcm_open");
pContextStateALSA->snd_pcm_close = (ma_snd_pcm_close_proc )ma_dlsym(pLog, pContextStateALSA->asoundSO, "snd_pcm_close");
pContextStateALSA->snd_pcm_link = (ma_snd_pcm_link_proc )ma_dlsym(pLog, pContextStateALSA->asoundSO, "snd_pcm_link");
pContextStateALSA->snd_pcm_hw_params_sizeof = (ma_snd_pcm_hw_params_sizeof_proc )ma_dlsym(pLog, pContextStateALSA->asoundSO, "snd_pcm_hw_params_sizeof");
pContextStateALSA->snd_pcm_hw_params_any = (ma_snd_pcm_hw_params_any_proc )ma_dlsym(pLog, pContextStateALSA->asoundSO, "snd_pcm_hw_params_any");
pContextStateALSA->snd_pcm_hw_params_current = (ma_snd_pcm_hw_params_current_proc )ma_dlsym(pLog, pContextStateALSA->asoundSO, "snd_pcm_hw_params_current");
@@ -28579,6 +28583,7 @@ static ma_result ma_context_init__alsa(ma_context* pContext, const void* pContex
ma_snd_lib_error_set_handler_proc _snd_lib_error_set_handler = snd_lib_error_set_handler;
ma_snd_pcm_open_proc _snd_pcm_open = snd_pcm_open;
ma_snd_pcm_close_proc _snd_pcm_close = snd_pcm_close;
ma_snd_pcm_link_proc _snd_pcm_link = snd_pcm_link;
ma_snd_pcm_hw_params_sizeof_proc _snd_pcm_hw_params_sizeof = snd_pcm_hw_params_sizeof;
ma_snd_pcm_hw_params_any_proc _snd_pcm_hw_params_any = snd_pcm_hw_params_any;
ma_snd_pcm_hw_params_current_proc _snd_pcm_hw_params_current = snd_pcm_hw_params_current;
@@ -28649,6 +28654,7 @@ static ma_result ma_context_init__alsa(ma_context* pContext, const void* pContex
pContextStateALSA->snd_lib_error_set_handler = _snd_lib_error_set_handler;
pContextStateALSA->snd_pcm_open = _snd_pcm_open;
pContextStateALSA->snd_pcm_close = _snd_pcm_close;
pContextStateALSA->snd_pcm_link = _snd_pcm_link;
pContextStateALSA->snd_pcm_hw_params_sizeof = _snd_pcm_hw_params_sizeof;
pContextStateALSA->snd_pcm_hw_params_any = _snd_pcm_hw_params_any;
pContextStateALSA->snd_pcm_hw_params_current = _snd_pcm_hw_params_current;
@@ -29648,6 +29654,15 @@ static ma_result ma_device_init__alsa(ma_device* pDevice, const void* pDeviceBac
}
/* Link the PCMs in duplex mode. */
if (deviceType == ma_device_type_duplex) {
resultALSA = pContextStateALSA->snd_pcm_link(pDeviceStateALSA->pPCMCapture, pDeviceStateALSA->pPCMPlayback);
if (resultALSA == 0) {
pDeviceStateALSA->isLinked = MA_TRUE;
}
}
*ppDeviceState = pDeviceStateALSA;
return MA_SUCCESS;
@@ -29689,6 +29704,7 @@ static ma_result ma_device_start__alsa(ma_device* pDevice)
}
}
if (ma_device_get_type(pDevice) != ma_device_type_duplex || !pDeviceStateALSA->isLinked) { /* <-- In duplex mode the PCMs are linked which means the playback side will be started when the capture side starts. */
if (pDeviceStateALSA->pPCMPlayback != NULL) {
/*
When data is written to the device we wait for the device to get ready to receive data with poll(). In my testing
@@ -29706,6 +29722,7 @@ static ma_result ma_device_start__alsa(ma_device* pDevice)
return ma_result_from_errno(-resultALSA);
}
}
}
return MA_SUCCESS;
}
@@ -29717,11 +29734,6 @@ static ma_result ma_device_stop__alsa(ma_device* pDevice)
int resultPoll;
int resultRead;
/*
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.
*/
if (pDeviceStateALSA->pPCMCapture != NULL) {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Dropping capture device...");
pContextStateALSA->snd_pcm_drop(pDeviceStateALSA->pPCMCapture);
@@ -29736,6 +29748,7 @@ static ma_result ma_device_stop__alsa(ma_device* pDevice)
}
}
if (ma_device_get_type(pDevice) != ma_device_type_duplex && pDeviceStateALSA->isLinked) { /* <-- In duplex mode the PCMs are linked which means the playback side will be stopped when the capture side starts. */
if (pDeviceStateALSA->pPCMPlayback != NULL) {
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Dropping playback device...");
pContextStateALSA->snd_pcm_drop(pDeviceStateALSA->pPCMPlayback);
@@ -29749,6 +29762,7 @@ static ma_result ma_device_stop__alsa(ma_device* pDevice)
ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Preparing playback device successful.");
}
}
}
/* Clear the wakeupfd. */
resultPoll = poll(pDeviceStateALSA->pPollDescriptors, 1, 0);