Skip to content

pipeline: introduce declarative static topology definition and loader - #11266

Open
lgirdwood wants to merge 7 commits into
thesofproject:mainfrom
lgirdwood:topic/static-pipeline-api
Open

lgirdwood wants to merge 7 commits into
thesofproject:mainfrom
lgirdwood:topic/static-pipeline-api

Conversation

@lgirdwood

Copy link
Copy Markdown
Member

Summary

Add support for declarative static audio pipelines in Sound Open Firmware.
In microcontroller, hostless, and standalone embedded environments (such as ESP32-P4/S3/C6, PJRC Teensy 4.1, Nordic nRF54, RP2350, smart speakers, and audio bridges), there is no dynamic IPC host driver (Linux ALSA/SoundWire or Windows) to construct topologies at runtime.

Key Additions & Features

  1. Declarative Topology Structures & Macros (<sof/audio/pipeline/static_pipeline.h>):

    • Full Doxygen API docblocks covering all structures, fields, enums, macros, and public APIs.
    • Comprehensive sample rate bitmasks (SOF_STATIC_RATE_*) aligned with SOF_RATE_* and format bitmasks (SOF_STATIC_FMT_*) aligned with enum sof_ipc_frame.
    • Concise constructor macros (SOF_STATIC_MODULE, SOF_STATIC_MODULE_RATE_CONV, SOF_STATIC_ENDPOINT_DAI, SOF_STATIC_ENDPOINT_USB) for clean declarative pipeline definition.
  2. Ops-Driven Decoupled Architecture:

    • Generic headers and loader engine have zero per-module logic or dependencies.
    • Audio processing modules define and self-register their static operations (struct sof_static_module_ops) providing .create, .apply_volume, .apply_switch, and .apply_enum callbacks directly in their own source files (SRC, ASRC, Volume/Gain, Level Multiplier, Selector, EQ IIR, DRC, and TDFB) using DECLARE_STATIC_MODULE_OPS().
  3. Generic Module Registry & Base IPC4 Config Synthesizer (static_pipeline_modules.c):

    • Generic ops registry with structured error logging on lookup failures.
    • Base IPC4 config synthesizer (sof_static_init_base_cfg) generating standard IPC4 base module configurations (struct ipc4_base_module_cfg) on behalf of the absent host, calculating IBS/OBS and channel mapping from declarative capabilities and periods.
  4. Dynamic Format & Rate Negotiation:

    • Dynamically resolves primary stream sample rates from topology descriptors, removing hardcoded defaults.
    • Supports sample rate converters (SRC/ASRC), up/down mixers, and format conversions with per-buffer rate/channel inheritance.
  5. Static Topology Loader Engine (static_pipeline_loader.c):

    • Instantiates native SOF pipelines, components, intermediate buffers, routes, and kcontrols directly at boot.
    • Component preparation and parameter negotiation to ensure all processing modules reach ready state prior to streaming.
    • Comprehensive inline comments on every code block explaining the action and rationale.
  6. Dedicated Pipeline Control & Trigger Safety:

    • Separate start/stop routines (sof_static_pipeline_start, sof_static_pipeline_stop).
    • Strict abort on pipeline_prepare() failure preventing triggers on uninitialized circular buffers.
    • UAC2 terminal dispatch routing directly to modular start/stop helpers.
    • Decoupled custom kcontrol callback handler for board- and platform-specific controls.
  7. Kconfig & Build Integration:

    • CONFIG_STATIC_PIPELINE Kconfig option and CMakeLists integration.
  8. Developer Documentation:

    • Comprehensive architectural guide, API references, and step-by-step tutorial with multi-rate SRC examples in src/audio/pipeline/README.md.

@lgirdwood
lgirdwood force-pushed the topic/static-pipeline-api branch from 2fc03a7 to 5c11182 Compare October 5, 2026 21:18

@lgirdwood lgirdwood left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Lets split this patch into patch per feature. Need to LOG_ERR any errors and IPC3 support not needed

Comment thread src/audio/pipeline/static_pipeline_loader.c Outdated
Comment thread src/audio/level_multiplier/level_multiplier.c
Comment thread src/audio/pipeline/static_pipeline_loader.c Outdated
Comment thread src/audio/pipeline/README.md Outdated
Comment thread src/audio/pipeline/static_pipeline_loader.c Outdated
Comment thread src/audio/pipeline/static_pipeline_loader.c
Comment thread src/audio/pipeline/static_pipeline_loader.c Outdated
Comment thread src/audio/pipeline/static_pipeline_modules.c Outdated

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.

🟡 Changes recommended

It contains compilation failures plus multiple unsafe initialization, triggering, control, and format-handling defects.

16 open findings
What changed in this PR

Introduces declarative, boot-time audio topology construction for hostless SOF platforms.

Changes:

  • Adds static topology descriptors, module registry, loader, controls, and UAC2 integration.
  • Registers static operations for supported processing modules.
  • Adds configuration, build integration, and developer documentation.
File Description
src/​include/​sof/​audio/​pipeline/​static_pipeline.h Defines the public static topology API.
src/​include/​sof/​audio/​component.h Declares component-driver lookup.
src/​audio/​component.c Implements component-driver lookup.
src/​audio/​pipeline/​static_pipeline_loader.c Builds, configures, controls, and triggers static graphs.
src/​audio/​pipeline/​static_pipeline_modules.c Implements module registration and IPC4 config synthesis.
src/​audio/​pipeline/​static_pipeline_modules.h Declares internal module helpers.
src/​audio/​pipeline/​static_pipeline_uac2.c Bridges UAC2 controls and triggers.
src/​audio/​pipeline/​CMakeLists.txt Adds static pipeline sources.
src/​audio/​pipeline/​README.md Documents architecture and usage.
src/​audio/​Kconfig Adds feature and capacity options.
src/​audio/​volume/​volume.c Adds Volume and Gain operations.
src/​audio/​src/​src.c Adds SRC creation support.
src/​audio/​asrc/​asrc.c Adds ASRC creation support.
src/​audio/​selector/​selector.c Adds Selector creation and controls.
src/​audio/​level_multiplier/​level_multiplier.c Adds gain and switch controls.
src/​audio/​eq_iir/​eq_iir.c Adds EQ bypass control.
src/​audio/​drc/​drc.c Adds DRC enable control.
src/​audio/​tdfb/​tdfb.c Adds beamforming switch control.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +118 to +124
/* Validate component pointer and configuration blob payload */
if (!dev || !abi_blob || abi_blob_total_size == 0) {
LOG_ERR("send_comp_config: invalid parameter or empty blob");
return -EINVAL;
}

const struct sof_abi_hdr *hdr = (const struct sof_abi_hdr *)abi_blob;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed. Added strict validation requiring abi_blob_total_size >= sizeof(struct sof_abi_hdr) and verifying that hdr->size <= abi_blob_total_size - sizeof(struct sof_abi_hdr) before dereferencing or forwarding payload data, logging LOG_ERR and returning -EINVAL on truncated or oversized blobs.

Comment on lines +348 to +352
/* Configure underlying physical DAI controller instance */
struct dai *dai = dai_get(cdesc->ep.dai.dai_type, cdesc->ep.dai.dai_index, DAI_CREAT);

if (dai) {
dai_set_config(dai, &dai_cfg, &spec_cfg, sizeof(spec_cfg));

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed. Removed direct application-tier dai_get(), dai_set_config(), and dai_put() HAL calls. DAI endpoint creation and hardware configuration are now delegated exclusively to the standard component driver framework via drv->ops.create and comp_dai_config(), preserving userspace/HAL privilege boundaries.

Comment thread src/audio/selector/selector.c Outdated
return -EINVAL;
}

cd->config.sel_channel = val;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed. sel_static_apply_enum() now checks val >= 0, enforces val < SEL_SOURCE_4CH, and queries the producer stream/configured channel width to ensure val < src_channels, logging comp_err and returning -EINVAL on out-of-range selection.

Comment thread src/audio/volume/volume.c
Comment on lines +934 to +935
for (uint32_t ch = 0; ch < channels; ch++)
volume_set_chan(mod, ch, val, true);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed. Added bounds validation in vol_static_apply_volume() verifying channels > 0 && channels <= SOF_IPC_MAX_CHANNELS and returning -EINVAL on invalid counts.

Comment thread src/audio/volume/volume.c
Comment on lines +949 to +954
for (uint32_t ch = 0; ch < channels; ch++) {
if (val == 0)
volume_set_chan_mute(mod, ch);
else
volume_set_chan_unmute(mod, ch);
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed. Added bounds validation in vol_static_apply_switch() verifying channels > 0 && channels <= SOF_IPC_MAX_CHANNELS prior to channel mute/unmute iteration.

Comment on lines +55 to +59
/* Linear interpolation between 6 dB bit shifts */
int rem = db_x10 % 60;
uint64_t v = (uint64_t)SOF_VOL_ZERO_DB >> shift;
v = (v * (60 - rem)) / 60;
return (int32_t)v;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed. Corrected interpolation in uac2_to_sof_volume() to interpolate monotonically between v and v_next = v >> 1: val = v_next + (((v - v_next) * (60 - rem)) / 60).

* \param[in] is_volume True for volume command, false for mute switch command.
* \return 0 on success, negative errno on failure.
*/
int sof_static_kcontrol_set_by_uac2(uint8_t entity_id, uint8_t channel, int32_t val, bool is_volume)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed. Added sof_static_kcontrol_set_chan() and wired per-channel .apply_volume_chan and .apply_switch_chan callbacks. When channel == 0 (master), all channels are updated; when channel > 0, the request routes to the specific channel.

* \param[in] is_volume True for volume query, false for mute query.
* \return 0 on success, negative errno on failure.
*/
int sof_static_kcontrol_get_by_uac2(uint8_t entity_id, uint8_t channel, int32_t *val, bool is_volume)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed. Added per-channel storage in s_uac2_cache indexed by UAC2 channel number, enabling channel-accurate GET_CUR responses.

Comment on lines +133 to +135
if (is_volume && ctl->type == SOF_STATIC_CTRL_VOLUME) {
*val = ctl_val;
return 0;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed. s_uac2_cache now caches the original UAC2 8.8 dB signed value on SET_CUR and returns it directly on GET_CUR, preventing precision loss and returning exact UAC2 format.

Comment thread src/audio/pipeline/README.md Outdated
Comment on lines +404 to +406
.min = 0,
.max = 65536,
.def = 65536, /* 0 dB default */

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed. Updated the Volume kcontrol example in README.md to use .max = INT32_MAX, .def = INT32_MAX (0 dB default in Q1.31).

Add a standard driver lookup API comp_driver_find() to search
registered component drivers by UUID (for audio processing modules)
or by driver type (for Host and DAI endpoints).

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
…d headers

Add <sof/audio/pipeline/static_pipeline.h> providing declarative
topology descriptors, capability bitmasks (rates and frame formats),
component constructor macros, ops-driven static module interface,
and public control and trigger APIs.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
… config synthesizer

Add static_pipeline_modules.c and static_pipeline_modules.h providing
generic module operations registration, UUID lookup, and IPC4 base module
configuration synthesis. Contains purely generic infrastructure with zero
per-module logic and no IPC3 dependencies.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Implement static_pipeline_loader.c to parse declarative static audio
topologies and instantiate native SOF pipelines, components, intermediate
buffers, routes, and kcontrols at boot.

Features:
- Purely IPC4 based architecture with no IPC3 dependencies
- Modular multi-stage initialization with explicit LOG_ERR on all failures
- Per-pipeline sample rate negotiation and tracking across pipelines,
  streams, and DAI/host endpoints
- Configurable tracking table limits via Kconfig (STATIC_PIPELINE_MAX_*)
  to support memory-constrained embedded devices
- Runtime kcontrol dispatch to registered module ops with error checking

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
…ol operations

Add static_pipeline_uac2.c providing translation between USB Audio Class 2.0
(UAC2) requests (8.8 dB volume representation, mute switches, streaming terminal
trigger events) and SOF static pipelines and kcontrols.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Register static module operations (struct sof_static_module_ops) across
core audio processing components (Volume, Gain, Level Multiplier, SRC,
ASRC, Selector, EQ IIR, DRC, and TDFB) for IPC4 static pipeline execution.
Includes explicit error logging on invalid module pointers or private data.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Add comprehensive documentation for the static audio pipeline subsystem
in src/audio/pipeline/README.md covering:
- Architectural motivations for microcontroller and hostless systems
- Core concepts and declarative topology structures
- Step-by-step tutorial with multi-rate SRC playback examples
- Ops-driven module interface and UAC2 integration
- Custom kcontrol handlers with named identifiers

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
@lgirdwood
lgirdwood force-pushed the topic/static-pipeline-api branch from b0df45d to a9ed44c Compare October 11, 2026 12:46
@lgirdwood
lgirdwood marked this pull request as ready for review October 11, 2026 12:57
@intel-sofci

Copy link
Copy Markdown

PR 11266: test results

Run date: 2026-10-11 13:33 UTC

Tested commit: a9ed44c17dff0f89be0e5d626ba7b4a9ee1d818c

mtl pass rate lnl pass rate ptl pass rate wcl pass rate nvl pass rate

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