From ec5d2d2a29340e57e9ea8ac9107a15b01b8e8282 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 26 Jun 2025 11:26:05 +0200 Subject: [PATCH] audioconvert: rework the stage recalc a little Use bits to capture the work that is needed. We clear the bit when we added the stage, when all bits are cleared we have nothing more to do. This avoids having to check multiple bookleans. Make a helper function to calculate the destination buffer. When all bits are cleared, we can use the output buffer. --- spa/plugins/audioconvert/audioconvert.c | 170 ++++++++++++------------ 1 file changed, 86 insertions(+), 84 deletions(-) diff --git a/spa/plugins/audioconvert/audioconvert.c b/spa/plugins/audioconvert/audioconvert.c index bab5def32..5c411efcf 100644 --- a/spa/plugins/audioconvert/audioconvert.c +++ b/spa/plugins/audioconvert/audioconvert.c @@ -214,6 +214,13 @@ struct stage_context { uint32_t src_idx; uint32_t dst_idx; uint32_t final_idx; + uint32_t tmp; +#define SRC_CONVERT_BIT (1<<0) +#define RESAMPLE_BIT (1<<1) +#define FILTER_BIT (1<<2) +#define MIX_BIT (1<<3) +#define DST_CONVERT_BIT (1<<4) + uint32_t bits; struct port *ctrlport; bool empty; }; @@ -3392,6 +3399,16 @@ static uint64_t get_time_ns(struct impl *impl) return SPA_TIMESPEC_TO_NSEC(&now); } +static uint32_t get_dst_idx(struct stage_context *ctx) +{ + uint32_t res; + if (ctx->bits == 0) + res = ctx->final_idx; + else + res = CTX_DATA_TMP_0 + ((ctx->tmp++) & 1); + return res; +} + static void run_wav_stage(struct stage *stage, struct stage_context *c) { struct impl *impl = stage->impl; @@ -3504,14 +3521,15 @@ static void run_src_convert_stage(struct stage *s, struct stage_context *c) static void add_src_convert_stage(struct impl *impl, struct stage_context *ctx) { struct stage *s = &impl->stages[impl->n_stages]; + SPA_FLAG_CLEAR(ctx->bits, SRC_CONVERT_BIT); s->impl = impl; s->in_idx = ctx->src_idx; - s->out_idx = ctx->dst_idx; + s->out_idx = get_dst_idx(ctx); s->data = NULL; s->run = run_src_convert_stage; spa_log_trace(impl->log, "%p: stage %d", impl, impl->n_stages); impl->n_stages++; - ctx->src_idx = ctx->dst_idx; + ctx->src_idx = s->out_idx; } static void run_resample_stage(struct stage *s, struct stage_context *c) @@ -3531,14 +3549,36 @@ static void run_resample_stage(struct stage *s, struct stage_context *c) static void add_resample_stage(struct impl *impl, struct stage_context *ctx) { struct stage *s = &impl->stages[impl->n_stages]; + SPA_FLAG_CLEAR(ctx->bits, RESAMPLE_BIT); s->impl = impl; s->in_idx = ctx->src_idx; - s->out_idx = ctx->dst_idx; + s->out_idx = get_dst_idx(ctx); s->data = NULL; s->run = run_resample_stage; spa_log_trace(impl->log, "%p: stage %d", impl, impl->n_stages); impl->n_stages++; - ctx->src_idx = ctx->dst_idx; + ctx->src_idx = s->out_idx; +} + +static void run_filter_stage(struct stage *s, struct stage_context *c) +{ + struct filter_graph *fg = s->data; + + spa_log_trace_fp(s->impl->log, "%p: filter-graph %d", s->impl, c->n_samples); + spa_filter_graph_process(fg->graph, (const void **)c->datas[s->in_idx], + c->datas[s->out_idx], c->n_samples); +} +static void add_filter_stage(struct impl *impl, uint32_t i, struct filter_graph *fg, struct stage_context *ctx) +{ + struct stage *s = &impl->stages[impl->n_stages]; + s->impl = impl; + s->in_idx = ctx->src_idx; + s->out_idx = get_dst_idx(ctx); + s->data = fg; + s->run = run_filter_stage; + spa_log_trace(impl->log, "%p: stage %d", impl, impl->n_stages); + impl->n_stages++; + ctx->src_idx = s->out_idx; } static void run_channelmix_stage(struct stage *s, struct stage_context *c) @@ -3567,38 +3607,18 @@ static void run_channelmix_stage(struct stage *s, struct stage_context *c) } } -static void run_filter_stage(struct stage *s, struct stage_context *c) -{ - struct filter_graph *fg = s->data; - - spa_log_trace_fp(s->impl->log, "%p: filter-graph %d", s->impl, c->n_samples); - spa_filter_graph_process(fg->graph, (const void **)c->datas[s->in_idx], - c->datas[s->out_idx], c->n_samples); -} -static void add_filter_stage(struct impl *impl, uint32_t i, struct filter_graph *fg, struct stage_context *ctx) -{ - struct stage *s = &impl->stages[impl->n_stages]; - s->impl = impl; - s->in_idx = ctx->src_idx; - s->out_idx = ctx->dst_idx; - s->data = fg; - s->run = run_filter_stage; - spa_log_trace(impl->log, "%p: stage %d", impl, impl->n_stages); - impl->n_stages++; - ctx->src_idx = ctx->dst_idx; -} - static void add_channelmix_stage(struct impl *impl, struct stage_context *ctx) { struct stage *s = &impl->stages[impl->n_stages]; + SPA_FLAG_CLEAR(ctx->bits, MIX_BIT); s->impl = impl; s->in_idx = ctx->src_idx; - s->out_idx = ctx->dst_idx; + s->out_idx = get_dst_idx(ctx); s->data = NULL; s->run = run_channelmix_stage; spa_log_trace(impl->log, "%p: stage %d", impl, impl->n_stages); impl->n_stages++; - ctx->src_idx = ctx->dst_idx; + ctx->src_idx = s->out_idx; } static void run_dst_convert_stage(struct stage *s, struct stage_context *c) @@ -3639,8 +3659,7 @@ static void add_dst_convert_stage(struct impl *impl, struct stage_context *ctx) static void recalc_stages(struct impl *this, struct stage_context *ctx) { struct dir *dir; - bool filter_passthrough, in_passthrough, mix_passthrough, resample_passthrough, out_passthrough; - int tmp = 0; + bool test, do_wav; struct port *ctrlport = ctx->ctrlport; bool in_need_remap, out_need_remap; uint32_t i; @@ -3648,36 +3667,44 @@ static void recalc_stages(struct impl *this, struct stage_context *ctx) this->recalc = false; this->n_stages = 0; + ctx->tmp = 0; + ctx->bits = 0; + ctx->src_idx = CTX_DATA_SRC; + ctx->dst_idx = CTX_DATA_DST; + ctx->final_idx = CTX_DATA_DST; + + /* set bits for things we need to do */ dir = &this->dir[SPA_DIRECTION_INPUT]; - in_passthrough = dir->conv.is_passthrough; + SPA_FLAG_UPDATE(ctx->bits, SRC_CONVERT_BIT, !dir->conv.is_passthrough); in_need_remap = dir->need_remap; dir = &this->dir[SPA_DIRECTION_OUTPUT]; - out_passthrough = dir->conv.is_passthrough; + SPA_FLAG_UPDATE(ctx->bits, DST_CONVERT_BIT, !dir->conv.is_passthrough); out_need_remap = dir->need_remap; - resample_passthrough = resample_is_passthrough(this); - filter_passthrough = this->n_graph == 0; - this->resample_passthrough = resample_passthrough; - mix_passthrough = SPA_FLAG_IS_SET(this->mix.flags, CHANNELMIX_FLAG_IDENTITY) && + this->resample_passthrough = resample_is_passthrough(this); + SPA_FLAG_UPDATE(ctx->bits, RESAMPLE_BIT, !this->resample_passthrough); + + SPA_FLAG_UPDATE(ctx->bits, FILTER_BIT, this->n_graph != 0); + + test = SPA_FLAG_IS_SET(this->mix.flags, CHANNELMIX_FLAG_IDENTITY) && (ctrlport == NULL || ctrlport->ctrl == NULL) && (this->vol_ramp_sequence == NULL); + SPA_FLAG_UPDATE(ctx->bits, MIX_BIT, !test); - if (in_passthrough && filter_passthrough && mix_passthrough && resample_passthrough) - out_passthrough = false; + /* if we have nothing to do, force a conversion to the destination to make sure we + * actually write something to the destination buffer */ + if (ctx->bits == 0) + SPA_FLAG_SET(ctx->bits, DST_CONVERT_BIT); - if (out_passthrough && out_need_remap) + do_wav = this->props.wav_path[0] || this->wav_file != NULL; + + if (!SPA_FLAG_IS_SET(ctx->bits, DST_CONVERT_BIT) && out_need_remap) add_dst_remap_stage(this, ctx); - if (this->direction == SPA_DIRECTION_INPUT && - (this->props.wav_path[0] || this->wav_file != NULL)) + if (this->direction == SPA_DIRECTION_INPUT && do_wav) add_wav_stage(this, ctx); - if (!in_passthrough) { - if (filter_passthrough && mix_passthrough && resample_passthrough && out_passthrough) - ctx->dst_idx = ctx->final_idx; - else - ctx->dst_idx = CTX_DATA_TMP_0 + ((tmp++) & 1); - + if (SPA_FLAG_IS_SET(ctx->bits, SRC_CONVERT_BIT)) { add_src_convert_stage(this, ctx); } else { if (in_need_remap) @@ -3685,55 +3712,34 @@ static void recalc_stages(struct impl *this, struct stage_context *ctx) } if (this->direction == SPA_DIRECTION_INPUT) { - if (!resample_passthrough) { - if (filter_passthrough && mix_passthrough && out_passthrough) - ctx->dst_idx = ctx->final_idx; - else - ctx->dst_idx = CTX_DATA_TMP_0 + ((tmp++) & 1); - + if (SPA_FLAG_IS_SET(ctx->bits, RESAMPLE_BIT)) add_resample_stage(this, ctx); - resample_passthrough = true; - } } - if (!filter_passthrough) { + if (SPA_FLAG_IS_SET(ctx->bits, FILTER_BIT)) { for (i = 0; i < this->n_graph; i++) { struct filter_graph *fg = this->filter_graph[i]; - if (mix_passthrough && resample_passthrough && out_passthrough && - i + 1 == this->n_graph) - ctx->dst_idx = ctx->final_idx; - else - ctx->dst_idx = CTX_DATA_TMP_0 + ((tmp++) & 1); + if (i + 1 == this->n_graph) + SPA_FLAG_CLEAR(ctx->bits, FILTER_BIT); add_filter_stage(this, i, fg, ctx); } } - if (!mix_passthrough) { - if (resample_passthrough && out_passthrough) - ctx->dst_idx = ctx->final_idx; - else - ctx->dst_idx = CTX_DATA_TMP_0 + ((tmp++) & 1); - + if (SPA_FLAG_IS_SET(ctx->bits, MIX_BIT)) add_channelmix_stage(this, ctx); - } - if (this->direction == SPA_DIRECTION_OUTPUT) { - if (!resample_passthrough) { - if (out_passthrough) - ctx->dst_idx = ctx->final_idx; - else - ctx->dst_idx = CTX_DATA_TMP_0 + ((tmp++) & 1); + if (this->direction == SPA_DIRECTION_OUTPUT) { + if (SPA_FLAG_IS_SET(ctx->bits, RESAMPLE_BIT)) add_resample_stage(this, ctx); - } } - if (!out_passthrough) { + + if (SPA_FLAG_IS_SET(ctx->bits, DST_CONVERT_BIT)) add_dst_convert_stage(this, ctx); - } - if (this->direction == SPA_DIRECTION_OUTPUT && - (this->props.wav_path[0] || this->wav_file != NULL)) + + if (this->direction == SPA_DIRECTION_OUTPUT && do_wav) add_wav_stage(this, ctx); - spa_log_trace(this->log, "got %u processing stages", this->n_stages); + spa_log_debug(this->log, "got %u processing stages", this->n_stages); } static int impl_node_process(void *object) @@ -4027,12 +4033,8 @@ static int impl_node_process(void *object) ctx.ctrlport = ctrlport; ctx.empty = in_empty; - if (SPA_UNLIKELY(this->recalc)) { - ctx.src_idx = CTX_DATA_SRC; - ctx.dst_idx = CTX_DATA_DST; - ctx.final_idx = CTX_DATA_DST; + if (SPA_UNLIKELY(this->recalc)) recalc_stages(this, &ctx); - } for (i = 0; i < this->n_stages; i++) { struct stage *s = &this->stages[i];