音频的录制,播放传输,势必离不开音频的降噪和回音消除,特别是在语音的双向对讲过程中,回音消除是必须跨越的门槛,总结在jni代码中,代码实现如下,具体调试流程,参数设置则只能说多次测试的结果。配合speex源码编译成so后即可使用。
#include <stdio.h> #include <jni.h> #include <string.h> #include "speex/speex_preprocess.h" #include "speex/speex_echo.h" #include <stdio.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; int nInitSuccessFlag = 0; SpeexEchoState* m_pState; SpeexPreprocessState* m_pPreprocessorState; int m_nFrameSize; int m_nFilterLen; int m_nSampleRate; int iArg; jint Java_com_stream_Speex_CancelNoiseInit(JNIEnv* env,jobject this,jint frame_size, jint sample_rate) { int i; int count=0; float f; st = speex_preprocess_state_init(frame_size/2, sample_rate); i=1; speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DENOISE, &i);//降噪 i = -25;//负的32位整数 speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_NOISE_SUPPRESS,&i); //设置噪声的dB i=1; speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC, &i);//增益 i=24000; speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC_LEVEL, &i); i=0; 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"); return 1; } jint Java_com_stream_Speex_CancelNoisePreprocess(JNIEnv* env,jobject this,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"); return vad; } jint Java_com_stream_Speex_CancelNoiseDestroy(JNIEnv* env,jobject this) { if(st != NULL){ speex_preprocess_state_destroy(st); st = NULL; } LOGI("speex destory"); return 1; } //回声消除部分代码 //初始化回音消除参数 /* * jint frame_size 帧长 一般都是 80,160,320 * jint filter_length 尾长 一般都是 80*25 ,160*25 ,320*25 * jint sampling_rate 采样频率 一般都是 8000,16000,32000 * 比如初始化 * InitAudioAEC(80, 80*25,8000) //8K,10毫秒采样一次 * InitAudioAEC(160,160*25,16000) //16K,10毫秒采样一次 * InitAudioAEC(320,320*25,32000) //32K,10毫秒采样一次 */ jint Java_com_audioaec_talkdemo_AudioAEC_InitAudioAEC( JNIEnv* env,jobject thiz,jint frame_size,jint filter_length,jint sampling_rate) { if(nInitSuccessFlag == 1) return 1 ; if (frame_size<=0 || filter_length<=0 || sampling_rate<=0) { m_nFrameSize =160; m_nFilterLen = 160*8; m_nSampleRate = 8000; } else { m_nFrameSize =frame_size; m_nFilterLen = filter_length; m_nSampleRate = sampling_rate; } m_pState = speex_echo_state_init(m_nFrameSize, m_nFilterLen); if(m_pState == NULL) return -1 ; m_pPreprocessorState = speex_preprocess_state_init(m_nFrameSize, m_nSampleRate); if(m_pPreprocessorState == NULL) return -2 ; iArg = m_nSampleRate; speex_echo_ctl(m_pState, SPEEX_ECHO_SET_SAMPLING_RATE, &iArg); speex_preprocess_ctl(m_pPreprocessorState, SPEEX_PREPROCESS_SET_ECHO_STATE, m_pState); nInitSuccessFlag = 1 ; return 1 ; } /* 参数: jbyteArray recordArray 录音数据 jbyteArray playArray 放音数据 jbyteArray szOutArray */ jint Java_com_audioaec_talkdemo_AudioAEC_AudioAECProc(JNIEnv* env,jobject thiz,jbyteArray recordArray,jbyteArray playArray,jbyteArray szOutArray) { if(nInitSuccessFlag == 0) return 0 ; jbyte* recordBuffer = (jbyte *)(*env)->GetByteArrayElements(env,recordArray, 0); jbyte* playBuffer = (jbyte *)(*env)->GetByteArrayElements(env,playArray, 0); jbyte* szOutBuffer = (jbyte *)(*env)->GetByteArrayElements(env,szOutArray, 0); speex_echo_cancellation(m_pState,(spx_int16_t *)recordBuffer, (spx_int16_t *)playBuffer,(spx_int16_t *)szOutBuffer); int flag=speex_preprocess_run(m_pPreprocessorState,(spx_int16_t *)szOutBuffer); (*env)->ReleaseByteArrayElements(env,recordArray,recordBuffer,0) ; (*env)->ReleaseByteArrayElements(env,playArray,playBuffer,0) ; (*env)->ReleaseByteArrayElements(env,szOutArray,szOutBuffer,0) ; return 1 ; } //退出 jint Java_com_sosea_xmeeting_SpeexAEC_ExitSpeexDsp( JNIEnv* env,jobject thiz) { if(nInitSuccessFlag == 0) return 0 ; if (m_pState != NULL) { speex_echo_state_destroy(m_pState); m_pState = NULL; } if (m_pPreprocessorState != NULL) { speex_preprocess_state_destroy(m_pPreprocessorState); m_pPreprocessorState = NULL; } nInitSuccessFlag = 0 ; return 1 ; }