audio: src: move filter and delay line allocation to init phase by jsarha · Pull Request #10846 · thesofproject/sof · GitHub
Skip to content

audio: src: move filter and delay line allocation to init phase#10846

Open
jsarha wants to merge 3 commits into
thesofproject:mainfrom
jsarha:src_move_allocs_to_init
Open

audio: src: move filter and delay line allocation to init phase#10846
jsarha wants to merge 3 commits into
thesofproject:mainfrom
jsarha:src_move_allocs_to_init

Conversation

@jsarha

@jsarha jsarha commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Refactor SRC and SRC-lite so that filter stage setup and delay line allocation happen during the module init callback instead of prepare. This ensures the bulk of SRC memory allocation occurs while the vregion allocator is still in its lifetime phase, before the interim heap is created. The allocations then persist across prepare/reset cycles without needing to be re-allocated each time.

A new setup_stages() callback is added to struct comp_data, set by each variant (src.c, src_lite.c) to point at its own coefficient tables. The common src_allocate_delay_lines() is factored out of the old prepare path into src_common.c.

For IPC4, src_init_stages() calls setup_stages() and src_allocate_delay_lines() at init time. The prepare path (src_prepare_do) only validates rates and sets downstream params.

For IPC3, src_init_stages() is a no-op and src_prepare_do() retains the original behavior of doing full setup at prepare time, since IPC3 cannot be tested at this time.

Copilot AI review requested due to automatic review settings June 4, 2026 22:11

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors the SRC and SRC-lite modules so that filter-stage setup and delay-line allocation can happen during module init (IPC4) rather than during prepare, allowing the bulk of SRC allocations to occur earlier (while the vregion allocator is still in its lifetime phase) and persist across prepare/reset cycles.

Changes:

  • Add a setup_stages() callback on struct comp_data so each SRC variant can bind its own coefficient tables during init.
  • Factor delay-line allocation and polyphase initialization into src_allocate_delay_lines() in src_common.c.
  • Split IPC behavior: IPC4 allocates at init (src_init_stages()), while IPC3 keeps full setup in prepare (src_prepare_do()).

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/audio/src/src.c Introduces src_setup_stages() and an init wrapper to bind coefficient tables and run init-time stage setup.
src/audio/src/src_lite.c Mirrors SRC changes for SRC-lite via src_lite_setup_stages() and init wrapper.
src/audio/src/src_ipc4.c Adds IPC4 src_init_stages() (init-time allocation) and new IPC4 src_prepare_do() path.
src/audio/src/src_ipc3.c Adds IPC3 src_init_stages() no-op and keeps full setup/allocation in prepare via src_prepare_do().
src/audio/src/src_common.h Extends struct comp_data with setup_stages callback and adds new common function prototypes.
src/audio/src/src_common.c Adds src_allocate_delay_lines() to centralize delay-line allocation and polyphase initialization.

Comment thread src/audio/src/src_ipc4.c
Comment on lines +268 to +277
uint32_t frame_bytes = cd->channels_count * cd->sample_container_bytes;

if (frame_bytes && cd->sink_rate) {
dev->period = 1000000ULL *
(cd->ipc_config.base.obs / frame_bytes) /
cd->sink_rate;
dev->period /= LL_TIMER_PERIOD_US;
dev->period *= LL_TIMER_PERIOD_US;
component_set_nearest_period_frames(dev, cd->sink_rate);
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed

Comment thread src/audio/src/src_ipc4.c
Comment on lines +287 to +311
struct comp_data *cd = module_get_private_data(mod);
struct comp_dev *dev = mod->dev;
int ret;

if (cd->source_rate != cd->ipc_config.base.audio_fmt.sampling_frequency ||
cd->sink_rate != cd->ipc_config.sink_rate) {
comp_err(mod->dev, "rate mismatch: source %u/%u sink %u/%u",
cd->source_rate,
cd->ipc_config.base.audio_fmt.sampling_frequency,
cd->sink_rate, cd->ipc_config.sink_rate);
return -EINVAL;
}

ret = src_set_params(mod, sink);
if (ret < 0) {
comp_err(mod->dev, "set params failed.");
return ret;
}

/* Update frame counts with final dev->frames from src_set_params */
cd->source_frames = dev->frames * cd->source_rate / cd->sink_rate;
cd->sink_frames = dev->frames;

return src_prepare_general(mod, source, sink);
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two followup commit to address this and more complex issues arising from it. But in the way out Linux driver uses SOF, thoise two followup commits, would not be strictly needed.

Comment thread src/audio/src/src_ipc3.c Outdated
}

/* IPC3: Full filter setup at prepare time */
int src_prepare_do(struct processing_module *mod,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's make up our mind - "do_prepare" or "prepare_do?" :-)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...to match src_do_init()

* and stage pointers (stage1, stage2) are already set up via
* cd->setup_stages().
*/
int src_allocate_delay_lines(struct processing_module *mod)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why in src_common.c if it's only used with IPC4? Looks like this is duplicating code now for IPC3 and IPC4. Can we not extract and reuse some common functions?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Common is more correct place for this, but I did not dare to touch ipc3 as I do not know how to test that code.

@lgirdwood

Copy link
Copy Markdown
Member

@singalsu pls take a look.

Jyri Sarha added 3 commits July 2, 2026 20:33
Refactor SRC and SRC-lite so that filter stage setup and delay line
allocation happen during the module init callback instead of prepare.
This ensures the bulk of SRC memory allocation occurs while the vregion
allocator is still in its lifetime phase, before the interim heap is
created. The allocations then persist across prepare/reset cycles
without needing to be re-allocated each time.

A new setup_stages() callback is added to struct comp_data, set by each
variant (src.c, src_lite.c) to point at its own coefficient tables.
The common src_allocate_delay_lines() is factored out of the old prepare
path into src_common.c.

For IPC4, src_init_stages() calls setup_stages() and
src_allocate_delay_lines() at init time. The prepare path
(src_prepare_do) only validates rates and sets downstream params.

For IPC3, src_init_stages() is a no-op and src_prepare_do() retains
the original behavior of doing full setup at prepare time, since IPC3
cannot be tested at this time.

Signed-off-by: Jyri Sarha <jyri.sarha@linux.intel.com>
Now that filter stage setup and delay line allocation happen at init
time, src_reset() must not destroy that state. Replace the call to
src_polyphase_reset() (which NULLs stage pointers and zeroes sizes)
with the new src_polyphase_reset_state() that only:

 - zeroes the delay line memory contents (clearing filter history),
 - resets fir_wp / out_rp pointers to their initial positions,
 - resets the inter-stage buffer pointers and counter.

The filter stage descriptors, delay line pointers, and their sizes
are preserved so the next prepare/trigger cycle can resume without
re-allocating or re-initializing the filters.

Signed-off-by: Jyri Sarha <jyri.sarha@linux.intel.com>
Check that the source stream rate and channel count at prepare match
what was used to initialize the filter stages and delay lines. Since
these allocations now happen at init and persist across prepare/reset
cycles, a mismatch would cause incorrect processing or buffer overruns.

Also compare rates against the actual source stream rather than only
the IPC config, catching cases where the upstream pipeline delivers a
different rate than originally configured.

Signed-off-by: Jyri Sarha <jyri.sarha@linux.intel.com>
@jsarha jsarha force-pushed the src_move_allocs_to_init branch from 9def2d6 to 056152e Compare July 2, 2026 17:39
@jsarha

jsarha commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

@lyakh lyakh left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry, I think this needs a very thorough review, in particular from @singalsu but I'd also like to try and better understand where various parts come from. I previously commented about code duplication, and the current stats for the first commit, which is supposed to (mostly) move code around are:

 6 files changed, 239 insertions(+), 38 deletions(-)

which looks like a fair bit more than moving around. Let me press the brake on this one for now until we can review it in better detail.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants