diff --git a/src/audio/webrtc_aec/webrtc_aec-shims.c b/src/audio/webrtc_aec/webrtc_aec-shims.c index 868ecfb9e9fd..9943445043a7 100644 --- a/src/audio/webrtc_aec/webrtc_aec-shims.c +++ b/src/audio/webrtc_aec/webrtc_aec-shims.c @@ -11,8 +11,7 @@ #include #include #include -#include -#if !defined(LLEXT_MODULE) +#if !defined(LLEXT_MODULE) && !defined(LL_EXTENSION_BUILD) #include static APP_SYSUSER_BSS struct processing_module *active_aec_mod; #else @@ -73,7 +72,6 @@ void *webrtc_realloc(void *ptr, size_t size) return NULL; } - /* Not called by AEC3 */ - k_panic(); + /* Not called by AECm/AEC3 */ return NULL; } diff --git a/src/audio/webrtc_aec/webrtc_aec.c b/src/audio/webrtc_aec/webrtc_aec.c index 4c3f8f027a27..482aac572239 100644 --- a/src/audio/webrtc_aec/webrtc_aec.c +++ b/src/audio/webrtc_aec/webrtc_aec.c @@ -168,6 +168,67 @@ static void s16_to_sink(struct sof_sink *dst, int16_t src[][WEBRTC_AEC_FIFO_FRAM sink_commit_buffer(dst, nbytes); } +static void src_drop_frames(struct sof_source *src, int frames) +{ + size_t frame_bytes = source_get_frame_bytes(src); + const void *data_ptr, *buf_start; + size_t buf_size, nbytes; + + if (frames <= 0 || !frame_bytes) + return; + + nbytes = (size_t)frames * frame_bytes; + if (!source_get_data(src, nbytes, &data_ptr, &buf_start, &buf_size)) + source_release_data(src, nbytes); +} + +static void webrtc_aec_resolve_sources(struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks, + int *mic_idx, int *ref_idx) +{ + *mic_idx = 0; + *ref_idx = -1; + + if (num_of_sources <= 1) + return; + +#ifdef CONFIG_IPC_MAJOR_4 + { + uint32_t q0 = IPC4_SINK_QUEUE_ID(source_get_id(sources[0])); + uint32_t q1 = IPC4_SINK_QUEUE_ID(source_get_id(sources[1])); + + if (q0 != q1) { + if (q0 == 0) { + *mic_idx = 0; + *ref_idx = 1; + } else { + *mic_idx = 1; + *ref_idx = 0; + } + return; + } + } +#endif + + if (num_of_sinks > 0) { + if (source_get_pipeline_id(sources[0]) == sink_get_pipeline_id(sinks[0]) && + source_get_pipeline_id(sources[1]) != sink_get_pipeline_id(sinks[0])) { + *mic_idx = 0; + *ref_idx = 1; + return; + } + if (source_get_pipeline_id(sources[1]) == sink_get_pipeline_id(sinks[0]) && + source_get_pipeline_id(sources[0]) != sink_get_pipeline_id(sinks[0])) { + *mic_idx = 1; + *ref_idx = 0; + return; + } + } + + *mic_idx = 0; + *ref_idx = 1; +} + /* ---------------------------------------------------------------- * module_interface operations * ---------------------------------------------------------------- */ @@ -226,21 +287,8 @@ __cold static int webrtc_aec_prepare(struct processing_module *mod, return -EINVAL; } - if (num_of_sources == 1) { - cd->mic_src = 0; - cd->ref_src = -1; - } else if (source_get_pipeline_id(sources[0]) == sink_get_pipeline_id(sinks[0]) && - source_get_pipeline_id(sources[1]) != sink_get_pipeline_id(sinks[0])) { - cd->mic_src = 0; - cd->ref_src = 1; - } else if (source_get_pipeline_id(sources[1]) == sink_get_pipeline_id(sinks[0]) && - source_get_pipeline_id(sources[0]) != sink_get_pipeline_id(sinks[0])) { - cd->mic_src = 1; - cd->ref_src = 0; - } else { - cd->mic_src = 0; - cd->ref_src = 1; - } + webrtc_aec_resolve_sources(sources, num_of_sources, sinks, num_of_sinks, + &cd->mic_src, &cd->ref_src); mic_fmt = source_get_frm_fmt(sources[cd->mic_src]); mic_rate = source_get_rate(sources[cd->mic_src]); @@ -313,7 +361,8 @@ __cold static int webrtc_aec_prepare(struct processing_module *mod, #ifdef CONFIG_IPC_MAJOR_4 /* Apply reference format override from topology pin descriptor. */ - if (cd->ref_src >= 0) + if (cd->ref_src >= 0 && mod->priv.cfg.nb_input_pins > 1 && + mod->priv.cfg.input_pins) ipc4_update_source_format(sources[cd->ref_src], &mod->priv.cfg.input_pins[1].audio_fmt); #endif @@ -343,29 +392,52 @@ static int webrtc_aec_process(struct processing_module *mod, struct sof_sink **sinks, int num_of_sinks) { struct webrtc_aec_comp_data *cd = module_get_private_data(mod); - struct sof_source *mic = sources[cd->mic_src]; - struct sof_source *ref = cd->ref_src >= 0 ? sources[cd->ref_src] : NULL; - struct sof_sink *out = sinks[0]; - int fmic = (int)source_get_data_frames_available(mic); - int fref = ref ? (int)source_get_data_frames_available(ref) : 0; - int n, drain, c; - - if (fmic <= 0) + struct sof_source *mic; + struct sof_source *ref; + struct sof_sink *out; + int mic_idx, ref_idx; + int fmic, fref, n, drain, c; + bool ref_s32; + + if (num_of_sources < 1 || num_of_sinks < 1) return 0; - /* Cap to available space in input accumulation buffers */ + webrtc_aec_resolve_sources(sources, num_of_sources, sinks, num_of_sinks, + &mic_idx, &ref_idx); + cd->mic_src = mic_idx; + cd->ref_src = ref_idx; + + mic = sources[mic_idx]; + ref = ref_idx >= 0 ? sources[ref_idx] : NULL; + out = sinks[0]; + fmic = (int)source_get_data_frames_available(mic); + fref = ref ? (int)source_get_data_frames_available(ref) : 0; + + /* Cap to available space in input accumulation and output sink buffers */ n = MIN(fmic, WEBRTC_AEC_FIFO_FRAMES - cd->buffered_in_frames); - if (n <= 0) + n = MIN(n, (int)sink_get_free_frames(out)); + if (n <= 0) { + if (ref && fref > 0) { + size_t fb = source_get_frame_bytes(ref); + int keep = fb ? (int)(source_get_min_available(ref) / fb) : 0; + + if (fref > keep) + src_drop_frames(ref, fref - keep); + } return 0; + } /* Convert mic input to per-channel S16 */ src_to_s16(mic, n, cd->mic_buf, cd->buffered_in_frames, cd->channels, cd->is_s32); /* Convert ref input to per-channel S16; if starved/silent, fill with silence */ + ref_s32 = ref ? (source_get_frm_fmt(ref) == SOF_IPC_FRAME_S32_LE) : cd->is_s32; if (fref >= n) { - src_to_s16(ref, n, cd->ref_buf, cd->buffered_in_frames, cd->channels, cd->is_s32); + if (fref > n) + src_drop_frames(ref, fref - n); + src_to_s16(ref, n, cd->ref_buf, cd->buffered_in_frames, cd->channels, ref_s32); } else if (fref > 0) { - src_to_s16(ref, fref, cd->ref_buf, cd->buffered_in_frames, cd->channels, cd->is_s32); + src_to_s16(ref, fref, cd->ref_buf, cd->buffered_in_frames, cd->channels, ref_s32); for (c = 0; c < cd->channels; c++) memset(&cd->ref_buf[c][cd->buffered_in_frames + fref], 0, (size_t)(n - fref) * sizeof(int16_t)); @@ -648,17 +720,27 @@ static bool webrtc_aec_is_ready_to_process(struct processing_module *mod, int num_of_sinks) { struct webrtc_aec_comp_data *cd = module_get_private_data(mod); - struct sof_source *mic; + struct sof_source *mic, *ref; struct sof_sink *out; + int mic_idx, ref_idx; - if (!cd || !cd->configured || num_of_sources <= cd->mic_src || num_of_sinks < 1) + if (!cd || !cd->configured || num_of_sources < 1 || num_of_sinks < 1) return false; - mic = sources[cd->mic_src]; + webrtc_aec_resolve_sources(sources, num_of_sources, sinks, num_of_sinks, + &mic_idx, &ref_idx); + mic = sources[mic_idx]; + ref = ref_idx >= 0 ? sources[ref_idx] : NULL; out = sinks[0]; - return source_get_data_available(mic) >= source_get_min_available(mic) && - sink_get_free_size(out) >= sink_get_min_free_space(out); + if (source_get_data_available(mic) >= source_get_min_available(mic) && + sink_get_free_size(out) >= sink_get_min_free_space(out)) + return true; + + if (ref && source_get_data_available(ref) >= 2 * source_get_min_available(ref)) + return true; + + return false; } static const struct module_interface webrtc_aec_interface = { diff --git a/src/audio/webrtc_aec/webrtc_aec.cmake b/src/audio/webrtc_aec/webrtc_aec.cmake index 094f55e4bb0b..4c42edf068ed 100644 --- a/src/audio/webrtc_aec/webrtc_aec.cmake +++ b/src/audio/webrtc_aec/webrtc_aec.cmake @@ -33,6 +33,16 @@ set(WEBRTC_AECM_INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}/webrtc-aecm-install" set(_aecm_src "${SOF_WEBRTC_APM_SRC_DIR}/webrtc") +if("${ARCH}" STREQUAL "xtensa") + if(CONFIG_LLEXT_BUILD_PIC) + set(_aecm_arch_cflags "-fPIC -mlongcalls -mtext-section-literals") + else() + set(_aecm_arch_cflags "-fno-pic -fno-pie -mlongcalls -mtext-section-literals") + endif() +else() + set(_aecm_arch_cflags "-fPIC") +endif() + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/webrtc-aecm-build.sh" "#!/bin/sh set -e @@ -42,7 +52,7 @@ OBJ=${CMAKE_CURRENT_BINARY_DIR}/webrtc-aecm-obj mkdir -p \"$OBJ\" \"$INST/lib\" \"$INST/include\" \"$INST/include/webrtc\" -CFLAGS=\"-O2 -fPIC -I${SOF_WEBRTC_APM_SRC_DIR} -I$SRC -I$SRC/common_audio/signal_processing/include -DWEBRTC_ARCH_32_BITS= -DWEBRTC_ARCH_LITTLE_ENDIAN= -Dmalloc=webrtc_malloc -Dcalloc=webrtc_calloc -Drealloc=webrtc_realloc -Dfree=webrtc_free\" +CFLAGS=\"-O2 ${_aecm_arch_cflags} -DNDEBUG -I${SOF_WEBRTC_APM_SRC_DIR} -I$SRC -I$SRC/common_audio/signal_processing/include -DWEBRTC_ARCH_32_BITS= -DWEBRTC_ARCH_LITTLE_ENDIAN= -Dmalloc=webrtc_malloc -Dcalloc=webrtc_calloc -Drealloc=webrtc_realloc -Dfree=webrtc_free\" # AECm core SRCS=\" diff --git a/src/audio/webrtc_aec/webrtc_aec.toml b/src/audio/webrtc_aec/webrtc_aec.toml index a6f10aa3cb4c..7a72ac57c5f1 100644 --- a/src/audio/webrtc_aec/webrtc_aec.toml +++ b/src/audio/webrtc_aec/webrtc_aec.toml @@ -12,6 +12,7 @@ domain_types = "1" load_type = LOAD_TYPE module_type = "9" + init_config = "1" auto_start = "0" sched_caps = [1, 0x00008000] REM # pin = [dir, type, sample rate, size, container, channel-cfg] diff --git a/src/audio/webrtc_ns/webrtc_ns-shims.c b/src/audio/webrtc_ns/webrtc_ns-shims.c index 4f5b91362079..888ca47075a8 100644 --- a/src/audio/webrtc_ns/webrtc_ns-shims.c +++ b/src/audio/webrtc_ns/webrtc_ns-shims.c @@ -13,7 +13,7 @@ #include #include #include -#if !defined(LLEXT_MODULE) +#if !defined(LLEXT_MODULE) && !defined(LL_EXTENSION_BUILD) #include static APP_SYSUSER_BSS struct processing_module *active_ns_mod; #else @@ -60,7 +60,7 @@ void *webrtc_ns_calloc(size_t nmemb, size_t size) return p; } -#if defined(LLEXT_MODULE) +#if defined(LLEXT_MODULE) || defined(LL_EXTENSION_BUILD) /* ============================ Memory ============================ */ void *malloc(size_t size) @@ -124,12 +124,12 @@ void *memmove(void *dest, const void *src, size_t n) */ -float fabsf(float x) +__attribute__((weak)) float fabsf(float x) { return (x < 0.0f) ? -x : x; } -double fabs(double x) +__attribute__((weak)) double fabs(double x) { return (x < 0.0) ? -x : x; } @@ -149,17 +149,17 @@ static inline float ns_exp2f(float x) return p * u.f; } -float expf(float x) +__attribute__((weak)) float expf(float x) { return ns_exp2f(x * 1.4426950408889634f); } -double exp(double x) +__attribute__((weak)) double exp(double x) { return (double)expf((float)x); } -double tanh(double x) +__attribute__((weak)) double tanh(double x) { if (x > 10.0) return 1.0; if (x < -10.0) return -1.0; @@ -167,10 +167,151 @@ double tanh(double x) return (e2 - 1.0) / (e2 + 1.0); } -float atanf(float x) +__attribute__((weak)) float atanf(float x) { if (x == 1.0f) return 0.7853981633974483f; float x2 = x * x; return x * (1.0f + 0.28f * x2) / (1.0f + 0.613f * x2); } + +static float ns_log2f(float x) +{ + union { float f; uint32_t i; } u = { .f = x }; + int e; + float m, z; + + if (x <= 0.0f) + return -127.0f; + + e = (int)((u.i >> 23) & 0xff) - 127; + u.i = (u.i & 0x007fffff) | 0x3f800000; + m = u.f; + z = m - 1.0f; + + return (float)e + z * (1.44269504f - z * (0.72134752f - z * 0.48089834f)); +} + +__attribute__((weak)) float logf(float x) +{ + return ns_log2f(x) * 0.6931471805599453f; +} + +__attribute__((weak)) double log(double x) +{ + return (double)logf((float)x); +} + +__attribute__((weak)) float sqrtf(float x) +{ + if (x <= 0.0f) + return 0.0f; + return __builtin_sqrtf(x); +} + +__attribute__((weak)) double sqrt(double x) +{ + return (double)sqrtf((float)x); +} + +__attribute__((weak)) float powf(float x, float y) +{ + if (x <= 0.0f) + return (x == 0.0f && y > 0.0f) ? 0.0f : 1.0f; + if (y == 0.0f) + return 1.0f; + if (y == 1.0f) + return x; + if (y == 2.0f) + return x * x; + if (y == 0.5f) + return sqrtf(x); + return ns_exp2f(y * ns_log2f(x)); +} + +static inline float ns_floorf(float x) +{ + int i = (int)x; + + if (x < 0.0f && (float)i != x) + i--; + return (float)i; +} + +__attribute__((weak)) float floorf(float x) +{ + return ns_floorf(x); +} + +__attribute__((weak)) double floor(double x) +{ + return (double)ns_floorf((float)x); +} + +static inline float ns_ceilf(float x) +{ + int i = (int)x; + + if (x > 0.0f && (float)i != x) + i++; + return (float)i; +} + +static inline float ns_roundf(float x) +{ + return (x >= 0.0f) ? ns_floorf(x + 0.5f) : ns_ceilf(x - 0.5f); +} + +static inline void ns_sincosf_poly(float z, float *s_out, float *c_out) +{ + float z2 = z * z; + + *s_out = z * (1.0f + z2 * (-0.166666667f + z2 * (0.008333333f - z2 * 0.0001984127f))); + *c_out = 1.0f + z2 * (-0.5f + z2 * (0.041666667f + z2 * (-0.0013888889f + z2 * 0.0000248016f))); +} + +__attribute__((weak)) float sinf(float x) +{ + const float inv_half_pi = 0.636619772367581343f; + const float half_pi_hi = 1.5707963267948966f; + int k = (int)ns_roundf(x * inv_half_pi); + float z = x - (float)k * half_pi_hi; + float s, c; + + ns_sincosf_poly(z, &s, &c); + + switch ((k % 4 + 4) % 4) { + case 0: return s; + case 1: return c; + case 2: return -s; + case 3: default: return -c; + } +} + +__attribute__((weak)) double sin(double x) +{ + return (double)sinf((float)x); +} + +__attribute__((weak)) float cosf(float x) +{ + const float inv_half_pi = 0.636619772367581343f; + const float half_pi_hi = 1.5707963267948966f; + int k = (int)ns_roundf(x * inv_half_pi); + float z = x - (float)k * half_pi_hi; + float s, c; + + ns_sincosf_poly(z, &s, &c); + + switch ((k % 4 + 4) % 4) { + case 0: return c; + case 1: return -s; + case 2: return -c; + case 3: default: return s; + } +} + +__attribute__((weak)) double cos(double x) +{ + return (double)cosf((float)x); +} diff --git a/src/audio/webrtc_ns/webrtc_ns.cmake b/src/audio/webrtc_ns/webrtc_ns.cmake index fb39b40e1793..771001fc8427 100644 --- a/src/audio/webrtc_ns/webrtc_ns.cmake +++ b/src/audio/webrtc_ns/webrtc_ns.cmake @@ -37,6 +37,16 @@ set(WEBRTC_NS_INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}/webrtc-ns-install" set(_ns_src "${SOF_WEBRTC_APM_SRC_DIR}/webrtc") +if("${ARCH}" STREQUAL "xtensa") + if(CONFIG_LLEXT_BUILD_PIC) + set(_ns_arch_cflags "-fPIC -mlongcalls -mtext-section-literals") + else() + set(_ns_arch_cflags "-fno-pic -fno-pie -mlongcalls -mtext-section-literals") + endif() +else() + set(_ns_arch_cflags "-fPIC") +endif() + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/webrtc-ns-build.sh" "#!/bin/sh set -e @@ -46,7 +56,7 @@ OBJ=${CMAKE_CURRENT_BINARY_DIR}/webrtc-ns-obj mkdir -p \"$OBJ\" \"$INST/lib\" \"$INST/include\" -CFLAGS=\"-O2 -fPIC -DWEBRTC_ARCH_32_BITS= -DWEBRTC_ARCH_LITTLE_ENDIAN= -I${SOF_WEBRTC_APM_SRC_DIR} -I$SRC/modules/audio_processing/ns/include -Dmalloc=webrtc_ns_malloc -Dcalloc=webrtc_ns_calloc -Dfree=webrtc_ns_free\" +CFLAGS=\"-O2 ${_ns_arch_cflags} -DNDEBUG -DWEBRTC_ARCH_32_BITS= -DWEBRTC_ARCH_LITTLE_ENDIAN= -I${SOF_WEBRTC_APM_SRC_DIR} -I$SRC/modules/audio_processing/ns/include -Dmalloc=webrtc_ns_malloc -Dcalloc=webrtc_ns_calloc -Dfree=webrtc_ns_free\" SRCS=\" $SRC/modules/audio_processing/ns/noise_suppression.c diff --git a/src/audio/webrtc_ns2/webrtc_ns2-shims.c b/src/audio/webrtc_ns2/webrtc_ns2-shims.c index e6064d31e0e6..a847a8984859 100644 --- a/src/audio/webrtc_ns2/webrtc_ns2-shims.c +++ b/src/audio/webrtc_ns2/webrtc_ns2-shims.c @@ -9,7 +9,7 @@ #include #include #include -#if !defined(LLEXT_MODULE) +#if !defined(LLEXT_MODULE) && !defined(LL_EXTENSION_BUILD) #include static APP_SYSUSER_BSS struct processing_module *active_ns2_mod; #else @@ -56,7 +56,7 @@ void *webrtc_ns2_calloc(size_t nmemb, size_t size) return p; } -#if defined(LLEXT_MODULE) +#if defined(LLEXT_MODULE) || defined(LL_EXTENSION_BUILD) /* ============================ Memory ============================ */ void *malloc(size_t size) @@ -111,6 +111,7 @@ void *memmove(void *dest, const void *src, size_t n) } return dest; } +#endif /* LLEXT_MODULE || LL_EXTENSION_BUILD */ /* ============================ Math ============================== */ @@ -143,17 +144,17 @@ static float ns2_log2f(float x) return (float)e + z * (1.44269504f - z * (0.72134752f - z * 0.48089834f)); } -float log10f(float x) +__attribute__((weak)) float log10f(float x) { return ns2_log2f(x) * 0.3010299956639812f; } -double log10(double x) +__attribute__((weak)) double log10(double x) { return (double)log10f((float)x); } -float floorf(float x) +__attribute__((weak)) float floorf(float x) { int i = (int)x; @@ -162,12 +163,12 @@ float floorf(float x) return (float)i; } -double floor(double x) +__attribute__((weak)) double floor(double x) { return (double)floorf((float)x); } -float ceilf(float x) +__attribute__((weak)) float ceilf(float x) { int i = (int)x; @@ -181,24 +182,24 @@ static inline float ns2_roundf(float x) return (x >= 0.0f) ? floorf(x + 0.5f) : ceilf(x - 0.5f); } -float fabsf(float x) +__attribute__((weak)) float fabsf(float x) { return (x < 0.0f) ? -x : x; } -double fabs(double x) +__attribute__((weak)) double fabs(double x) { return (x < 0.0) ? -x : x; } -float sqrtf(float x) +__attribute__((weak)) float sqrtf(float x) { if (x <= 0.0f) return 0.0f; return __builtin_sqrtf(x); } -double sqrt(double x) +__attribute__((weak)) double sqrt(double x) { return (double)sqrtf((float)x); } @@ -211,7 +212,7 @@ static inline void ns2_sincosf_poly(float z, float *s_out, float *c_out) *c_out = 1.0f + z2 * (-0.5f + z2 * (0.041666667f + z2 * (-0.0013888889f + z2 * 0.0000248016f))); } -float sinf(float x) +__attribute__((weak)) float sinf(float x) { const float inv_half_pi = 0.636619772367581343f; const float half_pi_hi = 1.5707963267948966f; @@ -229,12 +230,12 @@ float sinf(float x) } } -double sin(double x) +__attribute__((weak)) double sin(double x) { return (double)sinf((float)x); } -float cosf(float x) +__attribute__((weak)) float cosf(float x) { const float inv_half_pi = 0.636619772367581343f; const float half_pi_hi = 1.5707963267948966f; @@ -252,12 +253,12 @@ float cosf(float x) } } -double cos(double x) +__attribute__((weak)) double cos(double x) { return (double)cosf((float)x); } -float exp2f(float x) +__attribute__((weak)) float exp2f(float x) { int n; float f, p; @@ -276,13 +277,12 @@ float exp2f(float x) return p * ns2_ldexp2(n); } -float expf(float x) +__attribute__((weak)) float expf(float x) { return exp2f(x * 1.4426950408889634f); } -double exp(double x) +__attribute__((weak)) double exp(double x) { return (double)expf((float)x); } -#endif /* LLEXT_MODULE */ diff --git a/src/audio/webrtc_ns2/webrtc_ns2.cmake b/src/audio/webrtc_ns2/webrtc_ns2.cmake index b9c78c55e6ca..d6bd7dda5790 100644 --- a/src/audio/webrtc_ns2/webrtc_ns2.cmake +++ b/src/audio/webrtc_ns2/webrtc_ns2.cmake @@ -34,6 +34,16 @@ set(WEBRTC_NS2_INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}/rnnoise-install" set(_rnn_src "${SOF_RNNOISE_SRC_DIR}/src") set(_rnn_inc "${SOF_RNNOISE_SRC_DIR}/include") +if("${ARCH}" STREQUAL "xtensa") + if(CONFIG_LLEXT_BUILD_PIC) + set(_rnn_arch_cflags "-fPIC -mlongcalls -mtext-section-literals") + else() + set(_rnn_arch_cflags "-fno-pic -fno-pie -mlongcalls -mtext-section-literals") + endif() +else() + set(_rnn_arch_cflags "-fPIC") +endif() + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/rnnoise-build.sh" "#!/bin/sh set -e @@ -44,7 +54,7 @@ OBJ=${CMAKE_CURRENT_BINARY_DIR}/rnnoise-obj mkdir -p \"$OBJ\" \"$INST/lib\" \"$INST/include\" -CFLAGS=\"-O2 -fPIC -I$SRC -I$INC -DOUTSIDE_SPEEX -DRANDOM_PREFIX=rnn -DFLOAT_APPROX\" +CFLAGS=\"-O2 ${_rnn_arch_cflags} -DNDEBUG -I$SRC -I$INC -DOUTSIDE_SPEEX -DRANDOM_PREFIX=rnn -DFLOAT_APPROX\" # Core RNNoise sources (excludes dump_features.c and train-only files). SRCS=\" diff --git a/src/audio/webrtc_vad/webrtc_vad-shims.c b/src/audio/webrtc_vad/webrtc_vad-shims.c index b8ac6860a2c5..9f6e6f821f66 100644 --- a/src/audio/webrtc_vad/webrtc_vad-shims.c +++ b/src/audio/webrtc_vad/webrtc_vad-shims.c @@ -17,7 +17,7 @@ #include #include #include -#if !defined(LLEXT_MODULE) +#if !defined(LLEXT_MODULE) && !defined(LL_EXTENSION_BUILD) #include static APP_SYSUSER_BSS struct processing_module *active_vad_mod; #else @@ -29,7 +29,7 @@ void webrtc_vad_set_active_mod(struct processing_module *mod) active_vad_mod = mod; } -#if defined(LLEXT_MODULE) +#if defined(LLEXT_MODULE) || defined(LL_EXTENSION_BUILD) /* ============================ Memory ============================ */ void *malloc(size_t size) diff --git a/src/audio/webrtc_vad/webrtc_vad.cmake b/src/audio/webrtc_vad/webrtc_vad.cmake index d0124c7ded5f..49afd97c3cb4 100644 --- a/src/audio/webrtc_vad/webrtc_vad.cmake +++ b/src/audio/webrtc_vad/webrtc_vad.cmake @@ -39,6 +39,16 @@ set(LIBFVAD_INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}/libfvad-install" # Rather than invoking its CMakeLists (which would need a CMake toolchain file), # we compile the objects directly and archive them. This mirrors the libshine # approach in ffmpeg.cmake. +if("${ARCH}" STREQUAL "xtensa") + if(CONFIG_LLEXT_BUILD_PIC) + set(_fvad_arch_cflags "-fPIC -mlongcalls -mtext-section-literals") + else() + set(_fvad_arch_cflags "-fno-pic -fno-pie -mlongcalls -mtext-section-literals") + endif() +else() + set(_fvad_arch_cflags "-fPIC") +endif() + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/fvad-build.sh" "#!/bin/sh set -e @@ -66,7 +76,7 @@ SRCS=\" for f in \$SRCS; do bn=\$(basename \"\$f\" .c) - ${CMAKE_C_COMPILER} -O2 -fPIC \ + ${CMAKE_C_COMPILER} -O2 ${_fvad_arch_cflags} -DNDEBUG \ -I$SRC/include \ -I$SRC/src \ -c \"\$f\" -o \"$OBJ/\${bn}.o\" diff --git a/src/lib/notifier.c b/src/lib/notifier.c index 16b1df0dba3d..057568140f56 100644 --- a/src/lib/notifier.c +++ b/src/lib/notifier.c @@ -178,6 +178,7 @@ void notifier_event(const void *caller, enum notify_id type, uint32_t core_mask, } } } +EXPORT_SYMBOL(notifier_event); __cold void init_system_notify(struct sof *sof) { diff --git a/tools/topology/topology2/cavs-mixin-mixout-hda.conf b/tools/topology/topology2/cavs-mixin-mixout-hda.conf index e5ac78e505d1..ebc0c52780b9 100644 --- a/tools/topology/topology2/cavs-mixin-mixout-hda.conf +++ b/tools/topology/topology2/cavs-mixin-mixout-hda.conf @@ -1,3 +1,4 @@ + Define { @@ -21,6 +22,7 @@ Define { EFX_IIR_PARAMS 'passthrough' EFX_DRC_PARAMS 'passthrough' HDA_MIC_ENHANCED_CAPTURE 'false' + AEC_PROCESSING 'false' # Compress capture (encode) via the FFmpeg encoder (ffmpeg_enc). The PCM # name overrides the generic compr-default.conf default. COMPR_ENC_SOURCE @@ -34,6 +36,12 @@ Define { COMPR_ENC_SOURCE 'mixin.4.1' } +IncludeByKey.AEC_PROCESSING { + "true" { + + } +} + # include deep buffer config if buffer size is in 1 - 1000 ms. IncludeByKey.DEEPBUFFER_FW_DMA_MS{ "[1-1000]" "platform/intel/deep-buffer.conf" @@ -439,6 +447,85 @@ IncludeByKey.HDA_MIC_ENHANCED_CAPTURE { } } +IncludeByKey.AEC_PROCESSING { + "true" { + Object.Widget.module-copier."2" { + index 2 + stream_name $HDA_ANALOG_DAI_NAME + num_input_pins 1 + num_output_pins 2 + num_input_audio_formats 1 + num_output_audio_formats 1 + Object.Base.input_audio_format [ + { + in_rate $HDA_ANALOG_PLAYBACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_rate $HDA_ANALOG_PLAYBACK_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + + Object.Widget.webrtc-aec [ + { + index 3 + name "webrtc-aec.3.1" + num_input_pins 2 + num_input_audio_formats 2 + num_output_audio_formats 1 + + Object.Base.input_audio_format [ + { + input_pin_index 0 + in_rate $HDA_ANALOG_CAPTURE_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + ibs "$[(($in_channels * ($[($in_rate + 999)] / 1000)) * ($in_bit_depth / 8)) * $WEBRTC_AEC_PERIOD_MS]" + } + { + input_pin_index 1 + in_rate $HDA_ANALOG_PLAYBACK_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + ibs "$[(($in_channels * ($[($in_rate + 999)] / 1000)) * ($in_bit_depth / 8)) * $WEBRTC_AEC_PERIOD_MS]" + } + ] + + Object.Base.output_audio_format [ + { + out_rate $HDA_ANALOG_CAPTURE_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + obs "$[(($out_channels * ($[($out_rate + 999)] / 1000)) * ($out_bit_depth / 8)) * $WEBRTC_AEC_PERIOD_MS]" + } + ] + + Object.Base.input_pin_binding.1 { + input_pin_binding_name "module-copier.4.2" + } + Object.Base.input_pin_binding.2 { + input_pin_binding_name "module-copier.2.2" + } + + Object.Control { + mixer."1" { + name '$ANALOG_CAPTURE_PCM AEC Switch' + } + mixer."2" { + name '$ANALOG_CAPTURE_PCM AEC Suppression Switch' + } + } + } + ] + } +} + Object.PCM.pcm [ { id 0 @@ -466,10 +553,6 @@ Object.PCM.pcm [ # top-level pipeline connections Object.Base.route [ - { - sink 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.playback' - source 'drc.2.1' - } { source 'mixin.1.1' sink 'mixout.2.1' @@ -480,6 +563,29 @@ Object.Base.route [ } ] +IncludeByKey.AEC_PROCESSING { + "true" { + Object.Base.route [ + { + source 'drc.2.1' + sink 'module-copier.2.2' + } + { + source 'module-copier.2.2' + sink 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.playback' + } + ] + } + "false" { + Object.Base.route [ + { + source 'drc.2.1' + sink 'dai-copier.HDA.$HDA_ANALOG_DAI_NAME.playback' + } + ] + } +} + IncludeByKey.COMPR_FFMPEG_ENC { "false" { # stock capture BE processing chain feeding the normal analog capture FE @@ -507,12 +613,32 @@ IncludeByKey.COMPR_FFMPEG_ENC { ] } "false" { - Object.Base.route [ - { - source 'module-copier.4.2' - sink 'host-copier.0.capture' + IncludeByKey.AEC_PROCESSING { + "true" { + Object.Base.route [ + { + source 'module-copier.4.2' + sink 'webrtc-aec.3.1' + } + { + source 'module-copier.2.2' + sink 'webrtc-aec.3.1' + } + { + source 'webrtc-aec.3.1' + sink 'host-copier.0.capture' + } + ] } - ] + "false" { + Object.Base.route [ + { + source 'module-copier.4.2' + sink 'host-copier.0.capture' + } + ] + } + } } } } diff --git a/tools/topology/topology2/cavs-sdw.conf b/tools/topology/topology2/cavs-sdw.conf index 7edd0975d4f6..5d19c41b4d88 100644 --- a/tools/topology/topology2/cavs-sdw.conf +++ b/tools/topology/topology2/cavs-sdw.conf @@ -288,3 +288,14 @@ IncludeByKey.SDW_DMIC_AUDIO_FEATURE_CAPTURE { IncludeByKey.SDW_DMIC_COMPR_AUDIO_FEATURE_CAPTURE { "true" "platform/intel/sdw-dmic-audio-feature-compress.conf" } + +IncludeByKey.SDW_JACK_WEBRTC_CAPTURE { + "^ns$" "platform/intel/sdw-jack-webrtc-feature.conf" + "^ns2$" "platform/intel/sdw-jack-webrtc-feature.conf" + "^aec$" "platform/intel/sdw-jack-webrtc-feature.conf" +} + +IncludeByKey.SDW_DMIC_WEBRTC_CAPTURE { + "^ns$" "platform/intel/sdw-dmic-webrtc-feature.conf" + "^ns2$" "platform/intel/sdw-dmic-webrtc-feature.conf" +} diff --git a/tools/topology/topology2/development/cavs-nocodec-webrtc-ns.conf b/tools/topology/topology2/development/cavs-nocodec-webrtc-ns.conf index 59c17845d940..047aeeec8a6c 100644 --- a/tools/topology/topology2/development/cavs-nocodec-webrtc-ns.conf +++ b/tools/topology/topology2/development/cavs-nocodec-webrtc-ns.conf @@ -1,17 +1,19 @@ # -# cAVS nocodec topology: webrtc-vad + webrtc-ns capture test +# cAVS nocodec topology: webrtc-hpf + webrtc-vad + webrtc-ns + webrtc-agc capture test # -# Standalone test topology for validating the webrtc_vad and webrtc_ns -# modules on real hardware using the nocodec (loopback) SSP interface. +# Standalone test topology for validating the webrtc_hpf, webrtc_vad, +# webrtc_ns, and webrtc_agc modules on real hardware using the nocodec +# (loopback) SSP interface. # # Pipeline diagram: # -# PCM0 playback ──(1)──────────────(2)──> SSP0 TX +# PCM0 playback ──(1)──────────────────────────(2)──> SSP0 TX # -# SSP0 RX ──────(3)──> VAD + NS ──(4)──> PCM0 capture +# SSP0 RX ──────(3)──> HPF + VAD + NS + AGC ──(4)──> PCM0 capture # -# The VAD module fires NOTIFIER_ID_VAD events; the NS module removes -# stationary background noise. Both run on the same capture pipeline. +# The HPF module removes DC and <80 Hz rumble; the VAD module fires +# NOTIFIER_ID_VAD events; the NS module removes stationary background noise; +# and the AGC module normalizes speech levels. All run on the capture pipeline. # # Board: any cAVS/ACE platform with a nocodec SSP loopback fixture. # Compile: alsatplg -c cavs-nocodec-webrtc-ns.conf -o webrtc-ns.tplg diff --git a/tools/topology/topology2/development/tplg-targets.cmake b/tools/topology/topology2/development/tplg-targets.cmake index 9713c7088182..acabd4b0a1c0 100644 --- a/tools/topology/topology2/development/tplg-targets.cmake +++ b/tools/topology/topology2/development/tplg-targets.cmake @@ -325,17 +325,49 @@ PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-tgl-nocodec-crossover.bin,EFX_CROSSOVE "development/cavs-nocodec-rtcaec\;sof-tgl-nocodec-rtcaec\;PLATFORM=tgl,\ PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-tgl-nocodec-rtcaec.bin" -# WebRTC noise suppressor (webrtc_ns + webrtc_vad) on TGL nocodec SSP +# WebRTC voice pre-processing (webrtc_hpf + webrtc_vad + webrtc_ns + webrtc_agc) on TGL/PTL nocodec SSP "development/cavs-nocodec-webrtc-ns\;sof-tgl-nocodec-webrtc-ns\;PLATFORM=tgl,\ PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-tgl-nocodec-webrtc-ns.bin" +"development/cavs-nocodec-webrtc-ns\;sof-ptl-nocodec-webrtc-ns\;PLATFORM=ptl,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-ptl-nocodec-webrtc-ns.bin" -# WebRTC AECm echo canceller (dual SSP: mic + ref) on TGL nocodec +# WebRTC AEC echo canceller (dual SSP: mic + ref) on TGL/PTL nocodec "development/cavs-nocodec-webrtc-aec\;sof-tgl-nocodec-webrtc-aec\;PLATFORM=tgl,\ PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-tgl-nocodec-webrtc-aec.bin" +"development/cavs-nocodec-webrtc-aec\;sof-ptl-nocodec-webrtc-aec\;PLATFORM=ptl,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-ptl-nocodec-webrtc-aec.bin" -# WebRTC NS2/RNNoise (48 kHz float) on TGL nocodec SSP +# WebRTC NS2/RNNoise (48 kHz float) on TGL/PTL nocodec SSP "development/cavs-nocodec-webrtc-ns2\;sof-tgl-nocodec-webrtc-ns2\;PLATFORM=tgl,\ PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-tgl-nocodec-webrtc-ns2.bin" +"development/cavs-nocodec-webrtc-ns2\;sof-ptl-nocodec-webrtc-ns2\;PLATFORM=ptl,\ +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-ptl-nocodec-webrtc-ns2.bin" + +# WebRTC AEC capture on HDA generic +"sof-hda-generic\;sof-hda-generic-webrtc-aec\;HDA_CONFIG=mix,AEC_PROCESSING=true" + +# Standalone DMIC WebRTC feature topologies (NS chain at 16 kHz and NS2 RNNoise at 48 kHz) +"dmic-webrtc-feature\;sof-dmic-2ch-webrtc-ns\;PLATFORM=none,NUM_DMICS=2,DMIC1_RATE=16000,\ +WEBRTC_DMIC1_MODE=ns" +"dmic-webrtc-feature\;sof-dmic-2ch-webrtc-ns2\;PLATFORM=none,NUM_DMICS=2,DMIC1_RATE=48000,\ +WEBRTC_DMIC1_MODE=ns2" + +# SoundWire SDCA function topologies with WebRTC capture feature pipelines +"cavs-sdw\;sof-sdca-mic-id4-webrtc-ns\;SDW_JACK=false,SDW_DMIC=1,NUM_HDMIS=0,\ +SDW_DMIC_STREAM=Capture-SmartMic,SDW_DMIC_WEBRTC_CAPTURE=ns" +"cavs-sdw\;sof-sdca-mic-id4-webrtc-ns2\;SDW_JACK=false,SDW_DMIC=1,NUM_HDMIS=0,\ +SDW_DMIC_STREAM=Capture-SmartMic,SDW_DMIC_WEBRTC_CAPTURE=ns2" +"cavs-sdw\;sof-sdca-jack-id0-webrtc-ns\;SDW_JACK_OUT_STREAM=Playback-SimpleJack,\ +SDW_JACK_IN_STREAM=Capture-SimpleJack,NUM_HDMIS=0,SDW_JACK_WEBRTC_CAPTURE=ns" +"cavs-sdw\;sof-sdca-jack-id0-webrtc-aec\;SDW_JACK_OUT_STREAM=Playback-SimpleJack,\ +SDW_JACK_IN_STREAM=Capture-SimpleJack,NUM_HDMIS=0,SDW_JACK_WEBRTC_CAPTURE=aec" + +# PTL PCH-DMIC function topology with 16 kHz DMIC1 WebRTC NS capture +"cavs-sdw\;sof-ptl-dmic-2ch-id2-webrtc-ns\;PLATFORM=ptl,SDW_JACK=false,NUM_HDMIS=0,\ +NUM_DMICS=2,PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,DMIC0_ID=2,DMIC1_ID=3,\ +DMIC1_ENABLE=webrtc,DMIC1_RATE=16000,PREPROCESS_PLUGINS=nhlt,\ +NHLT_BIN=nhlt-sof-ptl-dmic-2ch-id2-webrtc-ns.bin,DMIC0_ENHANCED_CAPTURE=true,\ +EFX_DMIC0_TDFB_PARAMS=line2_generic_pm10deg,EFX_DMIC0_DRC_PARAMS=dmic_default" # Topology to test the USB audio offload on an HDA machine, load it with # snd_sof.tplg_filename=sof-hda-generic-uaol.tplg diff --git a/tools/topology/topology2/dmic-webrtc-feature.conf b/tools/topology/topology2/dmic-webrtc-feature.conf new file mode 100644 index 000000000000..20cd803929b8 --- /dev/null +++ b/tools/topology/topology2/dmic-webrtc-feature.conf @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/topology/topology2/include/common/common_definitions.conf b/tools/topology/topology2/include/common/common_definitions.conf index 06f0f425c5e2..2a4ba61880f5 100644 --- a/tools/topology/topology2/include/common/common_definitions.conf +++ b/tools/topology/topology2/include/common/common_definitions.conf @@ -75,4 +75,6 @@ Define { SDW_JACK_COMPR_AUDIO_FEATURE_CAPTURE false # No compress audio features capture for jack SDW_DMIC_AUDIO_FEATURE_CAPTURE false # No audio features capture for microphone SDW_DMIC_COMPR_AUDIO_FEATURE_CAPTURE false # No compress audio features capture for microphone + SDW_JACK_WEBRTC_CAPTURE false # No WebRTC capture for jack + SDW_DMIC_WEBRTC_CAPTURE false # No WebRTC capture for microphone } diff --git a/tools/topology/topology2/include/pipelines/cavs/dai-copier-eqiir-module-copier-capture.conf b/tools/topology/topology2/include/pipelines/cavs/dai-copier-eqiir-module-copier-capture.conf index 0f38da399467..245540faa634 100644 --- a/tools/topology/topology2/include/pipelines/cavs/dai-copier-eqiir-module-copier-capture.conf +++ b/tools/topology/topology2/include/pipelines/cavs/dai-copier-eqiir-module-copier-capture.conf @@ -146,6 +146,7 @@ Class.Pipeline."dai-copier-eqiir-module-copier-capture" { pipeline."1" { priority 0 lp_mode 0 + direction "capture" } } diff --git a/tools/topology/topology2/include/pipelines/cavs/host-gateway-capture.conf b/tools/topology/topology2/include/pipelines/cavs/host-gateway-capture.conf index c9a520f28b80..d4da094c7fe5 100644 --- a/tools/topology/topology2/include/pipelines/cavs/host-gateway-capture.conf +++ b/tools/topology/topology2/include/pipelines/cavs/host-gateway-capture.conf @@ -100,6 +100,7 @@ Class.Pipeline."host-gateway-capture" { pipeline."1" { priority 0 lp_mode 0 + direction "capture" } } diff --git a/tools/topology/topology2/include/pipelines/cavs/webrtc-aec-capture.conf b/tools/topology/topology2/include/pipelines/cavs/webrtc-aec-capture.conf index 76d40f18651b..f6fb5723a3a5 100644 --- a/tools/topology/topology2/include/pipelines/cavs/webrtc-aec-capture.conf +++ b/tools/topology/topology2/include/pipelines/cavs/webrtc-aec-capture.conf @@ -46,6 +46,7 @@ Class.Pipeline."webrtc-aec-capture" { pipeline."1" { priority 0 lp_mode 0 + direction "capture" } # Input copier: S32 DAI → S16 for AECm (fixed-point) diff --git a/tools/topology/topology2/include/pipelines/cavs/webrtc-ns-capture.conf b/tools/topology/topology2/include/pipelines/cavs/webrtc-ns-capture.conf index a43082adc9fb..1df6c3367a36 100644 --- a/tools/topology/topology2/include/pipelines/cavs/webrtc-ns-capture.conf +++ b/tools/topology/topology2/include/pipelines/cavs/webrtc-ns-capture.conf @@ -1,12 +1,12 @@ # -# cAVS webrtc-vad + webrtc-ns capture pipeline +# cAVS webrtc-hpf + webrtc-vad + webrtc-ns + webrtc-agc capture pipeline # -# DAI-copier → webrtc-vad → webrtc-ns → module-copier → host +# DAI-copier → webrtc-hpf → webrtc-vad → webrtc-ns → webrtc-agc → module-copier → host # -# webrtc-vad runs first so the VAD event fires on unprocessed mic audio. -# webrtc-ns follows to remove stationary noise before the host receives it. -# Either module can be omitted by editing routes; the component confs are -# independent and can be used separately. +# webrtc-hpf removes DC offset and sub-80 Hz rumble first. +# webrtc-vad runs next so the VAD event fires on high-passed mic audio. +# webrtc-ns removes stationary noise, and webrtc-agc normalizes speech +# levels before the host receives the stream. # # Usage: # Object.Pipeline.webrtc-ns-capture."N" { @@ -20,8 +20,10 @@ + + Class.Pipeline."webrtc-ns-capture" { @@ -44,6 +46,7 @@ Class.Pipeline."webrtc-ns-capture" { pipeline."1" { priority 0 lp_mode 0 + direction "capture" } # DAI → S32 on capture; convert to S16 for NS processing @@ -68,6 +71,13 @@ Class.Pipeline."webrtc-ns-capture" { ] } + # HPF: 2nd-order Butterworth high-pass filter (<80 Hz rejection) + webrtc-hpf."1" { + Object.Control.mixer.1 { + name 'WebRTC HPF Switch' + } + } + # VAD: pass-through + VAD event webrtc-vad."1" { } @@ -76,6 +86,13 @@ Class.Pipeline."webrtc-ns-capture" { webrtc-ns."1" { } + # AGC: digital automatic gain control + saturation limiter + webrtc-agc."1" { + Object.Control.mixer.1 { + name 'WebRTC AGC Switch' + } + } + # Output copier: S16 → S32 for host module-copier."2" { period_sink_count 1 @@ -102,14 +119,22 @@ Class.Pipeline."webrtc-ns-capture" { Object.Base { route.1 { source module-copier.$index.1 - sink webrtc-vad.$index.1 + sink webrtc-hpf.$index.1 } route.2 { + source webrtc-hpf.$index.1 + sink webrtc-vad.$index.1 + } + route.3 { source webrtc-vad.$index.1 sink webrtc-ns.$index.1 } - route.3 { + route.4 { source webrtc-ns.$index.1 + sink webrtc-agc.$index.1 + } + route.5 { + source webrtc-agc.$index.1 sink module-copier.$index.2 } } diff --git a/tools/topology/topology2/include/pipelines/cavs/webrtc-ns2-capture.conf b/tools/topology/topology2/include/pipelines/cavs/webrtc-ns2-capture.conf index e305ffd5acf2..25910fbb8825 100644 --- a/tools/topology/topology2/include/pipelines/cavs/webrtc-ns2-capture.conf +++ b/tools/topology/topology2/include/pipelines/cavs/webrtc-ns2-capture.conf @@ -44,6 +44,7 @@ Class.Pipeline."webrtc-ns2-capture" { pipeline."1" { priority 0 lp_mode 0 + direction "capture" } # RNNoise widget — 48 kHz float internally, S16/S32 pipeline diff --git a/tools/topology/topology2/platform/intel/dmic-generic.conf b/tools/topology/topology2/platform/intel/dmic-generic.conf index c473f1eea470..b42717f76310 100644 --- a/tools/topology/topology2/platform/intel/dmic-generic.conf +++ b/tools/topology/topology2/platform/intel/dmic-generic.conf @@ -1048,4 +1048,5 @@ IncludeByKey.DMIC0_DEEP_BUFFER { IncludeByKey.DMIC1_ENABLE { "passthrough" "platform/intel/dmic1-passthrough.conf" "mfcc" "platform/intel/dmic1-mfcc.conf" + "webrtc" "platform/intel/dmic1-webrtc.conf" } diff --git a/tools/topology/topology2/platform/intel/dmic1-webrtc.conf b/tools/topology/topology2/platform/intel/dmic1-webrtc.conf new file mode 100644 index 000000000000..168702f9722f --- /dev/null +++ b/tools/topology/topology2/platform/intel/dmic1-webrtc.conf @@ -0,0 +1,209 @@ + + + + + + +Define { + DMIC1_PCM_NAME "DMIC WebRTC" + WEBRTC_DMIC1_MODE "ns" +} + +Object.Pipeline.host-gateway-capture [ + { + index $DMIC1_HOST_PIPELINE_ID + Object.Widget.host-copier.1 { + stream_name $DMIC1_PCM_CAPS + pcm_id $DMIC1_PCM_ID + num_input_audio_formats 1 + num_output_audio_formats 1 + Object.Base.input_audio_format [ + { + in_rate $DMIC1_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_rate $DMIC1_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + } +] + +Object.Pipeline.io-gateway-capture [ + { + index $DMIC1_DAI_PIPELINE_ID + Object.Widget.dai-copier.1 { + dai_index 1 + dai_type "DMIC" + copier_type "DMIC" + type dai_out + stream_name $DMIC1_NAME + node_type $DMIC_LINK_INPUT_CLASS + num_input_audio_formats 3 + num_output_audio_formats 1 + Object.Base.input_audio_format [ + { + in_rate $DMIC1_RATE + in_bit_depth 16 + in_valid_bit_depth 16 + } + { + in_rate $DMIC1_RATE + in_bit_depth 32 + in_valid_bit_depth 24 + in_sample_type $SAMPLE_TYPE_MSB_INTEGER + } + { + in_rate $DMIC1_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_rate $DMIC1_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + } +] + +IncludeByKey.WEBRTC_DMIC1_MODE { + "^ns$" { + Object.Widget { + module-copier."2" { + index $DMIC1_HOST_PIPELINE_ID + num_input_audio_formats 1 + num_output_audio_formats 1 + Object.Base.input_audio_format [ + { + in_rate $DMIC1_RATE + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_rate $DMIC1_RATE + out_bit_depth 16 + out_valid_bit_depth 16 + } + ] + } + webrtc-hpf."1" { + index $DMIC1_HOST_PIPELINE_ID + Object.Control.mixer."1" { + name 'DMIC1 Capture HPF Switch' + } + } + webrtc-vad."1" { + index $DMIC1_HOST_PIPELINE_ID + } + webrtc-ns."1" { + index $DMIC1_HOST_PIPELINE_ID + } + webrtc-agc."1" { + index $DMIC1_HOST_PIPELINE_ID + Object.Control.mixer."1" { + name 'DMIC1 Capture AGC Switch' + } + } + module-copier."3" { + index $DMIC1_HOST_PIPELINE_ID + num_input_audio_formats 1 + num_output_audio_formats 1 + Object.Base.input_audio_format [ + { + in_rate $DMIC1_RATE + in_bit_depth 16 + in_valid_bit_depth 16 + } + ] + Object.Base.output_audio_format [ + { + out_rate $DMIC1_RATE + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + } + + Object.Base.route [ + { + source "dai-copier.DMIC.$DMIC1_NAME.capture" + sink "module-copier.$DMIC1_HOST_PIPELINE_ID.2" + } + { + source "module-copier.$DMIC1_HOST_PIPELINE_ID.2" + sink "webrtc-hpf.$DMIC1_HOST_PIPELINE_ID.1" + } + { + source "webrtc-hpf.$DMIC1_HOST_PIPELINE_ID.1" + sink "webrtc-vad.$DMIC1_HOST_PIPELINE_ID.1" + } + { + source "webrtc-vad.$DMIC1_HOST_PIPELINE_ID.1" + sink "webrtc-ns.$DMIC1_HOST_PIPELINE_ID.1" + } + { + source "webrtc-ns.$DMIC1_HOST_PIPELINE_ID.1" + sink "webrtc-agc.$DMIC1_HOST_PIPELINE_ID.1" + } + { + source "webrtc-agc.$DMIC1_HOST_PIPELINE_ID.1" + sink "module-copier.$DMIC1_HOST_PIPELINE_ID.3" + } + { + source "module-copier.$DMIC1_HOST_PIPELINE_ID.3" + sink "host-copier.$DMIC1_PCM_ID.capture" + } + ] + } + "^ns2$" { + Object.Widget { + webrtc-ns2."1" { + index $DMIC1_HOST_PIPELINE_ID + } + } + + Object.Base.route [ + { + source "dai-copier.DMIC.$DMIC1_NAME.capture" + sink "webrtc-ns2.$DMIC1_HOST_PIPELINE_ID.1" + } + { + source "webrtc-ns2.$DMIC1_HOST_PIPELINE_ID.1" + sink "host-copier.$DMIC1_PCM_ID.capture" + } + ] + } +} + +Object.PCM.pcm [ + { + name "$DMIC1_PCM_NAME" + id $DMIC1_PCM_ID + direction "capture" + Object.Base.fe_dai.1 { + name "$DMIC1_PCM_NAME" + } + + Object.PCM.pcm_caps.1 { + name $DMIC1_PCM_CAPS + formats 'S32_LE' + channels_min 2 + channels_max 2 + rate_min $DMIC1_RATE + rate_max $DMIC1_RATE + } + } +] diff --git a/tools/topology/topology2/platform/intel/sdw-dmic-webrtc-feature.conf b/tools/topology/topology2/platform/intel/sdw-dmic-webrtc-feature.conf new file mode 100644 index 000000000000..1ba5f5d57235 --- /dev/null +++ b/tools/topology/topology2/platform/intel/sdw-dmic-webrtc-feature.conf @@ -0,0 +1,196 @@ + + + + + + +Define { + SDW_DMIC_MODULE_COPIER_ID 41 + SDW_DMIC_WEBRTC_CAPTURE_PCM_NAME "Microphone WebRTC" + SDW_DMIC_WEBRTC_CAPTURE_PCM_ID 49 + SDW_DMIC_WEBRTC_CAPTURE_STREAM_NAME "Microphone WebRTC Stream" + SDW_DMIC_WEBRTC_CAPTURE_PIPELINE_ID 134 +} + +IncludeByKey.SDW_DMIC_WEBRTC_CAPTURE { + "^ns$" { + Object.Pipeline.host-gateway-capture [ + { + index $SDW_DMIC_WEBRTC_CAPTURE_PIPELINE_ID + + Object.Widget.host-copier.1 { + stream_name "$SDW_DMIC_WEBRTC_CAPTURE_STREAM_NAME" + pcm_id $SDW_DMIC_WEBRTC_CAPTURE_PCM_ID + num_input_audio_formats 1 + num_output_audio_formats 1 + Object.Base.input_audio_format [ + { + in_rate 16000 + in_bit_depth 16 + in_valid_bit_depth 16 + } + ] + Object.Base.output_audio_format [ + { + out_rate 16000 + out_bit_depth 16 + out_valid_bit_depth 16 + } + ] + } + } + ] + + Object.Widget { + src."1" { + index $SDW_DMIC_WEBRTC_CAPTURE_PIPELINE_ID + rate_in 48000 + rate_out 16000 + num_input_audio_formats 1 + num_output_audio_formats 1 + Object.Base.input_audio_format [ + { + in_rate 48000 + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_rate 16000 + out_bit_depth 16 + out_valid_bit_depth 16 + } + ] + } + webrtc-hpf."1" { + index $SDW_DMIC_WEBRTC_CAPTURE_PIPELINE_ID + Object.Control.mixer."1" { + name 'Microphone WebRTC HPF Switch' + } + } + webrtc-vad."1" { + index $SDW_DMIC_WEBRTC_CAPTURE_PIPELINE_ID + } + webrtc-ns."1" { + index $SDW_DMIC_WEBRTC_CAPTURE_PIPELINE_ID + } + webrtc-agc."1" { + index $SDW_DMIC_WEBRTC_CAPTURE_PIPELINE_ID + Object.Control.mixer."1" { + name 'Microphone WebRTC AGC Switch' + } + } + } + + Object.Base.route [ + { + source "module-copier.$SDW_DMIC_MODULE_COPIER_ID.0" + sink "src.$SDW_DMIC_WEBRTC_CAPTURE_PIPELINE_ID.1" + } + { + source "src.$SDW_DMIC_WEBRTC_CAPTURE_PIPELINE_ID.1" + sink "webrtc-hpf.$SDW_DMIC_WEBRTC_CAPTURE_PIPELINE_ID.1" + } + { + source "webrtc-hpf.$SDW_DMIC_WEBRTC_CAPTURE_PIPELINE_ID.1" + sink "webrtc-vad.$SDW_DMIC_WEBRTC_CAPTURE_PIPELINE_ID.1" + } + { + source "webrtc-vad.$SDW_DMIC_WEBRTC_CAPTURE_PIPELINE_ID.1" + sink "webrtc-ns.$SDW_DMIC_WEBRTC_CAPTURE_PIPELINE_ID.1" + } + { + source "webrtc-ns.$SDW_DMIC_WEBRTC_CAPTURE_PIPELINE_ID.1" + sink "webrtc-agc.$SDW_DMIC_WEBRTC_CAPTURE_PIPELINE_ID.1" + } + { + source "webrtc-agc.$SDW_DMIC_WEBRTC_CAPTURE_PIPELINE_ID.1" + sink "host-copier.$SDW_DMIC_WEBRTC_CAPTURE_PCM_ID.capture" + } + ] + + Object.PCM.pcm [ + { + name "$SDW_DMIC_WEBRTC_CAPTURE_PCM_NAME" + id $SDW_DMIC_WEBRTC_CAPTURE_PCM_ID + direction "capture" + Object.Base.fe_dai.1 { + name "$SDW_DMIC_WEBRTC_CAPTURE_PCM_NAME" + } + + Object.PCM.pcm_caps.1 { + name "$SDW_DMIC_WEBRTC_CAPTURE_STREAM_NAME" + formats 'S16_LE' + rates '16000' + channels_min 2 + channels_max 2 + } + } + ] + } + "^ns2$" { + Object.Pipeline.host-gateway-capture [ + { + index $SDW_DMIC_WEBRTC_CAPTURE_PIPELINE_ID + + Object.Widget.host-copier.1 { + stream_name "$SDW_DMIC_WEBRTC_CAPTURE_STREAM_NAME" + pcm_id $SDW_DMIC_WEBRTC_CAPTURE_PCM_ID + num_input_audio_formats 1 + num_output_audio_formats 1 + Object.Base.input_audio_format [ + { + in_rate 48000 + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_rate 48000 + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + } + ] + + Object.Widget { + webrtc-ns2."1" { + index $SDW_DMIC_WEBRTC_CAPTURE_PIPELINE_ID + } + } + + Object.Base.route [ + { + source "module-copier.$SDW_DMIC_MODULE_COPIER_ID.0" + sink "webrtc-ns2.$SDW_DMIC_WEBRTC_CAPTURE_PIPELINE_ID.1" + } + { + source "webrtc-ns2.$SDW_DMIC_WEBRTC_CAPTURE_PIPELINE_ID.1" + sink "host-copier.$SDW_DMIC_WEBRTC_CAPTURE_PCM_ID.capture" + } + ] + + Object.PCM.pcm [ + { + name "$SDW_DMIC_WEBRTC_CAPTURE_PCM_NAME" + id $SDW_DMIC_WEBRTC_CAPTURE_PCM_ID + direction "capture" + Object.Base.fe_dai.1 { + name "$SDW_DMIC_WEBRTC_CAPTURE_PCM_NAME" + } + + Object.PCM.pcm_caps.1 { + name "$SDW_DMIC_WEBRTC_CAPTURE_STREAM_NAME" + formats 'S32_LE' + rates '48000' + channels_min 2 + channels_max 2 + } + } + ] + } +} diff --git a/tools/topology/topology2/platform/intel/sdw-jack-webrtc-feature.conf b/tools/topology/topology2/platform/intel/sdw-jack-webrtc-feature.conf new file mode 100644 index 000000000000..08e89f31830b --- /dev/null +++ b/tools/topology/topology2/platform/intel/sdw-jack-webrtc-feature.conf @@ -0,0 +1,313 @@ + + + + + + + + +Define { + SDW_JACK_MODULE_COPIER_ID 11 + SDW_JACK_REF_COPIER "module-copier.1.12" + SDW_JACK_WEBRTC_CAPTURE_PCM_NAME "Jack In WebRTC" + SDW_JACK_WEBRTC_CAPTURE_PCM_ID 45 + SDW_JACK_WEBRTC_CAPTURE_STREAM_NAME "Jack In WebRTC Stream" + SDW_JACK_WEBRTC_CAPTURE_PIPELINE_ID 133 +} + +IncludeByKey.SDW_JACK_WEBRTC_CAPTURE { + "^ns$" { + Object.Pipeline.host-gateway-capture [ + { + index $SDW_JACK_WEBRTC_CAPTURE_PIPELINE_ID + + Object.Widget.host-copier.1 { + stream_name "$SDW_JACK_WEBRTC_CAPTURE_STREAM_NAME" + pcm_id $SDW_JACK_WEBRTC_CAPTURE_PCM_ID + num_input_audio_formats 1 + num_output_audio_formats 1 + Object.Base.input_audio_format [ + { + in_rate 16000 + in_bit_depth 16 + in_valid_bit_depth 16 + } + ] + Object.Base.output_audio_format [ + { + out_rate 16000 + out_bit_depth 16 + out_valid_bit_depth 16 + } + ] + } + } + ] + + Object.Widget { + src."1" { + index $SDW_JACK_WEBRTC_CAPTURE_PIPELINE_ID + rate_in 48000 + rate_out 16000 + num_input_audio_formats 1 + num_output_audio_formats 1 + Object.Base.input_audio_format [ + { + in_rate 48000 + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_rate 16000 + out_bit_depth 16 + out_valid_bit_depth 16 + } + ] + } + webrtc-hpf."1" { + index $SDW_JACK_WEBRTC_CAPTURE_PIPELINE_ID + Object.Control.mixer."1" { + name 'Jack In WebRTC HPF Switch' + } + } + webrtc-vad."1" { + index $SDW_JACK_WEBRTC_CAPTURE_PIPELINE_ID + } + webrtc-ns."1" { + index $SDW_JACK_WEBRTC_CAPTURE_PIPELINE_ID + } + webrtc-agc."1" { + index $SDW_JACK_WEBRTC_CAPTURE_PIPELINE_ID + Object.Control.mixer."1" { + name 'Jack In WebRTC AGC Switch' + } + } + } + + Object.Base.route [ + { + source "module-copier.$SDW_JACK_MODULE_COPIER_ID.0" + sink "src.$SDW_JACK_WEBRTC_CAPTURE_PIPELINE_ID.1" + } + { + source "src.$SDW_JACK_WEBRTC_CAPTURE_PIPELINE_ID.1" + sink "webrtc-hpf.$SDW_JACK_WEBRTC_CAPTURE_PIPELINE_ID.1" + } + { + source "webrtc-hpf.$SDW_JACK_WEBRTC_CAPTURE_PIPELINE_ID.1" + sink "webrtc-vad.$SDW_JACK_WEBRTC_CAPTURE_PIPELINE_ID.1" + } + { + source "webrtc-vad.$SDW_JACK_WEBRTC_CAPTURE_PIPELINE_ID.1" + sink "webrtc-ns.$SDW_JACK_WEBRTC_CAPTURE_PIPELINE_ID.1" + } + { + source "webrtc-ns.$SDW_JACK_WEBRTC_CAPTURE_PIPELINE_ID.1" + sink "webrtc-agc.$SDW_JACK_WEBRTC_CAPTURE_PIPELINE_ID.1" + } + { + source "webrtc-agc.$SDW_JACK_WEBRTC_CAPTURE_PIPELINE_ID.1" + sink "host-copier.$SDW_JACK_WEBRTC_CAPTURE_PCM_ID.capture" + } + ] + + Object.PCM.pcm [ + { + name "$SDW_JACK_WEBRTC_CAPTURE_PCM_NAME" + id $SDW_JACK_WEBRTC_CAPTURE_PCM_ID + direction "capture" + Object.Base.fe_dai.1 { + name "$SDW_JACK_WEBRTC_CAPTURE_PCM_NAME" + } + + Object.PCM.pcm_caps.1 { + name "$SDW_JACK_WEBRTC_CAPTURE_STREAM_NAME" + formats 'S16_LE' + rates '16000' + channels_min 2 + channels_max 2 + } + } + ] + } + "^ns2$" { + Object.Pipeline.host-gateway-capture [ + { + index $SDW_JACK_WEBRTC_CAPTURE_PIPELINE_ID + + Object.Widget.host-copier.1 { + stream_name "$SDW_JACK_WEBRTC_CAPTURE_STREAM_NAME" + pcm_id $SDW_JACK_WEBRTC_CAPTURE_PCM_ID + num_input_audio_formats 1 + num_output_audio_formats 1 + Object.Base.input_audio_format [ + { + in_rate 48000 + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_rate 48000 + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + } + ] + + Object.Widget { + webrtc-ns2."1" { + index $SDW_JACK_WEBRTC_CAPTURE_PIPELINE_ID + } + } + + Object.Base.route [ + { + source "module-copier.$SDW_JACK_MODULE_COPIER_ID.0" + sink "webrtc-ns2.$SDW_JACK_WEBRTC_CAPTURE_PIPELINE_ID.1" + } + { + source "webrtc-ns2.$SDW_JACK_WEBRTC_CAPTURE_PIPELINE_ID.1" + sink "host-copier.$SDW_JACK_WEBRTC_CAPTURE_PCM_ID.capture" + } + ] + + Object.PCM.pcm [ + { + name "$SDW_JACK_WEBRTC_CAPTURE_PCM_NAME" + id $SDW_JACK_WEBRTC_CAPTURE_PCM_ID + direction "capture" + Object.Base.fe_dai.1 { + name "$SDW_JACK_WEBRTC_CAPTURE_PCM_NAME" + } + + Object.PCM.pcm_caps.1 { + name "$SDW_JACK_WEBRTC_CAPTURE_STREAM_NAME" + formats 'S32_LE' + rates '48000' + channels_min 2 + channels_max 2 + } + } + ] + } + "^aec$" { + Object.Pipeline.host-gateway-capture [ + { + index $SDW_JACK_WEBRTC_CAPTURE_PIPELINE_ID + + Object.Widget.host-copier.1 { + stream_name "$SDW_JACK_WEBRTC_CAPTURE_STREAM_NAME" + pcm_id $SDW_JACK_WEBRTC_CAPTURE_PCM_ID + num_input_audio_formats 1 + num_output_audio_formats 1 + Object.Base.input_audio_format [ + { + in_rate 48000 + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_rate 48000 + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + } + ] + + Object.Widget.webrtc-aec [ + { + index $SDW_JACK_WEBRTC_CAPTURE_PIPELINE_ID + name "webrtc-aec.$SDW_JACK_WEBRTC_CAPTURE_PIPELINE_ID.1" + num_input_pins 2 + num_input_audio_formats 2 + num_output_audio_formats 1 + + Object.Base.input_audio_format [ + { + input_pin_index 0 + in_rate 48000 + in_bit_depth 32 + in_valid_bit_depth 32 + ibs "$[(($in_channels * ($[($in_rate + 999)] / 1000)) * ($in_bit_depth / 8)) * $WEBRTC_AEC_PERIOD_MS]" + } + { + input_pin_index 1 + in_rate 48000 + in_bit_depth 32 + in_valid_bit_depth 32 + ibs "$[(($in_channels * ($[($in_rate + 999)] / 1000)) * ($in_bit_depth / 8)) * $WEBRTC_AEC_PERIOD_MS]" + } + ] + + Object.Base.output_audio_format [ + { + out_rate 48000 + out_bit_depth 32 + out_valid_bit_depth 32 + obs "$[(($out_channels * ($[($out_rate + 999)] / 1000)) * ($out_bit_depth / 8)) * $WEBRTC_AEC_PERIOD_MS]" + } + ] + + Object.Base.input_pin_binding.1 { + input_pin_binding_name "module-copier.$SDW_JACK_MODULE_COPIER_ID.0" + } + Object.Base.input_pin_binding.2 { + input_pin_binding_name $SDW_JACK_REF_COPIER + } + + Object.Control { + mixer."1" { + name 'Jack In WebRTC AEC Switch' + } + mixer."2" { + name 'Jack In WebRTC AEC Suppression Switch' + } + } + } + ] + + Object.Base.route [ + { + source "module-copier.$SDW_JACK_MODULE_COPIER_ID.0" + sink "webrtc-aec.$SDW_JACK_WEBRTC_CAPTURE_PIPELINE_ID.1" + } + { + source $SDW_JACK_REF_COPIER + sink "webrtc-aec.$SDW_JACK_WEBRTC_CAPTURE_PIPELINE_ID.1" + } + { + source "webrtc-aec.$SDW_JACK_WEBRTC_CAPTURE_PIPELINE_ID.1" + sink "host-copier.$SDW_JACK_WEBRTC_CAPTURE_PCM_ID.capture" + } + ] + + Object.PCM.pcm [ + { + name "$SDW_JACK_WEBRTC_CAPTURE_PCM_NAME" + id $SDW_JACK_WEBRTC_CAPTURE_PCM_ID + direction "capture" + Object.Base.fe_dai.1 { + name "$SDW_JACK_WEBRTC_CAPTURE_PCM_NAME" + } + + Object.PCM.pcm_caps.1 { + name "$SDW_JACK_WEBRTC_CAPTURE_STREAM_NAME" + formats 'S32_LE' + rates '48000' + channels_min 2 + channels_max 2 + } + } + ] + } +}