examples: improve the ringbuffer example a little

Write the remaining samples in the ringbuffer and fill up the rest with
silence.

Add some more comments.
This commit is contained in:
Wim Taymans 2024-09-23 11:28:16 +02:00
parent ca488a5dcc
commit e095a1c4ac

View file

@ -55,6 +55,8 @@ static void fill_f32(struct data *d, uint32_t offset, int n_frames)
} }
} }
/* this is called from the main-thread when we need to fill up the ringbuffer
* with more data */
static void do_refill(void *userdata, uint64_t count) static void do_refill(void *userdata, uint64_t count)
{ {
struct data *data = userdata; struct data *data = userdata;
@ -84,6 +86,8 @@ static void do_refill(void *userdata, uint64_t count)
* b = pw_stream_dequeue_buffer(stream); * b = pw_stream_dequeue_buffer(stream);
* *
* .. generate stuff in the buffer ... * .. generate stuff in the buffer ...
* In this case we read samples from a ringbuffer. The ringbuffer is
* filled up by another thread.
* *
* pw_stream_queue_buffer(stream, b); * pw_stream_queue_buffer(stream, b);
*/ */
@ -92,10 +96,9 @@ static void on_process(void *userdata)
struct data *data = userdata; struct data *data = userdata;
struct pw_buffer *b; struct pw_buffer *b;
struct spa_buffer *buf; struct spa_buffer *buf;
int n_frames, stride;
uint8_t *p; uint8_t *p;
uint32_t index; uint32_t index, to_read, to_silence;
int32_t avail; int32_t avail, n_frames, stride;
if ((b = pw_stream_dequeue_buffer(data->stream)) == NULL) { if ((b = pw_stream_dequeue_buffer(data->stream)) == NULL) {
pw_log_warn("out of buffers: %m"); pw_log_warn("out of buffers: %m");
@ -112,32 +115,35 @@ static void on_process(void *userdata)
stride = sizeof(float) * DEFAULT_CHANNELS; stride = sizeof(float) * DEFAULT_CHANNELS;
n_frames = buf->datas[0].maxsize / stride; n_frames = buf->datas[0].maxsize / stride;
if (b->requested) if (b->requested)
n_frames = SPA_MIN((int)b->requested, n_frames); n_frames = SPA_MIN((int32_t)b->requested, n_frames);
if (avail < (int32_t)n_frames) { /* we can read if there is something available */
/* there is not enough data available in the ringbuffer, to_read = avail > 0 ? SPA_MIN(avail, n_frames) : 0;
* fill with silence and hope it will be filled next time */ /* and fill the remainder with silence */
memset(p, 0, n_frames * stride); to_silence = n_frames - to_read;
pw_log_warn("underrun");
} else { if (to_read > 0) {
/* enough data in the ringbuffer, copy it into the buffer data. /* read data into the buffer */
* We use the number of samples as the read/write counters so we
* need to multiply with the stride to get the byte offsets. */
spa_ringbuffer_read_data(&data->ring, spa_ringbuffer_read_data(&data->ring,
data->buffer, BUFFER_SIZE * stride, data->buffer, BUFFER_SIZE * stride,
(index % BUFFER_SIZE) * stride, (index % BUFFER_SIZE) * stride,
p, n_frames * stride); p, to_read * stride);
/* update the read pointer */ /* update the read pointer */
spa_ringbuffer_read_update(&data->ring, index + n_frames); spa_ringbuffer_read_update(&data->ring, index + to_read);
} }
if (to_silence > 0)
/* set the rest of the buffer to silence */
memset(SPA_PTROFF(p, to_read * stride, void), 0, to_silence * stride);
buf->datas[0].chunk->offset = 0; buf->datas[0].chunk->offset = 0;
buf->datas[0].chunk->stride = stride; buf->datas[0].chunk->stride = stride;
buf->datas[0].chunk->size = n_frames * stride; buf->datas[0].chunk->size = n_frames * stride;
pw_stream_queue_buffer(data->stream, b); pw_stream_queue_buffer(data->stream, b);
/* signal the main thread to fill the ringbuffer */ /* signal the main thread to fill the ringbuffer, we can only do this, for
* example when the available ringbuffer space falls below a certain
* level. */
pw_loop_signal_event(data->loop, data->refill_event); pw_loop_signal_event(data->loop, data->refill_event);
} }