Skip to content

Commit ac03eec

Browse files
committed
audio: webrtc_ns: add WebRTC spectral noise suppressor module
Add the webrtc_ns SOF module wrapping the classic WebRTC Noise Suppression algorithm (spectral Wiener filter, fixed-point) from the webrtc-audio-processing 0.3.1 library. Module characteristics: - Single-source, single-sink PCM effect - Fixed-point implementation; no FPU required - Operates at 8 or 16 kHz on 10 ms frames (160/80 samples) - Supports S16_LE and S32_LE, mono or stereo (per-channel instances) - Four suppression levels: Mild/Medium/Aggressive/VeryAggressive (configurable at build time or via IPC4 set_configuration) - Two backends: real (WebRTC NS) and pass-through stub for CI/LLEXT - Designed as a build-time alternative to webrtc_ns2 (RNNoise): lower CPU, no 48 kHz constraint, fully fixed-point Build: - WebRTC NS subset is cross-compiled by src/audio/webrtc_ns/webrtc_ns.cmake (6 C files from modules/audio/webrtc-apm) - Source fetched via west (modules/audio/webrtc-apm, tag v0.3.1) - LLEXT packaging supported UUID: 0fc8faef-945f-004b-8d5f315047f1136a Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
1 parent f9033d9 commit ac03eec

11 files changed

Lines changed: 1008 additions & 0 deletions

File tree

src/audio/webrtc_ns/CMakeLists.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# SPDX-License-Identifier: BSD-3-Clause
2+
3+
if(CONFIG_COMP_WEBRTC_NS STREQUAL "m" AND DEFINED CONFIG_LLEXT)
4+
add_subdirectory(llext ${PROJECT_BINARY_DIR}/webrtc_ns_llext)
5+
add_dependencies(app webrtc_ns)
6+
else()
7+
add_local_sources(sof webrtc_ns.c)
8+
if(CONFIG_COMP_WEBRTC_NS_STUB)
9+
add_local_sources(sof webrtc_ns-stub.c)
10+
else()
11+
add_local_sources(sof webrtc_ns-webrtc.c)
12+
endif()
13+
endif()

src/audio/webrtc_ns/Kconfig

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# SPDX-License-Identifier: BSD-3-Clause
2+
3+
config COMP_WEBRTC_NS
4+
tristate "WebRTC Noise Suppression (classic spectral Wiener filter)"
5+
help
6+
Select to include the WebRTC Noise Suppression module. It wraps
7+
the classic WebRTC NS algorithm — a frequency-domain spectral
8+
subtraction / Wiener filter — as a single-input, single-output
9+
PCM effect module.
10+
11+
The NS module reduces stationary and slowly-varying background
12+
noise (HVAC hum, fan noise, electrical hiss). It is independent
13+
of the ffmpeg afftdn filter already available through ffmpeg_dec,
14+
providing users a build-time choice between the two.
15+
16+
The real backend uses the pure-C noise_suppression module
17+
extracted from webrtc-audio-processing 0.3.x (no abseil, no C++,
18+
BSD-3-Clause). Source is fetched via west (west update).
19+
20+
Without the source, or for CI/testing, select COMP_WEBRTC_NS_STUB.
21+
22+
if COMP_WEBRTC_NS
23+
24+
config COMP_WEBRTC_NS_STUB
25+
bool "WebRTC NS stub backend (no WebRTC source dependency)"
26+
default y if COMP_STUBS
27+
help
28+
Build the webrtc_ns module against a dependency-free stub backend
29+
that passes audio through unmodified. Useful for CI validation of
30+
the SOF module glue, LLEXT packaging, and topology wiring without
31+
needing the cross-built libwebrtc_ns archive.
32+
33+
config WEBRTC_NS_LEVEL
34+
int "Noise suppression level (0=mild, 1=moderate, 2=aggressive, 3=very_aggressive)"
35+
range 0 3
36+
default 1
37+
help
38+
Controls the aggressiveness of the noise suppressor:
39+
0 - Mild (minimal suppression, lowest distortion)
40+
1 - Moderate (recommended for most use cases)
41+
2 - Aggressive
42+
3 - Very aggressive (maximum suppression, most distortion)
43+
44+
config WEBRTC_NS_SAMPLE_RATE_HZ
45+
int "NS processing sample rate in Hz"
46+
default 16000
47+
help
48+
The internal processing sample rate. The WebRTC NS algorithm works
49+
best at 16000 Hz. When the pipeline runs at 48000 Hz the module
50+
can downsample to 16 kHz for NS processing and upsample back to
51+
48 kHz, saving significant CPU. Set to 48000 to process at full
52+
rate (higher quality, higher CPU cost).
53+
Valid values: 8000, 16000, 32000, 48000.
54+
55+
endif # COMP_WEBRTC_NS
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Copyright (c) 2026 Intel Corporation.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
if(CONFIG_COMP_WEBRTC_NS_STUB)
5+
# Dependency-free build: SOF glue + pass-through stub, no WebRTC library.
6+
sof_llext_build("webrtc_ns"
7+
SOURCES ../webrtc_ns.c
8+
../webrtc_ns-stub.c
9+
LIB openmodules
10+
)
11+
else()
12+
# Real NS: cross-build webrtc-apm NS subset and link it.
13+
include(${CMAKE_CURRENT_LIST_DIR}/../webrtc_ns.cmake)
14+
15+
sof_llext_build("webrtc_ns"
16+
SOURCES ../webrtc_ns.c
17+
../webrtc_ns-webrtc.c
18+
../webrtc_ns-shims.c
19+
INCLUDES "${WEBRTC_NS_INSTALL_DIR}/include"
20+
LIBS_PATH "${WEBRTC_NS_INSTALL_DIR}/lib"
21+
LIBS webrtc_ns
22+
LIB openmodules
23+
)
24+
25+
add_dependencies(webrtc_ns_llext_lib webrtc_ns_ext)
26+
add_dependencies(webrtc_ns webrtc_ns_ext)
27+
endif()
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#include <tools/rimage/config/platform.toml>
2+
#define LOAD_TYPE "2"
3+
#include "../webrtc_ns.toml"
4+
5+
[module]
6+
count = __COUNTER__
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// SPDX-License-Identifier: BSD-3-Clause
2+
//
3+
// Copyright(c) 2026 Intel Corporation.
4+
//
5+
// libc shims for the webrtc_ns real backend in LLEXT context.
6+
//
7+
// The WebRTC NS C library references malloc/free and a small set of math
8+
// symbols. These are not exported by SOF core to LLEXT modules, so we
9+
// provide thin wrappers backed by SOF's rballoc heap and sofm_ math.
10+
11+
#include <stddef.h>
12+
#include <stdint.h>
13+
#include <rtos/alloc.h>
14+
15+
/* ============================ Memory ============================ */
16+
17+
void *malloc(size_t size)
18+
{
19+
return rballoc(SOF_MEM_FLAG_USER, size);
20+
}
21+
22+
void free(void *ptr)
23+
{
24+
rfree(ptr);
25+
}
26+
27+
void *calloc(size_t nmemb, size_t size)
28+
{
29+
void *p = rballoc(SOF_MEM_FLAG_USER, nmemb * size);
30+
31+
if (p)
32+
memset(p, 0, nmemb * size);
33+
return p;
34+
}
35+
36+
/* ============================ String helpers ===================== */
37+
38+
void *memset(void *s, int c, size_t n)
39+
{
40+
uint8_t *p = s;
41+
42+
while (n--)
43+
*p++ = (uint8_t)c;
44+
return s;
45+
}
46+
47+
void *memcpy(void *dest, const void *src, size_t n)
48+
{
49+
const uint8_t *s = src;
50+
uint8_t *d = dest;
51+
52+
while (n--)
53+
*d++ = *s++;
54+
return dest;
55+
}
56+
57+
void *memmove(void *dest, const void *src, size_t n)
58+
{
59+
uint8_t *d = dest;
60+
const uint8_t *s = src;
61+
62+
if (d < s || d >= s + n) {
63+
while (n--)
64+
*d++ = *s++;
65+
} else {
66+
d += n;
67+
s += n;
68+
while (n--)
69+
*--d = *--s;
70+
}
71+
return dest;
72+
}
73+
74+
/* ============================ Math ============================== */
75+
/*
76+
* The NS spectral processing uses log(), exp(), sqrt(), pow(), fabsf().
77+
* Route to sofm_ equivalents where available; fall back to soft-float
78+
* versions provided by the Zephyr minimal libc for others.
79+
*/
80+
#include <sof/math/numbers.h>
81+
82+
float sqrtf(float x) { return (float)sofm_sqrt_int32((int32_t)(x * 65536.0f)) / 256.0f; }
83+
84+
/* log/exp/pow are used for spectral gain computation — leave as weak
85+
* references satisfied by the toolchain's soft-float libm linked into
86+
* the SOF binary. LLEXT resolves them at load time from the core symbol
87+
* table. These shims are intentionally empty for now; add implementations
88+
* if the real WebRTC NS backend needs them unsatisfied. */
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// SPDX-License-Identifier: BSD-3-Clause
2+
//
3+
// Copyright(c) 2026 Intel Corporation.
4+
//
5+
// Dependency-free stub backend for the webrtc_ns module.
6+
//
7+
// Always passes audio through unmodified (identity transform). Used in CI
8+
// and for topology/LLEXT packaging validation without the WebRTC NS library.
9+
10+
#include <sof/audio/module_adapter/module/generic.h>
11+
#include <rtos/string.h>
12+
#include <errno.h>
13+
#include "webrtc_ns.h"
14+
15+
LOG_MODULE_DECLARE(webrtc_ns, CONFIG_SOF_LOG_LEVEL);
16+
17+
static int webrtc_ns_stub_init(struct processing_module *mod)
18+
{
19+
comp_info(mod->dev, "webrtc_ns stub backend: no WebRTC NS linked");
20+
return 0;
21+
}
22+
23+
static int webrtc_ns_stub_configure(struct processing_module *mod,
24+
int sample_rate_hz, int level, int num_channels)
25+
{
26+
comp_info(mod->dev, "webrtc_ns stub: rate=%d level=%d ch=%d (ignored)",
27+
sample_rate_hz, level, num_channels);
28+
return 0;
29+
}
30+
31+
/* Stub: copy input to output (pass-through). */
32+
static int webrtc_ns_stub_process(struct processing_module *mod,
33+
const float *const *in, float *const *out,
34+
int frame_samples)
35+
{
36+
struct webrtc_ns_comp_data *cd = module_get_private_data(mod);
37+
int c;
38+
39+
for (c = 0; c < cd->channels; c++)
40+
memcpy(out[c], in[c], (size_t)frame_samples * sizeof(float));
41+
42+
return 0;
43+
}
44+
45+
static int webrtc_ns_stub_reset(struct processing_module *mod)
46+
{
47+
(void)mod;
48+
return 0;
49+
}
50+
51+
static int webrtc_ns_stub_free(struct processing_module *mod)
52+
{
53+
(void)mod;
54+
return 0;
55+
}
56+
57+
const struct webrtc_ns_backend webrtc_ns_backend = {
58+
.name = "stub",
59+
.init = webrtc_ns_stub_init,
60+
.configure = webrtc_ns_stub_configure,
61+
.process = webrtc_ns_stub_process,
62+
.reset = webrtc_ns_stub_reset,
63+
.free = webrtc_ns_stub_free,
64+
};

0 commit comments

Comments
 (0)