@Cmake 编译Speex 使用 回声消除
Cmake 编译Speex 使用 回声消除
1. 编译Speex
2.使用回声消除
编译
1.下载Speex的文件,请下载speex-1.2rc1, 因为这个是speex还未删除回声消除前的版本,网址请自行百度
2.下载后的文件结构
这里将include 和 libSpeek 拷贝到 项目中的cpp包下 ,目录结构如下:
然后编写cmake 文件内容如下:
documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.10.2)
# Declares and names the project.
project("speexace3")
message(STATUS "Source Directory: ${CMAKE_CURRENT_SOURCE_DIR}")
message(STATUS "Android ABI: ${ANDROID_ABI}")
message(STATUS "Android API LEVEL: ${ANDROID_NATIVE_API_LEVEL}")
add_definitions("-DFIXED_POINT") // **这里是需要特别注意的地方**
add_definitions("-DUSE_KISS_FFT")
add_definitions("-DEXPORT=")
add_definitions("-UHAVE_CONFIG_H")
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
include_directories(include)
file(GLOB_RECURSE ALL_PROJ_SRC "libspeex/*c" "speex_process.c" "fflog.h")
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
add_library( # Sets the name of the library.
audio_speex
SHARED
${ALL_PROJ_SRC})
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log)
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
audio_speex
# Links the target library to the log library
# included in the NDK.
${log-lib})
这里有一点需要特殊说明就是 add_definitions 这几个值。因为对比 android.mk编译后你会发现再android.mk中有一段设置locl_tyep地方,它在cmake 文件中对应的就是 用 add_definitions 设置,如果没设置的话会在代码中报找不到方法实现的问题
即编译时走进这里,是个空实现导致报错,编译不通过,而上面说的locall_type设置对应的地方就是这个对方法实现的选择。
然后进行编译的话就会出现一个数据类型不对的问题:代码在这里
到了这一步,需要将speex_config_types.h.in 复制 改名为 speex_config_types.h 再将@SIZE16@ 改为 short @SIZE32@ 改为 int 即可,最后你遇到一个问题就是 一个无效的类型的报错:
You now need to define either FIXED_POINT or FLOATING_POINT 直接将报错的代码注释即可
到这里机会就已经编译完成了,如果还有为提的话可以参考这篇文章
[编译报错解决 (https://blog.csdn.net/I_do_can/article/details/55193136)
哦吼还少了一下东西:就是一些测试代码需要注释到,不然编译也报错:
标红的这个文件的main 方法如果不需要可以注释掉
到这里我遇到的坑就这些了了,尤其需要提示还是 local_type 在cmake中对应的方法add_definitions
还有就 高版本的ndk对speek中的一些方法的修饰符不支持,需要 替换为 EXPORT -> JNIEXPORT
回声消噪代码如下
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <jni.h>
#include <string.h>
#include "speex/speex_preprocess.h"
#include <stdio.h>
#include "fflog.h"
#include <android/log.h>
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, "keymatch", __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, "keymatch", __VA_ARGS__)
SpeexPreprocessState *st;
JNIEXPORT void JNICALL
Java_net_majorkernelpanic_streaming_speex_SpeexHelper_CancelNoiseInit(JNIEnv *env, jobject thiz,
jint frame_size,
jint sample_rate) {
int i;
float f;
st = speex_preprocess_state_init(frame_size / 2, sample_rate);
i = 1;
speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DENOISE, &i);
i = 1;
speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC, &i);
i = sample_rate;
speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC_LEVEL, &i);
i = 1;
speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DEREVERB, &i);
f = .0;
speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DEREVERB_DECAY, &f);
f = .0;
speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &f);
LOGI("speex init");
}
JNIEXPORT void JNICALL
Java_net_majorkernelpanic_streaming_speex_SpeexHelper_CancelNoisePreprocess(JNIEnv *env,
jobject thiz,
jbyteArray buffer) {
char *inbuffer = (*env)->GetByteArrayElements(env, buffer, 0);
short *in = inbuffer;
LOGI("speex change 000");
int vad = speex_preprocess_run(st, in);
(*env)->ReleaseByteArrayElements(env, buffer, (jbyte *) inbuffer, 0);
LOGI("speex change ok");
}
JNIEXPORT void JNICALL
Java_net_majorkernelpanic_streaming_speex_SpeexHelper_CancelNoiseDestroy(JNIEnv *env,
jobject thiz) {
if (st != NULL) {
speex_preprocess_state_destroy(st);
st = NULL;
}
LOGI("speex destory");
}
sample_rate 不在 speek支持的范围内是,就会崩溃如 44100 。支持的范围为 8k 16k 32k 44k 48k ,
好了就这样把
感谢如下文章
Android 上对Speek的是实现