单独抽取webRtc的NS&NSX(降噪)模块

注意:本文抽取的NS与NSX源码基于webRtc源码2020年1月7日的提交
本文只提取源码中 legacy 版本的NS与NSX模块
本文代码最终使用在Android设备上(其它设备根据情况自行调整)
抽取AGC(增益)模块文章链接:https://www.jianshu.com/p/e105a373d6d9
本文简述步骤:下载源码 → 抽取文件 → 修改源码文件 → 编写jni文件 → 编写CMakeLists.txt文件 → 正常使用→ 特别注意→ GitHub链接
(提示: 非代码编写顺序 )
1.webRtc源码
使用Git工具Clone源码地址:https://webrtc.googlesource.com/src (需要翻墙)
2.NS&NSX模块抽取
主函数入口为noise_suppression.h与noise_suppression_x.h
以下为主要源码文件:
modules/audio_processing/legacy_ns/ defines.h noise_suppression.c noise_suppression.h noise_suppression_x.c noise_suppression_x.h ns_core.c ns_core.h nsx_core.c nsx_core.h nsx_core_c.c nsx_defines.h windows_private.h

以下为依赖的源码文件:
rtc_base/ numerics/ safe_conversions.h safe_conversions_impl.h system/ arch.h checks.cc checks.h compile_assert_c.h sanitizer.hcommon_audio/signal_processing/ include/real_fft.h include/signal_processing_library.h include/spl_inl.h include/spl_inl_armv7.h include/spl_inl_mips.h complex_bit_reverse.c complex_fft.c complex_fft_tables.h copy_set_operations.c cross_correlation.c division_operations.c dot_product_with_scale.cc dot_product_with_scale.h downsample_fast.c energy.c get_scaling_square.c min_max_operations.c real_fft.c spl_init.c vector_scaling_operations.cthird_party/ fft4g/ fft4g.c fft4g.h spl_sqrt_floor/ spl_sqrt_floor.c spl_sqrt_floor.hsystem_wrappers/include/cpu_features_wrapper.h

3.修改源码文件
主要修改check.h与check.cc文件,因为这两个文件引用了absl库
主要修改是移除log打印,检查数据则修改使用基础库文件assert.h代替,效果无差别
下面贴出主要代码,详情查看GitHub中源码(因为全贴出来代码太长了)
check.h修改如下
//zhonghua code------------------------------------ #include #define RTC_CHECK(condition) assert(condition) #define RTC_CHECK_EQ(val1, val2) assert(val1 == val2) #define RTC_CHECK_NE(val1, val2) assert(val1 != val2) #define RTC_CHECK_LE(val1, val2) assert(val1 <= val2) #define RTC_CHECK_LT(val1, val2) assert(val1 < val2) #define RTC_CHECK_GE(val1, val2) assert(val1 >= val2) #define RTC_CHECK_GT(val1, val2) assert(val1 > val2)#define RTC_DCHECK(condition) RTC_CHECK(condition) #define RTC_DCHECK_EQ(v1, v2) RTC_CHECK_EQ(v1, v2) #define RTC_DCHECK_NE(v1, v2) RTC_CHECK_NE(v1, v2) #define RTC_DCHECK_LE(v1, v2) RTC_CHECK_LE(v1, v2) #define RTC_DCHECK_LT(v1, v2) RTC_CHECK_LT(v1, v2) #define RTC_DCHECK_GE(v1, v2) RTC_CHECK_GE(v1, v2) #define RTC_DCHECK_GT(v1, v2) RTC_CHECK_GT(v1, v2)#define FATAL()//zhonghua code------------------------------------ //为了缩减lib库大小,这样处理后可缩减200K大小#ifdef USE_WEBRTC_CODE#ifdef __cplusplus // C++ version. ··· ···[此处省略N行] ··· #endif// __cplusplus #endif

check.cc文件主要是去掉执行代码,理论上是可以去掉这个文件
//zhonghua code--------------------------------------- //为了缩减lib库大小,这样处理后可缩减200K大小 #ifdef USE_WEBRTC_CODE namespace { #if defined(__GNUC__) __attribute__((__format__(__printf__, 2, 3))) #endif void AppendFormat(std::string* s, const char* fmt, ...) { ··· ···[此处省略N行] ··· #endif //zhonghua code---------------------------------------

4.编写jni文件
这里的JNI文件指的是我们调用webRtc模块的C++文件
我一般使用的是NSX模块,但是接口代码是都实现了的,大家仔细斟酌使用哈
#include #include #include #include "modules/audio_processing/legacy_ns/noise_suppression.h" #include "modules/audio_processing/legacy_ns/noise_suppression_x.h"#if defined(__cplusplus) extern "C" { #endifJNIEXPORT jlong JNICALL Java_vip_inode_demo_webrtc_NoiseSuppressorUtils_nsCreate(JNIEnv *env, jobject obj) { return (long) WebRtcNs_Create(); }JNIEXPORT jint JNICALL Java_vip_inode_demo_webrtc_NoiseSuppressorUtils_nsInit(JNIEnv *env, jobject obj, jlong nsHandler, jint frequency) { NsHandle *handler = (NsHandle *) nsHandler; if (handler == nullptr) { return -3; } return WebRtcNs_Init(handler, frequency); }JNIEXPORT jint JNICALL Java_vip_inode_demo_webrtc_NoiseSuppressorUtils_nsSetPolicy(JNIEnv *env, jobject obj, jlong nsHandler, jint mode) { NsHandle *handle = (NsHandle *) nsHandler; if (handle == nullptr) { return -3; } return WebRtcNs_set_policy(handle, mode); }JNIEXPORT jint JNICALL Java_vip_inode_demo_webrtc_NoiseSuppressorUtils_nsProcess(JNIEnv *env, jobject obj, jlong nsHandler, jfloatArray spframe, jint num_bands, jfloatArray outframe) { NsHandle *handle = (NsHandle *) nsHandler; if (handle == nullptr) { return -3; } jfloat *cspframe = env->GetFloatArrayElements(spframe, nullptr); jfloat *coutframe = env->GetFloatArrayElements(outframe, nullptr); WebRtcNs_Process(handle, &cspframe, num_bands, &coutframe); env->ReleaseFloatArrayElements(spframe, cspframe, 0); env->ReleaseFloatArrayElements(outframe, coutframe, 0); return 0; }JNIEXPORT jint JNICALL Java_vip_inode_demo_webrtc_NoiseSuppressorUtils_nsFree(JNIEnv *env, jobject obj, jlong nsHandler) { NsHandle *handle = (NsHandle *) nsHandler; if (handle == nullptr) { return -3; } WebRtcNs_Free(handle); return 0; }JNIEXPORT jlong JNICALL Java_vip_inode_demo_webrtc_NoiseSuppressorUtils_nsxCreate(JNIEnv *env, jobject obj) { return (long) WebRtcNsx_Create(); }JNIEXPORT jint JNICALL Java_vip_inode_demo_webrtc_NoiseSuppressorUtils_nsxInit(JNIEnv *env, jobject obj, jlong nsHandler, jint frequency ) { NsxHandle *handler = (NsxHandle *) nsHandler; if (handler == nullptr) { return -3; } return WebRtcNsx_Init(handler, frequency); }JNIEXPORT jint JNICALL Java_vip_inode_demo_webrtc_NoiseSuppressorUtils_nsxSetPolicy(JNIEnv *env, jobject obj, jlong nsHandler, jint mode ) { NsxHandle *handle = (NsxHandle *) nsHandler; if (handle == nullptr) { return -3; } return WebRtcNsx_set_policy(handle, mode); }JNIEXPORT jint JNICALL Java_vip_inode_demo_webrtc_NoiseSuppressorUtils_nsxProcess(JNIEnv *env, jobject obj, jlong nsHandler, jshortArray speechFrame, jint num_bands, jshortArray outframe) { NsxHandle *handle = (NsxHandle *) nsHandler; if (handle == nullptr) { return -3; } jshort *cspeechFrame = env->GetShortArrayElements(speechFrame, nullptr); jshort *coutframe = env->GetShortArrayElements(outframe, nullptr); WebRtcNsx_Process(handle, &cspeechFrame, num_bands, &coutframe); env->ReleaseShortArrayElements(speechFrame, cspeechFrame, 0); env->ReleaseShortArrayElements(outframe, coutframe, 0); return 0; }JNIEXPORT jint JNICALL Java_vip_inode_demo_webrtc_NoiseSuppressorUtils_nsxFree(JNIEnv *env, jobject obj, jlong nsHandler) { NsxHandle *handle = (NsxHandle *) nsHandler; if (handle == nullptr) { return -3; } WebRtcNsx_Free(handle); return 0; }#if defined(__cplusplus) } #endif

5.编写CMakeLists.txt文件
Android中使用需要定义宏WEBRTC_ANDROIDWEBRTC_POSIX
CMakeLists.txt内容如下:
cmake_minimum_required(VERSION 3.4.1) file(GLOB SRC_FILES */*.cc */*/*.c */*/*.cc */*/*/*.c ns-lib.cpp ) add_library(legacy_ns-lib SHARED ${SRC_FILES}) include_directories(./) add_definitions( -DWEBRTC_ANDROID -DWEBRTC_POSIX ) find_library(log-lib log)target_link_libraries(legacy_ns-lib ${log-lib})

6.正常使用
在Java中使用需要先初始化
主要使用代码:
//初始化 val nsUtils = NoiseSuppressorUtils() val nsxId = nsUtils.nsxCreate() val nsxInit = nsUtils.nsxInit(nsxId, 16000) val nexSetPolicy = nsUtils.nsxSetPolicy(nsxId, 2) Log.i(tag, "nsxId : $nsxIdnsxInit: $nsxInit nexSetPolicy: $nexSetPolicy") ··· val inputData = https://www.it610.com/article/ShortArray(160) val outNsData = ShortArray(160) nsUtils.nsxProcess(nsxId, inputData, 1, outNsData) ··· nsUtils.nsxFree(nsxId)

特别注意:每次处理的音频数据需始终为 10ms (否则会失败) 以下为官方注解:
/* * This functions does noise suppression for the inserted speech frame. The * input and output signals should always be 10ms (80 or 160 samples). * * Input *- nsxInst: NSx instance. Needs to be initiated before call. *- speechFrame: Pointer to speech frame buffer for each band *- num_bands: Number of bands * * Output: *- nsxInst: Updated NSx instance *- outFrame: Pointer to output frame for each band */ void WebRtcNsx_Process(NsxHandle *nsxInst, const int16_t *const *speechFrame, int num_bands, int16_t *const *outFrame);

GitHub链接:https://github.com/inodevip/WebRtcNsAgcModel
【单独抽取webRtc的NS&NSX(降噪)模块】抽取AGC(增益)模块文章链接:https://www.jianshu.com/p/e105a373d6d9

    推荐阅读