jack: reorganize jack_port_get_buffer()

Dequeue a new buffer only once and reuse this queued buffer when
jack_port_get_buffer() is called multiple times in process().

Recycle an old buffer in the next cycle.

After calling process, mark all input buffers as consumed, process the
empty buffers and move the output buffers to the mix ports.

Fixes #1748
This commit is contained in:
Wim Taymans 2021-10-26 12:28:31 +02:00
parent 6f75b1433c
commit 31f387868a

View file

@ -972,31 +972,32 @@ static inline void *get_buffer_output(struct port *p, uint32_t frames, uint32_t
struct mix *mix;
struct client *c = p->client;
void *ptr = NULL;
p->io.status = -EPIPE;
p->io.buffer_id = SPA_ID_INVALID;
struct buffer *b;
if (frames == 0)
return NULL;
if (SPA_LIKELY((mix = p->global_mix) != NULL)) {
struct buffer *b;
if (SPA_UNLIKELY((mix = p->global_mix) == NULL))
return NULL;
if (SPA_UNLIKELY(mix->n_buffers == 0))
goto done;
pw_log_trace_fp("%p: port %p %d get buffer %d n_buffers:%d",
c, p, p->id, frames, mix->n_buffers);
pw_log_trace_fp("%p: port %p %d get buffer %d n_buffers:%d",
c, p, p->id, frames, mix->n_buffers);
if (SPA_UNLIKELY(mix->n_buffers == 0))
return NULL;
if (SPA_UNLIKELY((b = dequeue_buffer(mix)) == NULL)) {
pw_log_warn("port %p: out of buffers", p);
goto done;
if (p->io.status == SPA_STATUS_HAVE_DATA &&
p->io.buffer_id < mix->n_buffers) {
b = &mix->buffers[p->io.buffer_id];
} else {
if (p->io.buffer_id < mix->n_buffers) {
reuse_buffer(c, mix, p->io.buffer_id);
p->io.buffer_id = SPA_ID_INVALID;
}
if (SPA_UNLIKELY((b = dequeue_buffer(c, mix)) == NULL)) {
pw_log_warn("port %p: out of buffers", p);
return NULL;
}
reuse_buffer(c, mix, b->id);
ptr = b->datas[0].data;
if (buf)
*buf = b;
b->datas[0].chunk->offset = 0;
b->datas[0].chunk->size = frames * sizeof(float);
b->datas[0].chunk->stride = stride;
@ -1004,48 +1005,58 @@ static inline void *get_buffer_output(struct port *p, uint32_t frames, uint32_t
p->io.status = SPA_STATUS_HAVE_DATA;
p->io.buffer_id = b->id;
}
done:
spa_list_for_each(mix, &p->mix, port_link) {
struct spa_io_buffers *mio = mix->io;
if (SPA_UNLIKELY(mio == NULL))
continue;
pw_log_trace_fp("%p: port %p tee %d.%d get buffer %d io:%p",
c, p, p->id, mix->id, frames, mio);
*mio = p->io;
}
ptr = b->datas[0].data;
if (buf)
*buf = b;
return ptr;
}
static void process_tee(struct client *c, uint32_t frames)
static inline void process_empty(struct port *p, uint32_t frames)
{
void *ptr;
switch (p->object->port.type_id) {
case TYPE_ID_AUDIO:
ptr = get_buffer_output(p, frames, sizeof(float), NULL);
if (SPA_LIKELY(ptr != NULL))
memcpy(ptr, p->emptyptr, frames * sizeof(float));
break;
case TYPE_ID_MIDI:
{
struct buffer *b;
ptr = get_buffer_output(p, MAX_BUFFER_FRAMES, 1, &b);
if (SPA_LIKELY(ptr != NULL)) {
b->datas[0].chunk->size = convert_from_midi(p->emptyptr,
ptr, MAX_BUFFER_FRAMES * sizeof(float));
}
break;
}
default:
pw_log_warn("port %p: unhandled format %d", p, p->object->port.type_id);
break;
}
}
static void complete_process(struct client *c, uint32_t frames)
{
struct port *p;
struct mix *mix;
spa_list_for_each(p, &c->ports[SPA_DIRECTION_INPUT], link) {
spa_list_for_each(mix, &p->mix, port_link) {
if (SPA_LIKELY(mix->io != NULL))
mix->io->status = SPA_STATUS_NEED_DATA;
}
}
spa_list_for_each(p, &c->ports[SPA_DIRECTION_OUTPUT], link) {
void *ptr;
if (SPA_UNLIKELY(p->empty_out))
process_empty(p, frames);
if (SPA_LIKELY(!p->empty_out))
continue;
switch (p->object->port.type_id) {
case TYPE_ID_AUDIO:
ptr = get_buffer_output(p, frames, sizeof(float), NULL);
if (SPA_LIKELY(ptr != NULL))
memcpy(ptr, p->emptyptr, frames * sizeof(float));
break;
case TYPE_ID_MIDI:
{
struct buffer *b;
ptr = get_buffer_output(p, MAX_BUFFER_FRAMES, 1, &b);
if (SPA_LIKELY(ptr != NULL)) {
b->datas[0].chunk->size = convert_from_midi(p->emptyptr,
ptr, MAX_BUFFER_FRAMES * sizeof(float));
}
break;
}
default:
pw_log_warn("port %p: unhandled format %d", p, p->object->port.type_id);
break;
spa_list_for_each(mix, &p->mix, port_link) {
if (SPA_LIKELY(mix->io != NULL))
*mix->io = p->io;
}
p->io.status = SPA_STATUS_NEED_DATA;
}
}
@ -1312,7 +1323,7 @@ static inline void signal_sync(struct client *c)
struct link *l;
struct pw_node_activation *activation = c->activation;
process_tee(c, c->buffer_frames);
complete_process(c, c->buffer_frames);
clock_gettime(CLOCK_MONOTONIC, &ts);
nsec = SPA_TIMESPEC_TO_NSEC(&ts);
@ -4086,7 +4097,6 @@ static void *get_buffer_input_float(struct port *p, jack_nframes_t frames)
if ((b = get_mix_buffer(mix)) == NULL)
continue;
mix->io->status = SPA_STATUS_NEED_DATA;
if (layer++ == 0)
ptr = b->datas[0].data;
else {
@ -4103,7 +4113,6 @@ static void *get_buffer_input_float(struct port *p, jack_nframes_t frames)
static void *get_buffer_input_midi(struct port *p, jack_nframes_t frames)
{
struct mix *mix;
struct spa_io_buffers *io;
void *ptr = p->emptyptr;
struct spa_pod_sequence *seq[CONNECTION_NUM_FOR_PORT];
uint32_t n_seq = 0;
@ -4112,19 +4121,16 @@ static void *get_buffer_input_midi(struct port *p, jack_nframes_t frames)
spa_list_for_each(mix, &p->mix, port_link) {
struct spa_data *d;
struct buffer *b;
void *pod;
pw_log_trace_fp("%p: port %p mix %d.%d get buffer %d",
p->client, p, p->id, mix->id, frames);
io = mix->io;
if (io == NULL ||
io->status != SPA_STATUS_HAVE_DATA ||
io->buffer_id >= mix->n_buffers)
if ((b = get_mix_buffer(mix)) == NULL)
continue;
io->status = SPA_STATUS_NEED_DATA;
d = &mix->buffers[io->buffer_id].datas[0];
d = &b->datas[0];
if ((pod = spa_pod_from_data(d->data, d->maxsize, d->chunk->offset, d->chunk->size)) == NULL)
continue;