PipeWire: Use the new ring buffer.

This commit is contained in:
David Reid
2026-01-25 17:47:57 +10:00
parent af2cf5d161
commit 7d1c994414
+23 -91
View File
@@ -31235,7 +31235,7 @@ typedef struct
ma_uint32 bufferSizeInFrames;
ma_uint32 bufferCount;
ma_uint32 rbSizeInFrames;
ma_pcm_rb rb; /* Only used in single-threaded mode. Acts as an intermediary buffer for step(). For playback, PipeWire will read from this ring buffer. For capture, it'll write to it. */
ma_audio_ring_buffer rb; /* Only used in single-threaded mode. Acts as an intermediary buffer for step(). For playback, PipeWire will read from this ring buffer. For capture, it'll write to it. */
ma_device_descriptor* pDescriptor; /* This is only used for setting up internal format. It's needed here because it looks like the only way to get the internal format is via a stupid callback. Will be set to NULL after initialization of the PipeWire stream. */
} ma_pipewire_stream_state;
@@ -32468,7 +32468,6 @@ static void ma_stream_event_process__pipewire(void* pUserData, ma_device_type de
{
ma_device_state_pipewire* pDeviceStatePipeWire = (ma_device_state_pipewire*)pUserData;
ma_context_state_pipewire* pContextStatePipeWire = pDeviceStatePipeWire->pContextStatePipeWire;
ma_result result;
ma_pipewire_stream_state* pStreamState;
struct ma_pw_buffer* pBuffer;
ma_uint32 bytesPerFrame;
@@ -32517,14 +32516,14 @@ static void ma_stream_event_process__pipewire(void* pUserData, ma_device_type de
if (pStreamState->rbSizeInFrames > 0) {
if (ma_device_get_threading_mode(pDeviceStatePipeWire->pDevice) == MA_THREADING_MODE_SINGLE_THREADED) {
ma_pcm_rb_uninit(&pStreamState->rb);
ma_audio_ring_buffer_uninit(&pStreamState->rb);
}
}
pStreamState->rbSizeInFrames = (ma_uint32)time.size;
if (ma_device_get_threading_mode(pDeviceStatePipeWire->pDevice) == MA_THREADING_MODE_SINGLE_THREADED) {
ma_pcm_rb_init(pStreamState->format, pStreamState->channels, pStreamState->rbSizeInFrames, NULL, ma_device_get_allocation_callbacks(pDeviceStatePipeWire->pDevice), &pStreamState->rb);
ma_audio_ring_buffer_init(pStreamState->format, pStreamState->channels, pStreamState->sampleRate, pStreamState->rbSizeInFrames, ma_device_get_allocation_callbacks(pDeviceStatePipeWire->pDevice), &pStreamState->rb);
}
pStreamState->initStatus |= MA_PIPEWIRE_INIT_STATUS_HAS_LATENCY;
@@ -32555,38 +32554,12 @@ static void ma_stream_event_process__pipewire(void* pUserData, ma_device_type de
if (ma_device_get_threading_mode(pDeviceStatePipeWire->pDevice) == MA_THREADING_MODE_MULTI_THREADED) {
ma_device_handle_backend_data_callback(pDeviceStatePipeWire->pDevice, pBuffer->buffer->datas[0].data, NULL, frameCount);
} else {
ma_uint32 framesRemaining = frameCount;
ma_uint32 framesAvailable = ma_pcm_rb_available_read(&pStreamState->rb);
ma_uint64 framesRead;
/* Copy data in. Read from the ring buffer, output to the PipeWire buffer. */
if (framesAvailable < frameCount) {
/* Underflow. Just write silence. */
MA_ZERO_MEMORY((char*)pBuffer->buffer->datas[0].data + (frameCount - framesRemaining) * bytesPerFrame, framesRemaining * bytesPerFrame);
} else {
/*
Two ways of handling this. In multi-threaded mode, it doesn't really matter which thread does the data
processing so we can just do it directly from here and bypass the ring buffer entirely.
*/
while (framesRemaining > 0) {
ma_uint32 framesToProcess = (ma_uint32)ma_min(framesRemaining, framesAvailable);
void* pMappedBuffer;
result = ma_pcm_rb_acquire_read(&pStreamState->rb, &framesToProcess, &pMappedBuffer);
if (result != MA_SUCCESS) {
ma_log_postf(pContextStatePipeWire->pLog, MA_LOG_LEVEL_ERROR, "(PipeWire) Failed to acquire data from ring buffer.");
break;
}
MA_COPY_MEMORY((char*)pBuffer->buffer->datas[0].data + ((frameCount - framesRemaining) * bytesPerFrame), pMappedBuffer, framesToProcess * bytesPerFrame);
framesRemaining -= framesToProcess;
result = ma_pcm_rb_commit_read(&pStreamState->rb, framesToProcess);
if (result != MA_SUCCESS) {
ma_log_postf(pContextStatePipeWire->pLog, MA_LOG_LEVEL_ERROR, "(PipeWire) Failed to commit read to ring buffer.");
break;
}
}
ma_audio_ring_buffer_read_pcm_frames(&pStreamState->rb, pBuffer->buffer->datas[0].data, frameCount, &framesRead);
if (framesRead < frameCount) {
/* Underflow. Fill the remaining output with silence. */
MA_ZERO_MEMORY(ma_offset_ptr(pBuffer->buffer->datas[0].data, framesRead * bytesPerFrame), (frameCount - framesRead) * bytesPerFrame);
}
}
@@ -32595,28 +32568,11 @@ static void ma_stream_event_process__pipewire(void* pUserData, ma_device_type de
if (ma_device_get_threading_mode(pDeviceStatePipeWire->pDevice) == MA_THREADING_MODE_MULTI_THREADED) {
ma_device_handle_backend_data_callback(pDeviceStatePipeWire->pDevice, NULL, pBuffer->buffer->datas[0].data, frameCount);
} else {
ma_uint32 framesRemaining = frameCount;
ma_uint32 framesAvailable = ma_pcm_rb_available_write(&pStreamState->rb);
ma_uint64 framesWritten;
/* Copy data out. Write from the PipeWire buffer to the ring buffer. */
while (framesRemaining > 0) {
ma_uint32 framesToProcess = (ma_uint32)ma_min(framesRemaining, framesAvailable);
void* pMappedBuffer;
result = ma_pcm_rb_acquire_write(&pStreamState->rb, &framesToProcess, &pMappedBuffer);
if (result != MA_SUCCESS) {
ma_log_postf(pContextStatePipeWire->pLog, MA_LOG_LEVEL_ERROR, "(PipeWire) Failed to acquire space in ring buffer.");
break;
}
MA_COPY_MEMORY(pMappedBuffer, (char*)pBuffer->buffer->datas[0].data + ((frameCount - framesRemaining) * bytesPerFrame), framesToProcess * bytesPerFrame);
framesRemaining -= framesToProcess;
result = ma_pcm_rb_commit_write(&pStreamState->rb, framesToProcess);
if (result != MA_SUCCESS) {
ma_log_postf(pContextStatePipeWire->pLog, MA_LOG_LEVEL_ERROR, "(PipeWire) Failed to commit write to ring buffer.");
break;
}
ma_audio_ring_buffer_write_pcm_frames(&pStreamState->rb, pBuffer->buffer->datas[0].data, frameCount, &framesWritten);
if (framesWritten < frameCount) {
/* Overflow. This will glitch. */
}
}
@@ -32929,10 +32885,10 @@ static void ma_device_uninit__pipewire(ma_device* pDevice)
if (ma_device_get_threading_mode(pDeviceStatePipeWire->pDevice) == MA_THREADING_MODE_SINGLE_THREADED) {
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex) {
ma_pcm_rb_uninit(&pDeviceStatePipeWire->capture.rb);
ma_audio_ring_buffer_uninit(&pDeviceStatePipeWire->capture.rb);
}
if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) {
ma_pcm_rb_uninit(&pDeviceStatePipeWire->playback.rb);
ma_audio_ring_buffer_uninit(&pDeviceStatePipeWire->playback.rb);
}
}
@@ -32999,51 +32955,27 @@ static ma_result ma_device_step__pipewire(ma_device* pDevice, ma_blocking_mode b
/* We need only process data here in single-threaded mode. */
if (ma_device_get_threading_mode(pDeviceStatePipeWire->pDevice) == MA_THREADING_MODE_SINGLE_THREADED) {
/* We want to handle both playback and capture in a single iteration for duplex mode. */
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex) {
ma_uint32 framesAvailable;
void* pMappedBuffer;
ma_uint32 framesAvailable;
framesAvailable = ma_pcm_rb_available_read(&pDeviceStatePipeWire->capture.rb);
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex) {
framesAvailable = ma_audio_ring_buffer_map_consume(&pDeviceStatePipeWire->capture.rb, 0xFFFFFFFF, &pMappedBuffer);
if (framesAvailable > 0) {
hasProcessedData = MA_TRUE;
}
while (framesAvailable > 0) {
void* pMappedBuffer;
ma_uint32 framesToRead = framesAvailable;
ma_result result;
result = ma_pcm_rb_acquire_read(&pDeviceStatePipeWire->capture.rb, &framesToRead, &pMappedBuffer);
if (result == MA_SUCCESS) {
ma_device_handle_backend_data_callback(pDevice, NULL, pMappedBuffer, framesToRead);
ma_pcm_rb_commit_read(&pDeviceStatePipeWire->capture.rb, framesToRead);
framesAvailable -= framesToRead;
}
}
ma_device_handle_backend_data_callback(pDevice, NULL, pMappedBuffer, framesAvailable);
ma_audio_ring_buffer_unmap_consume(&pDeviceStatePipeWire->capture.rb, framesAvailable);
}
if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) {
ma_uint32 framesAvailable;
framesAvailable = ma_pcm_rb_available_write(&pDeviceStatePipeWire->playback.rb);
framesAvailable = ma_audio_ring_buffer_map_produce(&pDeviceStatePipeWire->playback.rb, 0xFFFFFFFF, &pMappedBuffer);
if (framesAvailable > 0) {
hasProcessedData = MA_TRUE;
}
while (framesAvailable > 0) {
void* pMappedBuffer;
ma_uint32 framesToWrite = framesAvailable;
ma_result result;
result = ma_pcm_rb_acquire_write(&pDeviceStatePipeWire->playback.rb, &framesToWrite, &pMappedBuffer);
if (result == MA_SUCCESS) {
ma_device_handle_backend_data_callback(pDevice, pMappedBuffer, NULL, framesToWrite);
ma_pcm_rb_commit_write(&pDeviceStatePipeWire->playback.rb, framesToWrite);
framesAvailable -= framesToWrite;
}
}
ma_device_handle_backend_data_callback(pDevice, pMappedBuffer, NULL, framesAvailable);
ma_audio_ring_buffer_unmap_produce(&pDeviceStatePipeWire->playback.rb, framesAvailable);
}
}