audio: src: move filter and delay line allocation to init phase#10846
audio: src: move filter and delay line allocation to init phase#10846jsarha wants to merge 1 commit into
Conversation
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>
There was a problem hiding this comment.
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 onstruct comp_dataso each SRC variant can bind its own coefficient tables during init. - Factor delay-line allocation and polyphase initialization into
src_allocate_delay_lines()insrc_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. |
| 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); | ||
| } |
| 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); | ||
| } |
| } | ||
|
|
||
| /* IPC3: Full filter setup at prepare time */ | ||
| int src_prepare_do(struct processing_module *mod, |
There was a problem hiding this comment.
let's make up our mind - "do_prepare" or "prepare_do?" :-)
| * and stage pointers (stage1, stage2) are already set up via | ||
| * cd->setup_stages(). | ||
| */ | ||
| int src_allocate_delay_lines(struct processing_module *mod) |
There was a problem hiding this comment.
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?
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.