论android等平台回音消除解决方案

发布时间:2024-12-06 21:56

使用烹饪社交平台,可以轻松解决烹饪难题,获得解决方案。 #生活乐趣# #日常生活趣事# #烹饪乐趣体验# #烹饪社交平台#

来源 http://www.qttaudio.com/android-aec.html

回声消除介绍

http://www.baike.com/wiki/%E5%9B%9E%E9%9F%B3%E6%B6%88%E9%99%A4%E6%8A%80%E6%9C%AF

在即时通讯应用中,需要进行双方,或是多方的实时语音交流,在要求较高的场合,通常都是采用外置音箱放音,这样必然会产生回音,即一方说话后,通过对方的音箱放音,然后又被对方的Mic采集到回传给自己。如果不对回音进行处理,将会影响通话质量和用户体验,更严重的还会形成震荡,产生啸叫。

​ 回声消除就是在Mic采集到声音之后,将本地音箱播放出来的声音从Mic采集的声音数据中消除掉,使得Mic录制的声音只有本地用户说话的声音。

传统的回声消除都是采用硬件方式,在硬件电路上集成DSP处理芯片,如我们常用的固定电话、手机等都有专门的回音消除处理电路,而采用软件方式实现回声消除一直存在技术难点。

回声消除已经成为即时通讯中提供全双工语音的标准方法。声学回声消除是通过消除或者移除本地话筒中拾取到的远端的音频信号来阻止远端的声音返回去的一种处理方法。这种音频的移除都是通过数字信号处理来完成的。回声消除技术是数字信号处理的典型应用之一。

Android平台回声消除方法 系统API

Android在4.1(API level 16)的时候增加了一个API:AcousticEchoCanceler

下面简单的介绍下AcousticEchoCanceler的使用方法:

private AcousticEchoCanceler canceler;

public boolean isDeviceSupportAEC()

{

return AcousticEchoCanceler.isAvailable();

}

public boolean initAEC(int audioSession)

{

if (canceler != null)

{

return false;

}

canceler = AcousticEchoCanceler.create(audioSession);

canceler.setEnabled(true);

return canceler.getEnabled();

}

public boolean setAECEnabled(boolean enable)

{

if (null == canceler)

{

return false;

}

canceler.setEnabled(enable);

return canceler.getEnabled();

}

public boolean release()

{

if (null == canceler)

{

return false;

}

canceler.setEnabled(false);

canceler.release();

return true;

}

从以上代码可知,AcousticEchoCanceler的初始化需要一个sessionid,这个sessionid由初始化好的AudioRecord对象获得:

sessionid = audioRecord.getAudioSessionId();

初始化AudioTrack时,也需要额外的处理sessionid:

audioTrack = new AudioTrack(AudioManager.STREAM_VOICE_CALL, frequency,

channelOUT, audioEncoding, tmpSize, AudioTrack.MODE_STREAM, sessionid);

为什么AcousticEchoCanceler和AudioTrack初始化都需要AudioRecord对象的sessionid呢?这牵涉到理解回声消除的原理,请见这篇文章。

上述代码是根据官方文档介绍编写的,而根据实际测试,离实际产品应用还有很长的距离。

Speex

Speex提供开源的的回音消除算法,从提供的文档(https://speex.org/docs/manual/speex-manual/node7.html#SECTION00740000000000000000)和测试用例看,效果还是非常棒的。下面简单介绍speex echo cancellation api的使用方法,官方示例文件testecho.c:

#ifdef HAVE_CONFIG_H

#include "config.h"

#endif

#include <stdio.h>

#include <stdlib.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include "speex/speex_echo.h"

#include "speex/speex_preprocess.h"

#define NN 128

#define TAIL 1024

int main(int argc, char **argv)

{

FILE *echo_fd, *ref_fd, *e_fd;

short echo_buf[NN], ref_buf[NN], e_buf[NN];

SpeexEchoState *st;

SpeexPreprocessState *den;

int sampleRate = 8000;

if (argc != 4)

{

fprintf(stderr, "testecho mic_signal.sw speaker_signal.sw output.sw\n");

exit(1);

}

echo_fd = fopen(argv[2], "rb");

ref_fd = fopen(argv[1], "rb");

e_fd = fopen(argv[3], "wb");

st = speex_echo_state_init(NN, TAIL);

den = speex_preprocess_state_init(NN, sampleRate);

speex_echo_ctl(st, SPEEX_ECHO_SET_SAMPLING_RATE, &sampleRate);

speex_preprocess_ctl(den, SPEEX_PREPROCESS_SET_ECHO_STATE, st);

while (!feof(ref_fd) && !feof(echo_fd))

{

fread(ref_buf, sizeof(short), NN, ref_fd);

fread(echo_buf, sizeof(short), NN, echo_fd);

speex_echo_cancellation(st, ref_buf, echo_buf, e_buf);

speex_preprocess_run(den, e_buf);

fwrite(e_buf, sizeof(short), NN, e_fd);

}

speex_echo_state_destroy(st);

speex_preprocess_state_destroy(den);

fclose(e_fd);

fclose(echo_fd);

fclose(ref_fd);

return 0;

}

以上代码是处理文件,而在实际的VOIP通话中,难点在于NN和TAIL的指定,也就是frame_size和tail_length,因为像android\ios、windows或linux等非实时系统,用户调用采集或者播放的接口,到实际硬件真正采集和播放声音,根据各硬件平台以及系统的不一样,这中间是有几十至几百毫秒的延迟,这对于回声处理增加了非常大的难度。

WebRTC

WebRTC,名称源自网页实时通信(Web Real-Time Communication)的缩写,是一个支持网页浏览器进行实时语音对话或视频对话的技术。

WebRTC源代码中设计了两个回声消除模块,AEC(Acoustic Echo Canceller)和AECM(Acoustic Echo Canceller Mobile),AEC是在电脑端使用的回声消除器,而AECM是在移动端使用。由于电脑与移动设备的差别比较明显,在处理速度上,编解码器的性能上和内存方面都有着较大的差异。

在VoIP实时语音通话中,之所以会产生声学回声的原因是,近端通话者的声音被自己的麦克风拾取后通过网络传到远端,远端扬声器播放出来的声音被麦克风拾取后通过网络又重新发回近端。加上网络和数据处理等各种延迟的影响,使得近端通话者能够从扬声器中听到自己的刚才所说的话,就产生了回声。

下面主要来简单介绍一下AECM模块 中echo_control_mobile.c的两个函数:

WebRtcAecm_BufferFarend(void *aecmInst, const int16_t *farend, int16_t nrOfSamples)

WebRtcAecm_Process(void *aecmInst, const int16_t *nearendNoisy, const int16_t *nearendClean,

int16_t *out, int16_t nrOfSamples, int16_t msInSndCardBuf)


QttAudio Android、iOS、Windows、(嵌入式)Linux系统的回音消除问题:通话再无回声啸叫,高清音质
多语音流混音问题:多人会议模式很简单
内置多种语音编解码格式:摆脱烦人的编解码开发工作量
跨平台,接口一致性,集成简单:合四为一,加速应用开发,助您抢占先机
与服务器无关:摆脱云服务绑架,私有云部署,更安全,更划算

    2. 一个代码小例子

Java(Android )

public class MainActivity extends AppCompatActivity {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

try {

QttAudioEngine.me().init(this, "your appkey");

QttAudioStream stream = QttAudioEngine.me().createStream();

QttAudioEngine.me().setMicCodecParams("pcm", 1, 48000, 0);

QttAudioEngine.me().setMicCaptureCb(new QttCaptureCallbak() {

@Override

public void onCapture(byte[] buf, int bufLength, Object userdata) {

QttAudioStream tmpStream = (QttAudioStream) userdata;

tmpStream.writePayload(buf, 0, bufLength);

}

}, stream);

stream.start();

} catch (QttException e) {

e.printStackTrace();

}

}

}

C (iOS、Linux、Windows)

static void onCapture(char *buf, size_t len, void *userdata) {

QttAudioStream *stream = (QttAudioStream *)userdata;

qtt_stream_write_payload(stream, buf, len);

}

int main() {

QttAudioEngine *engine = qtt_engine_init("your appkey");

if (engine == NULL) {

fprintf(stderr, "qtt_engine_init fail\n");

return -1;

}

QttAudioStream *stream = qtt_engine_create_stream(engine);

if (stream == NULL) {

fprintf(stderr, "qtt_engine_create_stream fail\n");

return -1;

}

qtt_engine_set_mic_codec_params(engine, "pcm", 1, 48000, 0);

qtt_engine_set_mic_capture_callback(engine, onCapture, stream);

qtt_stream_start(stream);

char c = getchar();

qtt_stream_stop(stream);

qtt_stream_free(stream);

qtt_engine_free(engine);

return 0;

}

网址:论android等平台回音消除解决方案 https://www.yuejiaxmz.com/news/view/398704

相关内容

解决Android开发难题:50个黑客技巧解析
物联网iot平台解决方案
基于Android平台Camera的设计与实现
iot平台技术方案
云之家一站式工作平台主解决方案V1.2= (2)(175页)
Android存储空间不足?试试这8个快速解决方案!
探索智能语音助手:Android
基于Android平台下的健康管理APP/基于android的健康管理系统
智能家庭安全防护解决方案
基于Spring Boot和Android的旧物交易平台与实现(源码+LW+调试+讲解)

随便看看