LADI
/
spa
1
Fork 0

modules: avoid partial writes to pulseaudio

Pulseaudio requires that we call pa_stream_write with a multiple
of frame_size bytes. Because our ringbuffer is a power of two, this
might cause problems at the edge of ringbuffer where a sample is
split between the end and beginning of the ringbuffer.

Avoid this by letting pulse allocate a buffer instead and memcpy
the requires samples into it.

Fixes multichannel output on module-pulse-tunnel.
This commit is contained in:
Wim Taymans 2022-10-18 13:14:32 +02:00
parent e6356f7415
commit 88785c42e5
1 changed files with 27 additions and 22 deletions

View File

@ -524,9 +524,10 @@ static void stream_write_request_cb(pa_stream *s, size_t length, void *userdata)
{
struct impl *impl = userdata;
int32_t avail;
uint32_t index, len, offset, l0, l1;
uint32_t index;
size_t size;
pa_usec_t latency;
int negative;
int negative, res;
if (impl->resync) {
impl->resync = false;
@ -542,30 +543,34 @@ static void stream_write_request_cb(pa_stream *s, size_t length, void *userdata)
impl->current_latency += avail / impl->frame_size;
while (avail < (int32_t)length) {
uint32_t maxsize = SPA_ROUND_DOWN(sizeof(impl->empty), impl->frame_size);
/* send silence for the data we don't have */
len = SPA_MIN(length - avail, sizeof(impl->empty));
pa_stream_write(impl->pa_stream,
impl->empty, len,
NULL, 0, PA_SEEK_RELATIVE);
length -= len;
size = SPA_MIN(length - avail, maxsize);
if ((res = pa_stream_write(impl->pa_stream,
impl->empty, size,
NULL, 0, PA_SEEK_RELATIVE)) != 0)
pw_log_warn("error writing stream: %s", pa_strerror(res));
length -= size;
}
if (length > 0 && avail >= (int32_t)length) {
/* always send as much as is requested */
len = length;
offset = index & RINGBUFFER_MASK;
l0 = SPA_MIN(len, RINGBUFFER_SIZE - offset);
l1 = len - l0;
while (length > 0 && avail >= (int32_t)length) {
void *data;
pa_stream_write(impl->pa_stream,
SPA_PTROFF(impl->buffer, offset, void), l0,
NULL, 0, PA_SEEK_RELATIVE);
size = length;
pa_stream_begin_write(impl->pa_stream, &data, &size);
if (SPA_UNLIKELY(l1 > 0)) {
pa_stream_write(impl->pa_stream,
impl->buffer, l1,
NULL, 0, PA_SEEK_RELATIVE);
}
index += len;
spa_ringbuffer_read_data(&impl->ring,
impl->buffer, RINGBUFFER_SIZE,
index & RINGBUFFER_MASK,
data, size);
if ((res = pa_stream_write(impl->pa_stream,
data, size, NULL, 0, PA_SEEK_RELATIVE)) != 0)
pw_log_warn("error writing stream: %zd %s", size,
pa_strerror(res));
index += size;
length -= size;
avail -= size;
spa_ringbuffer_read_update(&impl->ring, index);
}
}