Repository navigation
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
Codec selection, memory sizing, allocator concurrency, stream draining, metadata handling, and modular math linkage contain correctness and reliability defects.
15 open findings
Make allocator binding instance-safe · New Prevent unsynchronized image-wide malloc interception · New Link real libm for modular FFmpeg decoder · New Zero-initialize attribute buffer before dispatch · New Increase modular heap for AAC decoder working set · New Advertise only codecs enabled by Kconfig · New Recreate parser during decoder reset · New Support maximum FLAC and Opus frame sizes · New Parse per-instance codec ID from IPC4 setup payload · New Incrementally discard oversized ID3v2 tags · New Parse oversized FLAC metadata incrementally · New Flush parser and decoder before signaling EOS · New Clamp final playback copy to drain boundary · New Avoid hard-coded FLAC STREAMINFO in topology · New Remove ineffective extra EDF stack reservation · New
What changed in this PR
Adds SOF’s FFmpeg-backed compressed-audio decoder framework for FLAC, MP3, AAC-LC, and Opus, including firmware, IPC, topology, build, and platform integration.
Changes:
- Adds built-in/LLEXT decoder implementations, allocators, conversion, and private math/libc support.
- Adds compressed-playback topology targets and codec capability advertisement.
- Extends IPC drain handling, cross-core operations, manifests, and platform module packaging.
| File | Description |
|---|---|
west.yml |
Adds the pinned SOF FFmpeg fork. |
uuid-registry.txt |
Registers the decoder UUID. |
zephyr/Kconfig |
Adjusts EDF stack configuration. |
zephyr/include/rtos/idc.h |
Adds no-timeout IDC mode and payload alignment. |
src/audio/CMakeLists.txt |
Includes the decoder build. |
src/audio/Kconfig |
Exposes decoder configuration. |
src/audio/base_fw.c |
Advertises compressed codec capabilities. |
src/audio/host-zephyr.c |
Adds compressed-stream drain tracking. |
src/audio/ffmpeg_dec/* |
Implements decoder framework, backends, allocators, conversion, build integration, and metadata. |
src/audio/ffmpeg_dec/libm/* |
Vendors private newlib math sources. |
src/idc/idc.c |
Handles cross-core attributes and reset operations. |
src/idc/zephyr_idc.c |
Implements indefinite blocking IDC waits. |
src/include/ipc/compress_params.h |
Adds the raw Opus codec identifier. |
tools/topology/topology2/sof-hda-generic.conf |
Includes FFmpeg compressed playback. |
tools/topology/topology2/cavs-mixin-mixout-hda.conf |
Adds FFmpeg codec selection and inclusion. |
tools/topology/topology2/development/tplg-targets.cmake |
Adds FLAC, MP3, and AAC development targets. |
tools/topology/topology2/include/components/ffmpeg_dec* |
Defines decoder widgets and FLAC setup data. |
tools/topology/topology2/include/pipelines/cavs/compr-playback-ffmpeg.conf |
Defines the compressed playback pipeline. |
tools/topology/topology2/platform/intel/compr-default.conf |
Adds decoder memory defaults. |
tools/topology/topology2/platform/intel/compr-ffmpeg.conf |
Instantiates the FFmpeg compressed pipeline. |
tools/rimage/config/{lnl,mtl,nvl,ptl,tgl,tgl-h,wcl}.toml.h |
Registers the module across Intel platforms. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
PR 11308: test resultsRun date: 2026-10-15 09:41 UTC Tested commit: 76ef42158b4da11238cf08f9bea30290d012253a |
struct idc_payload lives in coherent (SHARED_DATA) memory and is shared across cores, but it is only a byte array with no explicit alignment, so the linker was free to place it (and every per-core slot) on an odd address. Handlers that read the payload as a wider type -- e.g. the cross-core get_attribute path, which reads a uint32 type field -- then take an EXCCAUSE 9 (load/store alignment) fault when a component runs on a secondary core (ptl/ace30). Align the payload to the cache line. That is the granularity the payload is already built around (IDC_MAX_PAYLOAD_SIZE == DCACHE_LINE_SIZE * 2) and it guarantees every per-core slot starts word-aligned. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The remote (cross-core) get_attribute handler passed the caller coherent (uncached) IDC buffer straight to comp_get_attribute(), which memcpy()s a whole ipc4_base_module_cfg into it. On Xtensa the compiler lowers that struct copy to wide accesses (AE_L32X2 / 64-bit) that the uncached window does not support, faulting EXCCAUSE 9 -- so binding a component that lives on a secondary core (e.g. ffmpeg_dec offloaded to core 1 on ptl/ace30) crashed. Have the handler fill a local cacheable copy and publish it to the coherent buffer with aligned 32-bit word stores (ipc4_coherent_copy32); do the same for the read-back on the initiator side. Only COMP_ATTR_BASE_CONFIG is supported remotely, so the fixed-size local copy is always correct. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A remote component prepare() can be expensive: a DP decoder one-time codec open builds large trig tables -- measured ~580 ms for mp3 on a secondary core. Waiting for it stalls the initiator core IPC/EDF thread for that whole time, and with the default CONFIG_IDC_TIMEOUT_US the blocking k_p4wq_wait() instead times out mid-prepare (-EAGAIN) and races pipeline teardown into a crash. Send the prepare IDC non-blocking. Ordering is preserved without the wait: each core drains its IDC work through a single in-order p4wq worker, so the prepare completes before the cross-core trigger (START) queued behind it. For a compress stream the START IPC also arrives only after the app first write, giving the remote prepare time to finish off the critical path. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
comp_reset_remote() sent the cross-core IDC_MSG_RESET with IDC_BLOCKING, which only waits CONFIG_IDC_TIMEOUT_US (15 ms) before returning -EAGAIN. A data-processing (DP) module reset runs schedule_task_cancel() -> k_thread_join() on the target core and cannot return until the DP thread finishes its in-flight process() call. That call is bounded but can be long during a codec cold-start (a deferred avcodec_open2 table build, up to ~1.4 s for aac, or the first decode after it), far exceeding the IDC timeout. When it timed out the component was left un-reset (not COMP_STATE_READY), so pipeline_reset() failed and the host-side free was then refused with an invalid-state error and the remote core could not be disabled - every teardown wedged until reboot. The caller (pipeline_reset -> host) depends on the reset actually being finished before it frees the component and powers down the remote core, so the reset must stay synchronous. Add IDC_BLOCKING_NO_TIMEOUT, which is IDC_BLOCKING but waits K_FOREVER for the handler to complete, and use it for comp_reset_remote(). A normal end-of-stream teardown joins an idle DP thread and returns immediately, so this only waits when it must. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
618c239 to
76ef421
Compare
Review Feedback Addressed & CI Build ResolutionAll 15 review findings from GitHub Copilot have been addressed and folded into the corresponding commits of the PR series, rebased onto 1. POSIX RTOS / CI Failure Resolution
2. Review Findings Addressed (15 Items)
|
There was a problem hiding this comment.
🟡 Changes recommended
Drain-counter truncation, DMA-tail hangs, and insufficient default decoder memory must be fixed before approval.
1 open finding
15 resolved since last review
Increase modular heap for AAC decoder working set Zero-initialize attribute buffer before dispatch Link real libm for modular FFmpeg decoder Prevent unsynchronized image-wide malloc interception Make allocator binding instance-safe Avoid hard-coded FLAC STREAMINFO in topology Clamp final playback copy to drain boundary Flush parser and decoder before signaling EOS Parse oversized FLAC metadata incrementally Incrementally discard oversized ID3v2 tags Parse per-instance codec ID from IPC4 setup payload Support maximum FLAC and Opus frame sizes Recreate parser during decoder reset Advertise only codecs enabled by Kconfig Remove ineffective extra EDF stack reservation
🧠 Review effort: Balanced
…count The HDA compress gateway free-runs its write pointer circularly and re-presents already-played data, so host_handle_eos() never sees dma_stat.pending_length reach 0 and the source buffer is never flagged END_OF_STREAM. A compress drain therefore never completes. On DRAIN the kernel now hands the host copier the total committed gateway byte count via a new SET_LARGE_CONFIG param (IPC4_COPIER_MODULE_CFG_PARAM_DRAIN_BYTES = 100), stored in host_data.drain_bytes. Once the copier has delivered that many bytes (total_data_processed >= drain_bytes), host_handle_eos() sets the source buffer to END_OF_STREAM and stops the copy, giving the pipeline a correct end of input. drain_bytes is cleared on reset. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add the FFmpeg project to west.yml using the official thesofproject fork repository (thesofproject/FFmpeg) pinned to the sof-hifi branch revision (08ab4baa3400d55be75be1280f6119e210ce354e). This supplies libavcodec and libavutil sources for the ffmpeg_dec audio decoder module. Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Define SND_AUDIOCODEC_OPUS_RAW (0x11) and update SND_AUDIOCODEC_MAX so that compressed Opus playback streams can be advertised and instantiated across SOF IPC interfaces. Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Advertise supported compressed audio playback formats (FLAC, MP3, AAC-LC, and Opus) to the host in get_codec_info() when their respective CONFIG_FFMPEG_DEC_* symbols are enabled. Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
… AAC, Opus) Add the ffmpeg_dec audio processing module providing compressed audio decoding for SOF pipelines using FFmpeg libavcodec. Key capabilities: - Module framework supporting both built-in (=y) and LLEXT (=m) loadable module builds, as well as a dependency-free stub backend for CI. - Support for FLAC (lossless fixed-point), MP3 (MPEG-1/2 Layer III), AAC-LC (Low Complexity), and Opus audio elementary streams. - Built-in private libc and newlib double-math archive compiled with -mlongcalls to satisfy libavcodec mathematical functions without polluting the minimal libc namespace. - DSP heap wrap allocator (ffmpeg_dec-builtin-alloc.c) to handle large decoder working sets without exceeding common-libc arena limits. - End-of-stream (EOS) signaling and compress drain handling. - Rimage module manifest toml and configuration registration for Intel platforms (PTL, LNL, MTL, NVL, TGL, TGL-H, WCL). Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Add topology definitions for driving compressed audio playback through the ffmpeg_dec widget instead of the legacy Cadence decoder: - New pipeline: include/pipelines/cavs/compr-playback-ffmpeg.conf - Platform instances: platform/intel/compr-ffmpeg.conf gated on COMPR_FFMPEG - Decoder component definition: include/components/ffmpeg_dec.conf - Configurable memory budgets (COMPR_FFMPEG_DEC_STACK / HEAP) in compr-default.conf - Added development topology targets: - sof-hda-generic-ffmpeg-compr (FLAC) - sof-hda-generic-ffmpeg-mp3-compr (MP3) - sof-hda-generic-ffmpeg-aac-compr (AAC-LC) Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
76ef421 to
e7f67ec
Compare



Overview
This is PR 1 in the series splitting monolithic PR #10990 into modular, reviewable PRs rebased on
main.This PR introduces the Core Engine & Audio Decoders (
ffmpeg_dec) module, enabling playback of compressed audio elementary streams (FLAC, MP3, AAC-LC, and Opus) on SOF hardware platforms (including PTL, LNL, MTL, NVL, TGL, and WCL).The module sources libavcodec and libavutil directly from the official SOF fork
thesofproject/FFmpegvia the West manifest (west.yml).Subsequent PRs in the series will build on this core:
ffmpeg_enc: MP3, AAC)afftdn,alimiter)Changes in this PR
1. West Manifest Integration (
west.yml)ffmpegpointing to official forkthesofproject/FFmpegpinned to thesof-hifibranch revision (08ab4baa3400d55be75be1280f6119e210ce354e).modules/audio/ffmpeg.2. Audio Processing Module (
src/audio/ffmpeg_dec)=y) and LLEXT (=m) modular builds, plus a stub backend (CONFIG_COMP_FFMPEG_DEC_STUB) for CI validation without external dependencies.ffmpeg_dec-builtin-libc.c: provides isolated libc symbols required by FFmpeg without conflicting with Zephyr minimal libc.libnewlib_m.a) compiled with-mlongcalls -mtext-section-literalsto satisfy double-precision math without calling into unsupported host libc.ffmpeg_dec-builtin-alloc.c: wrapsmalloc/free/realloc/calloconto the unshared DSP heap (.heap_mem), allowing large decoder working sets (e.g. AAC-LC MDCT tables) without overflowing the common-libc arena.-mlongcalls -mtext-section-literalsto preventcall8out-of-range relocation errors across segmented DSP memory.SND_AUDIOCODEC_OPUS_RAW(0x11) definition tosrc/include/ipc/compress_params.h.src/audio/base_fw.cwhen configured.3. Pipeline & Topology Definitions
include/pipelines/cavs/compr-playback-ffmpeg.conf: compress playback pipeline definition routing throughffmpeg_dec.platform/intel/compr-ffmpeg.conf: platform instance with FLACSTREAMINFOsetup control, gated onCOMPR_FFMPEG.development/tplg-targets.cmake:sof-hda-generic-ffmpeg-compr(FLAC)sof-hda-generic-ffmpeg-mp3-compr(MP3)sof-hda-generic-ffmpeg-aac-compr(AAC-LC)Verification & Build Results
xtensa-build-zephyr.py -z -p ptl: PASS (code 0)xtensa-build-zephyr.py -z -p -o ffmpeg_dec_stub.conf ptl: PASS (code 0)ffmpeg_dec_flac_y.conf: PASS (code 0)ffmpeg_dec_mp3_y.conf: PASS (code 0)ffmpeg_dec_aac_y.conf: PASS (code 0)ffmpeg_dec_opus_y.conf: PASS (code 0)xtensa-build-zephyr.py -z -p -o ffmpeg_dec_stub.conf tgl: PASS (code 0)topology2_dev_sof-hda-generic-ffmpeg-compr,topology2_dev_sof-hda-generic-ffmpeg-mp3-compr,topology2_dev_sof-hda-generic-ffmpeg-aac-compr: PASS (code 0)