adapter: only recheck formats when convert EnumFormat changed

Instead of always renegotiating a new format and buffers when the
driver changes, only renegotiate when the converter notifies us
of an EnumFormat change. It's possible that changing the driver does
not actually change the result of EnumFormat and then we would simply
renegotiate to the same format and buffers for nothing.

In the audioconvert, check if the target_rate of the new driver has
changed. We keep the last value in our own clock so that we don't
renegotiate when we are removed from a driver (which sets our own
clock as the position). The target rate influences the result of the
EnumFormat params when we are resampling and so we need to emit a
EnumFormat change.
This commit is contained in:
Wim Taymans 2025-10-30 17:32:09 +01:00
parent ece9545695
commit e9a89822f8
2 changed files with 43 additions and 4 deletions

View file

@ -931,7 +931,6 @@ static int impl_node_set_io(void *object, uint32_t id, void *data, size_t size)
switch (id) {
case SPA_IO_Position:
this->io_position = data;
this->recheck_format = true;
break;
default:
break;
@ -1220,6 +1219,9 @@ static void follower_convert_port_info(void *data,
case SPA_PARAM_Tag:
idx = IDX_Tag;
break;
case SPA_PARAM_EnumFormat:
idx = IDX_EnumFormat;
break;
default:
continue;
}
@ -1247,6 +1249,11 @@ static void follower_convert_port_info(void *data,
spa_log_debug(this->log, "tag: %d (%s)", res,
spa_strerror(res));
}
if (idx == IDX_EnumFormat) {
spa_log_info(this->log, "new EnumFormat from converter");
/* we will renegotiate when restarting */
this->recheck_format = true;
}
spa_log_debug(this->log, "param %d changed", info->params[i].id);
}
}
@ -1445,7 +1452,7 @@ static void follower_port_info(void *data,
spa_strerror(res));
}
if (idx == IDX_EnumFormat) {
spa_log_debug(this->log, "new formats");
spa_log_debug(this->log, "new EnumFormat from follower");
/* we will renegotiate when restarting */
this->recheck_format = true;
}

View file

@ -282,6 +282,7 @@ struct impl {
struct props props;
struct spa_io_clock *io_clock;
struct spa_io_position *io_position;
struct spa_io_rate_match *io_rate_match;
@ -1005,12 +1006,43 @@ static int impl_node_set_io(void *object, uint32_t id, void *data, size_t size)
spa_log_debug(this->log, "%p: io %d %p/%zd", this, id, data, size);
switch (id) {
case SPA_IO_Position:
this->io_position = data;
case SPA_IO_Clock:
this->io_clock = data;
break;
case SPA_IO_Position:
{
struct port *p;
uint32_t i;
this->io_position = data;
if (this->io_position && this->io_clock &&
this->io_position->clock.target_rate.denom != this->io_clock->target_rate.denom &&
!this->props.resample_disabled) {
spa_log_warn(this->log, "driver %d changed rate:%u -> %u", this->io_position->clock.id,
this->io_clock->target_rate.denom,
this->io_position->clock.target_rate.denom);
this->io_clock->target_rate = this->io_position->clock.target_rate;
for (i = 0; i < this->dir[SPA_DIRECTION_INPUT].n_ports; i++) {
if ((p = GET_IN_PORT(this, i)) && p->valid && !p->is_dsp && !p->is_control) {
p->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
p->params[IDX_EnumFormat].user++;
}
}
for (i = 0; i < this->dir[SPA_DIRECTION_OUTPUT].n_ports; i++) {
if ((p = GET_OUT_PORT(this, i)) && p->valid && !p->is_dsp && !p->is_control) {
p->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
p->params[IDX_EnumFormat].user++;
}
}
}
break;
}
default:
return -ENOENT;
}
emit_info(this, false);
return 0;
}