examples: improve the ring2 example

Make a function to make a block of samples that we then push into the
ringbuffer. This should match more with what audio backends need to
handle.
This commit is contained in:
Wim Taymans 2024-09-30 16:14:37 +02:00
parent 63747e2e40
commit 273a2b65a2

View file

@ -29,6 +29,11 @@
#define BUFFER_SIZE (16*1024) #define BUFFER_SIZE (16*1024)
#define MIN_SIZE 256
#define MAX_SIZE BUFFER_SIZE
static float samples[BUFFER_SIZE * DEFAULT_CHANNELS];
struct data { struct data {
struct pw_thread_loop *thread_loop; struct pw_thread_loop *thread_loop;
struct pw_loop *loop; struct pw_loop *loop;
@ -42,7 +47,7 @@ struct data {
float buffer[BUFFER_SIZE * DEFAULT_CHANNELS]; float buffer[BUFFER_SIZE * DEFAULT_CHANNELS];
}; };
static void fill_f32(struct data *d, uint32_t offset, int n_frames) static void fill_f32(struct data *d, float *samples, int n_frames)
{ {
float val; float val;
int i, c; int i, c;
@ -54,40 +59,52 @@ static void fill_f32(struct data *d, uint32_t offset, int n_frames)
val = sinf(d->accumulator) * DEFAULT_VOLUME; val = sinf(d->accumulator) * DEFAULT_VOLUME;
for (c = 0; c < DEFAULT_CHANNELS; c++) for (c = 0; c < DEFAULT_CHANNELS; c++)
d->buffer[((offset + i) % BUFFER_SIZE) * DEFAULT_CHANNELS + c] = val; samples[i * DEFAULT_CHANNELS + c] = val;
} }
} }
/* this is called from the main-thread as fast as possible. It will block until /* this can be called from any thread with a block of samples to write into
* more data can be written */ * the ringbuffer. It will block until all data has been written */
static void push_refill(void *userdata) static void push_samples(void *userdata, float *samples, uint32_t n_samples)
{ {
struct data *data = userdata; struct data *data = userdata;
int32_t filled; int32_t filled;
uint32_t index, avail; uint32_t index, avail, stride = sizeof(float) * DEFAULT_CHANNELS;
uint64_t count; uint64_t count;
float *s = samples;
while (true) { while (n_samples > 0) {
filled = spa_ringbuffer_get_write_index(&data->ring, &index); while (true) {
/* we xrun, this can not happen because we never read more filled = spa_ringbuffer_get_write_index(&data->ring, &index);
* than what there is in the ringbuffer and we never write more than /* we xrun, this can not happen because we never read more
* what is left */ * than what there is in the ringbuffer and we never write more than
spa_assert(filled >= 0); * what is left */
spa_assert(filled <= BUFFER_SIZE); spa_assert(filled >= 0);
spa_assert(filled <= BUFFER_SIZE);
/* this is how much samples we can write */ /* this is how much samples we can write */
avail = BUFFER_SIZE - filled; avail = BUFFER_SIZE - filled;
if (avail > 0) if (avail > 0)
break; break;
/* no space.. block and wait for free space */ /* no space.. block and wait for free space */
spa_system_eventfd_read(data->loop->system, data->eventfd, &count); spa_system_eventfd_read(data->loop->system, data->eventfd, &count);
}
if (avail > n_samples)
avail = n_samples;
spa_ringbuffer_write_data(&data->ring,
data->buffer, BUFFER_SIZE * stride,
(index % BUFFER_SIZE) * stride,
s, avail * stride);
s += avail * DEFAULT_CHANNELS;
n_samples -= avail;
/* and advance the ringbuffer */
spa_ringbuffer_write_update(&data->ring, index + avail);
} }
/* write new samples to the ringbuffer from the given index */
fill_f32(data, index, avail);
/* and advance the ringbuffer */
spa_ringbuffer_write_update(&data->ring, index + avail);
} }
/* our data processing function is in general: /* our data processing function is in general:
@ -226,15 +243,19 @@ int main(int argc, char *argv[])
params, 1); params, 1);
/* prefill the ringbuffer */ /* prefill the ringbuffer */
push_refill(&data); fill_f32(&data, samples, BUFFER_SIZE);
push_samples(&data, samples, BUFFER_SIZE);
srand(time(NULL));
pw_thread_loop_start(data.thread_loop); pw_thread_loop_start(data.thread_loop);
pw_thread_loop_unlock(data.thread_loop); pw_thread_loop_unlock(data.thread_loop);
while (data.running) { while (data.running) {
/* just keep on pushing data as fast as we can, this can be done uint32_t size = rand() % ((MAX_SIZE - MIN_SIZE + 1) + MIN_SIZE);
* from any thread. */ /* make new random sized block of samples and push */
push_refill(&data); fill_f32(&data, samples, size);
push_samples(&data, samples, size);
} }
pw_thread_loop_lock(data.thread_loop); pw_thread_loop_lock(data.thread_loop);