mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-02 09:01:50 -05:00
channelmix: improve control handling
We can't write to the input control buffer so keep track of the control offset ourselves ans skip what we already handled.
This commit is contained in:
parent
5e37131cf8
commit
055c8d6b63
1 changed files with 49 additions and 91 deletions
|
|
@ -105,6 +105,9 @@ struct port {
|
|||
uint32_t n_buffers;
|
||||
|
||||
struct spa_list queue;
|
||||
|
||||
struct spa_pod_sequence *ctrl;
|
||||
uint32_t ctrl_offset;
|
||||
};
|
||||
|
||||
struct impl {
|
||||
|
|
@ -897,106 +900,48 @@ static int impl_node_port_reuse_buffer(void *object, uint32_t port_id, uint32_t
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int update_control_sequence(struct spa_pod_sequence *ctrl_sequence,
|
||||
uint32_t ctrl_size, uint32_t curr_ctrl, uint32_t curr_offset)
|
||||
{
|
||||
struct spa_pod_control *c;
|
||||
struct spa_pod_builder b;
|
||||
struct spa_pod_frame f[1];
|
||||
uint32_t i = 0;
|
||||
|
||||
spa_return_val_if_fail(ctrl_sequence != NULL, -EINVAL);
|
||||
spa_return_val_if_fail(ctrl_size > 0, -EINVAL);
|
||||
spa_return_val_if_fail(curr_offset > 0, -EINVAL);
|
||||
|
||||
/* copy the sequence */
|
||||
uint8_t old[ctrl_size];
|
||||
memcpy(old, ctrl_sequence, ctrl_size);
|
||||
|
||||
/* reset the current sequence */
|
||||
spa_pod_builder_init(&b, ctrl_sequence, ctrl_size);
|
||||
spa_pod_builder_push_sequence(&b, &f[0], 0);
|
||||
|
||||
/* add the remaining controls */
|
||||
SPA_POD_SEQUENCE_FOREACH(&((struct spa_io_sequence *)old)->sequence, c) {
|
||||
switch (c->type) {
|
||||
case SPA_CONTROL_Properties:
|
||||
{
|
||||
if (i >= curr_ctrl) {
|
||||
spa_pod_builder_control(&b,
|
||||
i == curr_ctrl ? curr_offset : c->offset,
|
||||
SPA_CONTROL_Properties);
|
||||
spa_pod_builder_primitive(&b, &c->value);
|
||||
}
|
||||
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
spa_pod_builder_pop(&b, &f[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int channelmix_process_control(struct impl *this, struct buffer *cbuf,
|
||||
static int channelmix_process_control(struct impl *this, struct port *ctrlport,
|
||||
uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
|
||||
uint32_t n_src, const void * SPA_RESTRICT src[n_src],
|
||||
uint32_t n_samples)
|
||||
{
|
||||
struct spa_pod_sequence *ctrl_sequence;
|
||||
uint32_t ctrl_size;
|
||||
struct spa_pod_control *c;
|
||||
struct spa_pod_control *c, *prev = NULL;
|
||||
uint32_t avail_samples = n_samples;
|
||||
uint32_t i, j;
|
||||
uint32_t i;
|
||||
const float **s = (const float **)src;
|
||||
float **d = (float **)dst;
|
||||
|
||||
/* get the control sequence */
|
||||
spa_return_val_if_fail(cbuf != NULL, -EINVAL);
|
||||
spa_return_val_if_fail(cbuf->outbuf->n_datas == 1, -EINVAL);
|
||||
ctrl_sequence = (struct spa_pod_sequence *)cbuf->outbuf->datas[0].data;
|
||||
ctrl_size = cbuf->outbuf->datas[0].maxsize;
|
||||
|
||||
i = 0;
|
||||
SPA_POD_SEQUENCE_FOREACH(ctrl_sequence, c) {
|
||||
SPA_POD_SEQUENCE_FOREACH(ctrlport->ctrl, c) {
|
||||
switch (c->type) {
|
||||
case SPA_CONTROL_Properties:
|
||||
{
|
||||
/* update the sequence and return if all samples were processed */
|
||||
if (avail_samples == 0) {
|
||||
update_control_sequence(ctrl_sequence, ctrl_size, i, c->offset);
|
||||
uint32_t chunk;
|
||||
|
||||
if (avail_samples == 0)
|
||||
return 0;
|
||||
|
||||
/* ignore old control offsets */
|
||||
if (c->offset <= ctrlport->ctrl_offset) {
|
||||
prev = c;
|
||||
continue;
|
||||
}
|
||||
if (prev)
|
||||
apply_props(this, &prev->value);
|
||||
prev = c;
|
||||
|
||||
/* apply the sequence control props */
|
||||
apply_props(this, &c->value);
|
||||
chunk = SPA_MIN(avail_samples, c->offset - ctrlport->ctrl_offset);
|
||||
|
||||
if (c->offset > 0) {
|
||||
/* get the minimum offset for this buffer */
|
||||
uint32_t offset = SPA_MIN(avail_samples, c->offset);
|
||||
spa_log_trace_fp(this->log, NAME " %p: process %d %d", this,
|
||||
c->offset, chunk);
|
||||
|
||||
/* process the control sequence */
|
||||
channelmix_process(&this->mix, n_dst, dst, n_src, src, offset);
|
||||
for (j = 0; j < n_src; j++)
|
||||
s[j] += offset;
|
||||
for (j = 0; j < n_dst; j++)
|
||||
d[j] += offset;
|
||||
channelmix_process(&this->mix, n_dst, dst, n_src, src, chunk);
|
||||
for (i = 0; i < n_src; i++)
|
||||
s[i] += chunk;
|
||||
for (i = 0; i < n_dst; i++)
|
||||
d[i] += chunk;
|
||||
|
||||
/* update the sequence with the remaining offset samples */
|
||||
if (avail_samples < c->offset) {
|
||||
update_control_sequence(ctrl_sequence, ctrl_size, i, c->offset - avail_samples);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* decrease available samples */
|
||||
avail_samples -= offset;
|
||||
}
|
||||
|
||||
i++;
|
||||
avail_samples -= chunk;
|
||||
ctrlport->ctrl_offset += chunk;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
@ -1004,10 +949,11 @@ static int channelmix_process_control(struct impl *this, struct buffer *cbuf,
|
|||
}
|
||||
}
|
||||
|
||||
/* process the remaining samples */
|
||||
/* when we get here we run out of control points but still have some
|
||||
* remaining samples */
|
||||
spa_log_trace_fp(this->log, NAME " %p: remain %d", this, avail_samples);
|
||||
if (avail_samples > 0)
|
||||
channelmix_process(&this->mix, n_dst, dst, n_src, src, avail_samples);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -1016,7 +962,8 @@ static int impl_node_process(void *object)
|
|||
struct impl *this = object;
|
||||
struct port *outport, *inport, *ctrlport;
|
||||
struct spa_io_buffers *outio, *inio, *ctrlio;
|
||||
struct buffer *sbuf, *dbuf, *cbuf = NULL;
|
||||
struct buffer *sbuf, *dbuf;
|
||||
struct spa_pod_sequence *ctrl = NULL;
|
||||
|
||||
spa_return_val_if_fail(this != NULL, -EINVAL);
|
||||
|
||||
|
|
@ -1055,8 +1002,18 @@ static int impl_node_process(void *object)
|
|||
|
||||
if (ctrlio != NULL &&
|
||||
ctrlio->status == SPA_STATUS_HAVE_DATA &&
|
||||
ctrlio->buffer_id < ctrlport->n_buffers)
|
||||
cbuf = &ctrlport->buffers[ctrlio->buffer_id];
|
||||
ctrlio->buffer_id < ctrlport->n_buffers) {
|
||||
struct buffer *cbuf = &ctrlport->buffers[ctrlio->buffer_id];
|
||||
struct spa_data *d = &cbuf->outbuf->datas[0];
|
||||
|
||||
ctrl = spa_pod_from_data(d->data, d->maxsize, d->chunk->offset, d->chunk->size);
|
||||
if (ctrl && !spa_pod_is_sequence(&ctrl->pod))
|
||||
ctrl = NULL;
|
||||
if (ctrl != ctrlport->ctrl) {
|
||||
ctrlport->ctrl = ctrl;
|
||||
ctrlport->ctrl_offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
uint32_t i, n_samples;
|
||||
|
|
@ -1067,7 +1024,7 @@ static int impl_node_process(void *object)
|
|||
void *dst_datas[n_dst_datas];
|
||||
bool is_passthrough;
|
||||
|
||||
is_passthrough = this->is_passthrough && this->mix.identity && cbuf == NULL;
|
||||
is_passthrough = this->is_passthrough && this->mix.identity && ctrlport->ctrl == NULL;
|
||||
|
||||
n_samples = sb->datas[0].chunk->size / inport->stride;
|
||||
|
||||
|
|
@ -1083,11 +1040,12 @@ static int impl_node_process(void *object)
|
|||
this, n_src_datas, n_dst_datas, n_samples, is_passthrough);
|
||||
|
||||
if (!is_passthrough) {
|
||||
if (cbuf != NULL) {
|
||||
if (ctrlport->ctrl != NULL) {
|
||||
/* if return value is 1, the sequence has been processed */
|
||||
if (channelmix_process_control(this, cbuf, n_dst_datas, dst_datas,
|
||||
if (channelmix_process_control(this, ctrlport, n_dst_datas, dst_datas,
|
||||
n_src_datas, src_datas, n_samples) == 1) {
|
||||
ctrlio->status = SPA_STATUS_OK;
|
||||
ctrlport->ctrl = NULL;
|
||||
}
|
||||
} else {
|
||||
channelmix_process(&this->mix, n_dst_datas, dst_datas,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue