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 3 commits into
Conversation
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
| 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); | ||
| } |
There was a problem hiding this comment.
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.
| } | ||
|
|
||
| /* 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?
There was a problem hiding this comment.
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.
|
@singalsu pls take a look. |
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>
9def2d6 to
056152e
Compare
lyakh
left a comment
There was a problem hiding this comment.
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.

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.