注意:本文抽取的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.h
common_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.c
third_party/
fft4g/
fft4g.c
fft4g.h
spl_sqrt_floor/
spl_sqrt_floor.c
spl_sqrt_floor.h
system_wrappers/include/cpu_features_wrapper.h
3.修改源码文件
主要修改check.h与check.cc文件,因为这两个文件引用了absl库
主要修改是移除log打印,检查数据则修改使用基础库文件assert.h代替,效果无差别
下面贴出主要代码,详情查看GitHub中源码(因为全贴出来代码太长了)
check.h修改如下
//zhonghua code------------------------------------
#include <assert.h>
#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 <jni.h>
#include <string>
#include <cstdlib>
#include "modules/audio_processing/legacy_ns/noise_suppression.h"
#include "modules/audio_processing/legacy_ns/noise_suppression_x.h"
#if defined(__cplusplus)
extern "C" {
#endif
JNIEXPORT 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_ANDROID和WEBRTC_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 : $nsxId nsxInit: $nsxInit nexSetPolicy: $nexSetPolicy")
···
val inputData = 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
抽取AGC(增益)模块文章链接:https://www.jianshu.com/p/e105a373d6d9