From d68dd6c433dc71774988ea808ce4193ecbaf42c9 Mon Sep 17 00:00:00 2001 From: David Reid Date: Wed, 14 Jan 2026 11:28:50 +1000 Subject: [PATCH] sndio: Use a shared intermediary buffer for duplex mode. Previously this was using two separate buffers for the capture and playback sides, but it's not necessary to use two separate buffers because they'll never be used simultaneously. It can therefore be optimized by allocating a single buffer that is big enough for either of them. --- miniaudio.h | 52 +++++++++++++++++++++++++--------------------------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/miniaudio.h b/miniaudio.h index 01cb93d2..547b1227 100644 --- a/miniaudio.h +++ b/miniaudio.h @@ -36853,10 +36853,10 @@ typedef struct ma_context_state_sndio typedef struct ma_device_state_sndio { struct pollfd* pPollFDs; + void* pIntermediaryBuffer; struct { struct ma_sio_hdl* handle; - void* pIntermediaryBuffer; } playback, capture; } ma_device_state_sndio; @@ -37356,7 +37356,6 @@ static ma_result ma_device_init_by_type__sndio(ma_device* pDevice, ma_device_sta ma_uint32 internalSampleRate; ma_uint32 internalPeriodSizeInFrames; ma_uint32 internalPeriods; - void* pIntermediaryBuffer; MA_ASSERT(deviceType != ma_device_type_duplex); MA_ASSERT(pDevice != NULL); @@ -37499,20 +37498,10 @@ static ma_result ma_device_init_by_type__sndio(ma_device* pDevice, ma_device_sta internalPeriods = par.appbufsz / par.round; internalPeriodSizeInFrames = par.round; - /* An intermediary buffer is required for our step function. */ - pIntermediaryBuffer = ma_malloc(ma_get_bytes_per_frame(internalFormat, internalChannels) * internalPeriodSizeInFrames, ma_device_get_allocation_callbacks(pDevice)); - if (pIntermediaryBuffer == NULL) { - pContextStateSndio->sio_close(handle); - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[sndio] Failed to allocate intermediary buffer."); - return MA_OUT_OF_MEMORY; - } - if (deviceType == ma_device_type_capture) { - pDeviceStateSndio->capture.handle = handle; - pDeviceStateSndio->capture.pIntermediaryBuffer = pIntermediaryBuffer; + pDeviceStateSndio->capture.handle = handle; } else { - pDeviceStateSndio->playback.handle = handle; - pDeviceStateSndio->playback.pIntermediaryBuffer = pIntermediaryBuffer; + pDeviceStateSndio->playback.handle = handle; } pDescriptor->format = internalFormat; @@ -37536,6 +37525,8 @@ static ma_result ma_device_init__sndio(ma_device* pDevice, const void* pDeviceBa ma_device_type deviceType = ma_device_get_type(pDevice); int nfdsCapture = 0; int nfdsPlayback = 0; + size_t intermediaryBufferSizeCapture = 0; + size_t intermediaryBufferSizePlayback = 0; if (pDeviceConfigSndio == NULL) { defaultConfigSndio = ma_device_config_sndio_init(); @@ -37554,26 +37545,23 @@ static ma_result ma_device_init__sndio(ma_device* pDevice, const void* pDeviceBa if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex) { ma_result result = ma_device_init_by_type__sndio(pDevice, pDeviceStateSndio, pDeviceConfigSndio, pDescriptorCapture, ma_device_type_capture); if (result != MA_SUCCESS) { - ma_free(pDeviceStateSndio, ma_device_get_allocation_callbacks(pDevice)); + ma_device_uninit__sndio(pDevice); return result; } nfdsCapture = pContextStateSndio->sio_nfds(pDeviceStateSndio->capture.handle); + intermediaryBufferSizeCapture = ma_get_bytes_per_frame(pDescriptorCapture->format, pDescriptorCapture->channels) * pDescriptorCapture->periodSizeInFrames; } if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) { ma_result result = ma_device_init_by_type__sndio(pDevice, pDeviceStateSndio, pDeviceConfigSndio, pDescriptorPlayback, ma_device_type_playback); if (result != MA_SUCCESS) { - if (deviceType == ma_device_type_duplex) { - pContextStateSndio->sio_close(pDeviceStateSndio->capture.handle); - ma_free(pDeviceStateSndio->capture.pIntermediaryBuffer, ma_device_get_allocation_callbacks(pDevice)); - } - - ma_free(pDeviceStateSndio, ma_device_get_allocation_callbacks(pDevice)); + ma_device_uninit__sndio(pDevice); return result; } nfdsPlayback = pContextStateSndio->sio_nfds(pDeviceStateSndio->playback.handle); + intermediaryBufferSizePlayback = ma_get_bytes_per_frame(pDescriptorPlayback->format, pDescriptorPlayback->channels) * pDescriptorPlayback->periodSizeInFrames; } /* We need memory for our poll fds. */ @@ -37583,6 +37571,17 @@ static ma_result ma_device_init__sndio(ma_device* pDevice, const void* pDeviceBa return MA_OUT_OF_MEMORY; } + /* + Now we need an intermediary buffer. This can be shared between capture and playback so we just + allocate this based on the largest required size between the two. + */ + pDeviceStateSndio->pIntermediaryBuffer = ma_calloc(ma_max(intermediaryBufferSizeCapture, intermediaryBufferSizePlayback), ma_device_get_allocation_callbacks(pDevice)); + if (pDeviceStateSndio->pIntermediaryBuffer == NULL) { + ma_device_uninit__sndio(pDevice); + return MA_OUT_OF_MEMORY; + } + + *ppDeviceState = pDeviceStateSndio; return MA_SUCCESS; @@ -37596,14 +37595,13 @@ static void ma_device_uninit__sndio(ma_device* pDevice) if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex) { pContextStateSndio->sio_close(pDeviceStateSndio->capture.handle); - ma_free(pDeviceStateSndio->capture.pIntermediaryBuffer, ma_device_get_allocation_callbacks(pDevice)); } if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) { pContextStateSndio->sio_close(pDeviceStateSndio->playback.handle); - ma_free(pDeviceStateSndio->playback.pIntermediaryBuffer, ma_device_get_allocation_callbacks(pDevice)); } + ma_free(pDeviceStateSndio->pIntermediaryBuffer, ma_device_get_allocation_callbacks(pDevice)); ma_free(pDeviceStateSndio->pPollFDs, ma_device_get_allocation_callbacks(pDevice)); ma_free(pDeviceStateSndio, ma_device_get_allocation_callbacks(pDevice)); } @@ -37764,12 +37762,12 @@ static ma_result ma_device_step__sndio(ma_device* pDevice, ma_blocking_mode bloc if ((revents & POLLIN) != 0) { ma_uint32 framesRead; - result = ma_device_read__sndio(pDevice, pDeviceStateSndio->capture.pIntermediaryBuffer, pDevice->capture.internalPeriodSizeInFrames, &framesRead); + result = ma_device_read__sndio(pDevice, pDeviceStateSndio->pIntermediaryBuffer, pDevice->capture.internalPeriodSizeInFrames, &framesRead); if (result != MA_SUCCESS) { return result; } - ma_device_handle_backend_data_callback(pDevice, NULL, pDeviceStateSndio->capture.pIntermediaryBuffer, framesRead); + ma_device_handle_backend_data_callback(pDevice, NULL, pDeviceStateSndio->pIntermediaryBuffer, framesRead); } } @@ -37787,12 +37785,12 @@ static ma_result ma_device_step__sndio(ma_device* pDevice, ma_blocking_mode bloc if ((revents & POLLOUT) != 0) { ma_uint32 framesWritten; - result = ma_device_write__sndio(pDevice, pDeviceStateSndio->playback.pIntermediaryBuffer, pDevice->playback.internalPeriodSizeInFrames, &framesWritten); + result = ma_device_write__sndio(pDevice, pDeviceStateSndio->pIntermediaryBuffer, pDevice->playback.internalPeriodSizeInFrames, &framesWritten); if (result != MA_SUCCESS) { return result; } - ma_device_handle_backend_data_callback(pDevice, pDeviceStateSndio->playback.pIntermediaryBuffer, NULL, framesWritten); + ma_device_handle_backend_data_callback(pDevice, pDeviceStateSndio->pIntermediaryBuffer, NULL, framesWritten); } }