mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-02 09:01:50 -05:00
audioconvert2: more improvements
Use a wildcard rate for DSP ports. Handle wildcards for rate and channels. Calculate required in/out samples using quantum Limit monitor and output number of samples.
This commit is contained in:
parent
c0f34e9d9d
commit
3806cdaa6f
1 changed files with 91 additions and 31 deletions
|
|
@ -884,6 +884,7 @@ static int reconfigure_mode(struct impl *this, enum spa_param_port_config_mode m
|
|||
dir->n_ports = info->info.raw.channels;
|
||||
dir->format = *info;
|
||||
dir->format.info.raw.format = SPA_AUDIO_FORMAT_DSP_F32;
|
||||
dir->format.info.raw.rate = 0;
|
||||
dir->have_format = true;
|
||||
} else {
|
||||
dir->n_ports = 0;
|
||||
|
|
@ -1307,6 +1308,19 @@ static int setup_convert(struct impl *this)
|
|||
|
||||
if (!in->have_format || !out->have_format)
|
||||
return -EINVAL;
|
||||
if (in->format.info.raw.rate == 0 && out->format.info.raw.rate == 0)
|
||||
return -EINVAL;
|
||||
if (in->format.info.raw.channels == 0 && out->format.info.raw.channels == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (in->format.info.raw.rate == 0)
|
||||
in->format.info.raw.rate = out->format.info.raw.rate;
|
||||
else if (out->format.info.raw.rate == 0)
|
||||
out->format.info.raw.rate = in->format.info.raw.rate;
|
||||
if (in->format.info.raw.channels == 0)
|
||||
in->format.info.raw.channels = out->format.info.raw.channels;
|
||||
else if (out->format.info.raw.channels == 0)
|
||||
out->format.info.raw.channels = in->format.info.raw.channels;
|
||||
|
||||
setup_in_convert(this);
|
||||
setup_channelmix(this);
|
||||
|
|
@ -1991,31 +2005,28 @@ static inline bool resample_is_passthrough(struct impl *this)
|
|||
!SPA_FLAG_IS_SET(this->io_rate_match->flags, SPA_IO_RATE_MATCH_FLAG_ACTIVE));
|
||||
}
|
||||
|
||||
static void resample_recalc_rate_match(struct impl *this, bool passthrough)
|
||||
{
|
||||
uint32_t out_size = this->io_position ? this->io_position->clock.duration : this->quantum_limit;
|
||||
resample_update_rate_match(this, passthrough, out_size, 0);
|
||||
}
|
||||
|
||||
static int impl_node_process(void *object)
|
||||
{
|
||||
struct impl *this = object;
|
||||
const void *src_datas[MAX_PORTS], **in_datas;
|
||||
void *dst_datas[MAX_PORTS], *mon_datas[MAX_PORTS], **out_datas;
|
||||
uint32_t i, j, n_src_datas = 0, n_dst_datas = 0, n_mon_datas = 0, n_samples;
|
||||
uint32_t i, j, n_src_datas = 0, n_dst_datas = 0, n_mon_datas = 0;
|
||||
uint32_t in_samples, max_mon, max_out, out_samples, quant_samples;
|
||||
struct port *port;
|
||||
struct buffer *buf;
|
||||
struct spa_data *bd, *dst_bufs[MAX_PORTS];
|
||||
struct dir *dir;
|
||||
int tmp = 0;
|
||||
bool in_passthrough, mix_passthrough, resample_passthrough, out_passthrough, end_passthrough;
|
||||
bool flush_out;
|
||||
uint32_t in_len, out_len, remap;
|
||||
|
||||
dir = &this->dir[SPA_DIRECTION_INPUT];
|
||||
in_passthrough = dir->conv.is_passthrough;
|
||||
|
||||
n_samples = UINT32_MAX;
|
||||
in_samples = UINT32_MAX;
|
||||
|
||||
/* collect input port data */
|
||||
for (i = 0; i < dir->n_ports; i++) {
|
||||
port = GET_IN_PORT(this, i);
|
||||
|
||||
|
|
@ -2034,24 +2045,52 @@ static int impl_node_process(void *object)
|
|||
|
||||
src_datas[remap] = SPA_PTROFF(bd->data, bd->chunk->offset, void);
|
||||
|
||||
n_samples = SPA_MIN(n_samples, bd->chunk->size / port->stride);
|
||||
in_samples = SPA_MIN(in_samples, bd->chunk->size / port->stride);
|
||||
|
||||
spa_log_trace_fp(this->log, "%p: %d %d %d->%d", this,
|
||||
bd->chunk->size, n_samples,
|
||||
bd->chunk->size, in_samples,
|
||||
i * port->blocks + j, remap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* calculate quantum scale */
|
||||
if (SPA_LIKELY(this->io_position)) {
|
||||
double r = this->rate_scale;
|
||||
|
||||
quant_samples = this->io_position->clock.duration;
|
||||
if (this->direction == SPA_DIRECTION_INPUT) {
|
||||
if (this->io_position->clock.rate.denom != this->resample.o_rate)
|
||||
r = (double) this->io_position->clock.rate.denom / this->resample.o_rate;
|
||||
else
|
||||
r = 1.0;
|
||||
} else {
|
||||
if (this->io_position->clock.rate.denom != this->resample.i_rate)
|
||||
r = (double) this->resample.i_rate / this->io_position->clock.rate.denom;
|
||||
else
|
||||
r = 1.0;
|
||||
}
|
||||
if (this->rate_scale != r) {
|
||||
spa_log_info(this->log, "scale %f->%f", this->rate_scale, r);
|
||||
this->rate_scale = r;
|
||||
}
|
||||
}
|
||||
else
|
||||
quant_samples = this->quantum_limit;
|
||||
|
||||
resample_passthrough = resample_is_passthrough(this);
|
||||
if (n_samples == UINT32_MAX) {
|
||||
resample_recalc_rate_match(this, resample_passthrough);
|
||||
if (in_samples == UINT32_MAX) {
|
||||
/* no input, ask for more */
|
||||
resample_update_rate_match(this, resample_passthrough, quant_samples, 0);
|
||||
return SPA_STATUS_NEED_DATA;
|
||||
}
|
||||
|
||||
dir = &this->dir[SPA_DIRECTION_OUTPUT];
|
||||
out_passthrough = dir->conv.is_passthrough;
|
||||
|
||||
max_out = max_mon = UINT32_MAX;
|
||||
|
||||
/* collect output ports and monitor ports data */
|
||||
for (i = 0; i < dir->n_ports; i++) {
|
||||
port = GET_OUT_PORT(this, i);
|
||||
|
||||
|
|
@ -2074,12 +2113,15 @@ static int impl_node_process(void *object)
|
|||
bd->chunk->offset = 0;
|
||||
if (port->is_monitor) {
|
||||
mon_datas[n_mon_datas++] = bd->data;
|
||||
bd->chunk->size = n_samples * port->stride;
|
||||
max_mon = SPA_MIN(max_mon, in_samples);
|
||||
max_mon = SPA_MIN(max_mon, bd->maxsize / port->stride);
|
||||
bd->chunk->size = max_mon * port->stride;
|
||||
} else {
|
||||
remap = dir->dst_remap[n_dst_datas++];
|
||||
dst_bufs[remap] = bd;
|
||||
dst_datas[remap] = bd->data;
|
||||
bd->chunk->size = 0;
|
||||
max_out = SPA_MIN(max_out, bd->maxsize / port->stride);
|
||||
}
|
||||
spa_log_trace_fp(this->log, "%p: %d %d %d->%d", this,
|
||||
bd->chunk->size, n_samples,
|
||||
|
|
@ -2091,17 +2133,35 @@ static int impl_node_process(void *object)
|
|||
mix_passthrough = SPA_FLAG_IS_SET(this->mix.flags, CHANNELMIX_FLAG_IDENTITY);
|
||||
end_passthrough = mix_passthrough && resample_passthrough && out_passthrough;
|
||||
|
||||
for (i = 0; i < n_mon_datas; i++) {
|
||||
float volume;
|
||||
/* run monitors */
|
||||
if (max_mon != UINT32_MAX) {
|
||||
for (i = 0; i < n_mon_datas; i++) {
|
||||
float volume;
|
||||
|
||||
if (mon_datas[i] == NULL)
|
||||
continue;
|
||||
if (mon_datas[i] == NULL)
|
||||
continue;
|
||||
|
||||
volume = this->props.monitor.mute ? 0.0f : this->props.monitor.volumes[i];
|
||||
if (this->monitor_channel_volumes)
|
||||
volume *= this->props.channel.mute ? 0.0f : this->props.channel.volumes[i];
|
||||
volume = this->props.monitor.mute ? 0.0f : this->props.monitor.volumes[i];
|
||||
if (this->monitor_channel_volumes)
|
||||
volume *= this->props.channel.mute ? 0.0f : this->props.channel.volumes[i];
|
||||
|
||||
volume_process(&this->volume, mon_datas[i], src_datas[i], volume, n_samples);
|
||||
volume_process(&this->volume, mon_datas[i], src_datas[i], volume, max_mon);
|
||||
}
|
||||
}
|
||||
|
||||
/* calculate in/out sizes */
|
||||
if (this->direction == SPA_DIRECTION_INPUT) {
|
||||
/* in split mode we need to output exactly the size of the
|
||||
* duration so we don't try to flush early */
|
||||
out_samples = SPA_MIN(max_out, quant_samples);
|
||||
flush_out = false;
|
||||
} else {
|
||||
/* in merge mode we consume one duration of samples and
|
||||
* always output the resulting data */
|
||||
flush_out = true;
|
||||
if (this->io_rate_match)
|
||||
in_samples = SPA_MIN(in_samples, this->io_rate_match->size);
|
||||
out_samples = SPA_MIN(max_out, this->quantum_limit);
|
||||
}
|
||||
|
||||
in_datas = (const void**)src_datas;
|
||||
|
|
@ -2110,7 +2170,7 @@ static int impl_node_process(void *object)
|
|||
out_datas = (void **)dst_datas;
|
||||
else
|
||||
out_datas = (void **)this->tmp_datas[(tmp++) & 1];
|
||||
convert_process(&this->dir[SPA_DIRECTION_INPUT].conv, out_datas, in_datas, n_samples);
|
||||
convert_process(&this->dir[SPA_DIRECTION_INPUT].conv, out_datas, in_datas, in_samples);
|
||||
} else {
|
||||
out_datas = (void **)in_datas;
|
||||
}
|
||||
|
|
@ -2121,7 +2181,7 @@ static int impl_node_process(void *object)
|
|||
out_datas = (void **)dst_datas;
|
||||
else
|
||||
out_datas = (void **)this->tmp_datas[(tmp++) & 1];
|
||||
channelmix_process(&this->mix, out_datas, in_datas, n_samples);
|
||||
channelmix_process(&this->mix, out_datas, in_datas, in_samples);
|
||||
} else {
|
||||
out_datas = (void **)in_datas;
|
||||
}
|
||||
|
|
@ -2133,25 +2193,25 @@ static int impl_node_process(void *object)
|
|||
else
|
||||
out_datas = (void **)this->tmp_datas[(tmp++) & 1];
|
||||
|
||||
in_len = n_samples;
|
||||
out_len = this->quantum_limit;
|
||||
in_len = in_samples;
|
||||
out_len = out_samples;
|
||||
resample_process(&this->resample, in_datas, &in_len, out_datas, &out_len);
|
||||
} else {
|
||||
out_datas = (void **)in_datas;
|
||||
out_len = n_samples;
|
||||
out_len = in_samples;
|
||||
}
|
||||
resample_update_rate_match(this, resample_passthrough, n_samples, 0);
|
||||
n_samples = out_len;
|
||||
resample_update_rate_match(this, resample_passthrough, out_samples, 0);
|
||||
in_samples = out_len;
|
||||
|
||||
in_datas = (const void **)out_datas;
|
||||
if (!out_passthrough)
|
||||
convert_process(&this->dir[SPA_DIRECTION_OUTPUT].conv, dst_datas, in_datas, n_samples);
|
||||
convert_process(&this->dir[SPA_DIRECTION_OUTPUT].conv, dst_datas, in_datas, in_samples);
|
||||
|
||||
for (i = 0; i < n_dst_datas; i++) {
|
||||
port = GET_OUT_PORT(this, 0);
|
||||
if (dst_bufs[i]) {
|
||||
dst_bufs[i]->chunk->size = n_samples * port->stride;
|
||||
spa_log_debug(this->log, "%d %d", n_samples, dst_bufs[i]->chunk->size);
|
||||
dst_bufs[i]->chunk->size = in_samples * port->stride;
|
||||
spa_log_debug(this->log, "%d %d", in_samples, dst_bufs[i]->chunk->size);
|
||||
}
|
||||
}
|
||||
return SPA_STATUS_NEED_DATA | SPA_STATUS_HAVE_DATA;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue