一 Android操作系统由来

Android是一种基于Linux的自由及开放源代码的操作系统,主要使用于移动设备,如智能手机和平
板电脑,由Google公司和开放手机联盟领导及开发。尚未有统一中文名称,中国大陆地区较多人使用“安
卓”或“安致”。Android操作系统最初由Andy Rubin开发,主要支持手机。2005年8月由Google收购注资。
2007年11月,Google与84家硬件制造商、软件开发商及电信营运商组建开放手机联盟共同研发改良Androi
d系统。随后Google以Apache开源许可证的授权方式,发布了Android的源代码。第一部Android智能手机发
布于2008年10月。Android逐渐扩展到平板电脑及其他领域上,如电视、数码相机、游戏机等。2011年第
一季度,Android在全球的市场份额首次超过塞班系统,跃居全球第一。 2012年11月数据显示,Android
占据全球智能手机操作系统市场76%的份额,中国市场占有率为90%。2013年09月24日谷歌开发的操作系
统Android在迎来了5岁生日,全世界采用这款系统的设备数量已经达到10亿台。

二 Android平台语音通讯

正因为Android平台优越的性能、美观的界面,越来越多人使用Android手机,从而在Android平台上的
语音通话越来越多。语音通话大概流程如下:我认为一个语音通话系统至少有四个模块。分别是PCM(Pulse
Code Modulation,即 脉码编码调制)语音采集,编解码,网络传输以及语音播放。如果算上UI交互的话,
就是五个模块了。整体流程大概是:A打电话给B,A声音通过MIC被采集成PCM原始数据,然后经过编码压缩,
再通过网络(建立P2P连接)将编码后的数据传输出去;B端通过网络收到数据后进行解码处理,然后调用播
放模块,进行播放数据。如果想通话音质提供些,可以在编码前加入 噪音消除,回音消除。

三 录音、放音、编码、解码、网络发送、接收

1、语音采集模块
 Android平台上的实现是通过AudioRecord接口来实现PCM数据的采集,这一步比较容易的。但需要注意的是
AudioRecord接口的使用方法。构造AudioRecord 实例需要参数 public AudioRecord (int audioSource, int
sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes)
比如录音代码如下:

    static final int frequency = 8000;   static final int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;     static final int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;    int recBufSize,playBufSize; AudioRecord audioRecord;    recBufSize =  AudioRecord.getMinBufferSize(frequency,     channelConfiguration, audioEncoding);      audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, frequency,     AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, recBufSize);

2、语音播放

当语音数据采集好了之后,接着可以实现语音播放模块。Android上实现PCM数据的播放也很简单,直接
使用AudioTrack这个接口就行了。同样需要注意该接口
的使用方法。AudioTrack的构造方式跟AudioRecord是对应的

    static final int frequency = 8000;   static final int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;     static final int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;    int recBufSize,playBufSize; AudioTrack  audioPlayer ;playBufSize =  AudioTrack.getMinBufferSize(frequency,     channelConfiguration, audioEncoding);        audioPlayer = new AudioTrack(AudioManager.STREAM_MUSIC,frequency,AudioFormat.CHANNEL_OUT_MONO,AudioFormat.ENCODING_PCM_16BIT,playBufSize,AudioTrack.MODE_STREAM) ;

3、语音编解码

采集到的PCM数据是原始的语音数据,如果我们直接进行网络传输,那是不可取的。因此,要进行打包编码。
编码我们需要第三方的库,目前我使用的库是speex(http://www.speex.org)。我看到许多SIP语音电话都
使用到了这个库进行编解码。当然也有对这个库评 价不好的说法,但我觉得作为学习还是可取的,因为speex
使用起来很方便。把speex源码下载下来,写好JNI接口,在NDK环境编译一下,即可在java环境调用。
例如下面一个接口函数

jint
Java_com_audiocodec_talkdemo_AudioCodec_InitAudioEncodec( JNIEnv* env,jobject thiz,jint sampling_rate,jint audioLevel)
{
if(nInitAudioCodecEncodeFlag == 1 || audioLevel < 3 || audioLevel > 8 )
return 0 ;int  frame_size ;if(sampling_rate == 8000)
{
audio_Leval = 0 ;
capAudioLength = 160     ;
capAudioBitrate = 8000  ;
}else if(sampling_rate == 16000)
{audio_Leval = 1 ;  capAudioLength = 320     ;  capAudioBitrate = 16000  ;
}else if(sampling_rate == 32000)
{audio_Leval = 2 ; capAudioLength = 640     ;  capAudioBitrate = 32000  ;
}elsereturn 0 ; tmp_Level = audioLevel ; //设置等级 15kbit/s
speex_mode = speex_lib_get_mode(audio_Leval) ; enc_state = speex_encoder_init(speex_mode);
speex_encoder_ctl(enc_state,SPEEX_SET_QUALITY,&tmp_Level);int tmp = 30 ;//丢包补偿
int nRet = speex_encoder_ctl(enc_state, SPEEX_SET_PLC_TUNING, &tmp);
nRet = speex_encoder_ctl(enc_state, SPEEX_GET_PLC_TUNING, &tmp);speex_bits_init(&bits); nInitAudioCodecEncodeFlag = 1 ;return 1 ;
}//编码音频数据
/*
参数jbyteArray  szAudio   等待编码的音频数据jbyteArray  szOut     编码后的音频数据
返回值成功返回 编码后长度失败返回 0
*/jint Java_com_audiocodec_talkdemo_AudioCodec_AudioEncode( JNIEnv* env,jobject thiz,jbyteArray szAudio,jbyteArray szOut)
{
if(nInitAudioCodecEncodeFlag == 0)
return 0 ;jbyte* szAudioBuffer =  (jbyte *)(*env)->GetByteArrayElements(env,szAudio, 0);
jbyte* szOutBuffer   =  (jbyte *)(*env)->GetByteArrayElements(env,szOut, 0);//清空bits ,以便编码
speex_bits_reset(&bits);//进行编码
int nRet = speex_encode_int(enc_state,(spx_int16_t*)szAudioBuffer, &bits);//把编码后的bits 结构,拷贝到cbits_enc的数据可以从网络发送出去,长度为nByte_enc
int nByte_enc = speex_bits_write(&bits, szOutBuffer, 200);(*env)->ReleaseByteArrayElements(env,szAudio,szAudioBuffer,0) ;
(*env)->ReleaseByteArrayElements(env,szOut,szOutBuffer,0) ;return nByte_enc ;
}                                                 /*
函数功能 初始化编码器
参数无参数
返回值成功返回 1失败返回 0
*/
jint
Java_com_audiocodec_talkdemo_AudioCodec_ExitAudioEncodec( JNIEnv* env,jobject thiz)
{
if(nInitAudioCodecEncodeFlag == 1)
{
nInitAudioCodecEncodeFlag = 0 ;//销毁资源
speex_bits_destroy(&bits);
speex_encoder_destroy(enc_state);
enc_state = NULL ;
}else
return 0 ;
}

4 网络发送、接收

   //定义
DatagramSocket udpSocket  ;  //生成try {
udpSocket = new  DatagramSocket(6789);} catch (SocketException e1) {e1.printStackTrace();}//发送try {
udpSocket.send(sendPacket) ;} catch (IOException e) {
e.printStackTrace();}//接收udpSocket.receive(udpPackage); //关闭udpSocket.close() ;

四、 回音消除

    从Speex 的介绍可以看出它提供了噪音消除,回音消除,测试比较过噪音消除这功能效果是非常棒的,回音消除这功能也很不错这一功能,现在开源的,比较完善的回音消除模块就是Speex了,有许多中小公司也拿它作为回音消除功能 。经过测试,Speex的消除效果还是不错的。编写个jni文件,NDK 环境编译一下即可得到so 文件,在Android环境中调用即可。
      //初始化回音消除参数/** 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 ;m_nFrameSize  = frame_size;
m_nFilterLen  = filter_length;
m_nSampleRate = sampling_rate; //计算采样时长,即是10毫秒,还是20毫秒,还是30毫秒
nSampleTimeLong = (frame_size / (sampling_rate / 100)) * 10 ;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_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 ;
}

五 、 噪音消除处理

// 初始化 降噪
Java_com_audioaec_talkdemo_AudioAEC_InitAudioDeNose( JNIEnv* env,jobject thiz)
{int denoise_enabled = 1 ;
if(nInitDeNoseFlag == 1)
return 0 ;nInitDeNoseFlag = 1 ;//8K降噪
audioProcNose8K = speex_preprocess_state_init(80 * (nSampleTimeLong / 10),8000);
speex_preprocess_ctl(audioProcNose8K, SPEEX_PREPROCESS_SET_DENOISE, &denoise_enabled);//16K降噪
audioProcNose16K = speex_preprocess_state_init(160 * (nSampleTimeLong / 10),16000);
speex_preprocess_ctl(audioProcNose16K, SPEEX_PREPROCESS_SET_DENOISE, &denoise_enabled);return 1 ;
}//8K降噪
jint Java_com_audioaec_talkdemo_AudioAEC_AudioDeNose8K(JNIEnv* env,jobject thiz,jbyteArray recordArray)
{
if(nInitDeNoseFlag == 0)
return 0 ;jbyte* recordBuffer = (jbyte *)(*env)->GetByteArrayElements(env,recordArray, 0);speex_preprocess(audioProcNose8K,(spx_int16_t*)recordBuffer, NULL);(*env)->ReleaseByteArrayElements(env,recordArray,recordBuffer,0) ;return 1 ;
}//16K降噪
jint Java_com_audioaec_talkdemo_AudioAEC_AudioDeNose16K(JNIEnv* env,jobject thiz,jbyteArray recordArray)
{
if(nInitDeNoseFlag == 0)
return 0 ;jbyte* recordBuffer = (jbyte *)(*env)->GetByteArrayElements(env,recordArray, 0);speex_preprocess(audioProcNose16K,(spx_int16_t*)recordBuffer, NULL);(*env)->ReleaseByteArrayElements(env,recordArray,recordBuffer,0) ;return 1 ;
}// 释放降噪
jint
Java_com_audioaec_talkdemo_AudioAEC_ExitAudioDeNose( JNIEnv* env,jobject thiz)
{
if(nInitDeNoseFlag == 0)
return 0 ;nInitDeNoseFlag = 0 ;speex_preprocess_state_destroy(audioProcNose8K);
speex_preprocess_state_destroy(audioProcNose16K); return 1 ;
}

https://www.jianshu.com/p/e74700dd07cf

Android 平台语音通话及回音消除、噪音消除研究(转)相关推荐

  1. Android 平台语音通话及回音消除、噪音消除研究

    一 Android平台语音通讯 正因为Android平台优越的性能.美观的界面,越来越多人使用Android手机,从而在Android平台上的 语音通话越来越多.语音通话大概流程如下:我认为一个语音通 ...

  2. 【转】Android 平台语音通话及回音消除、噪音消除研究

    本文转自博客:https://www.cnblogs.com/jianglijs/p/8583603.html -------------------------------------------- ...

  3. Android P2P语音通话实现 【转】http://macleo.iteye.com/blog/1707455

    Android P2P语音通话实现(思路探讨) 博客分类: android android备忘录 1.http://www.cnblogs.com/milospooner/archive/2012/0 ...

  4. Android P2P语音通话实现(思路探讨)

    最近在在研究语音通话的实现,现在把我的实现思路记录在这里.不过,由于初次接触语音通话,所以这是一个简单的思路,也是经过google以及baidu之后的一个学习总结. 我认为一个语音通话系统至少有四个模 ...

  5. 基于android平台语音日程软件的设计与实现,基于Android平台语音日程软件的设计与实现...

    摘要: 随着移动互联网的发展,智能手机已成为最重要的终端设备,由此产生了以Android平台为代表的新一代操作系统,基于该平台的分布式应用成为移动通信技术领域的研究热点.由于基于Android手机桌面 ...

  6. Android IMS 语音通话 vs 视频通话 vs 视频彩铃

    背景 以下内容基于Android P code. 主要差异 视频通话比语音通话主要是多了判断是否为视频通话,及视频的显示和传输.如下: video call 视频界面显示控制 界面通过IVideoPr ...

  7. android去掉语音通话功能的方法(只保留上网功能)

    需要在frameworks\base\core\res\res\values\config.xml新增下列2行,即可关闭语音通话功能<!-- This device is not "v ...

  8. Android 加固与监测,基于Android平台的恶意软件检测和软件加固技术研究

    摘要: 随着智能手机技术的发展,人们越来越多地把工作和生活的计算平台从传统的PC平台转移到移动平台.智能手机储存了大量的用户隐私,例如通信记录,位置信息等,因而成为攻击者的攻击目标.作为主流移动平台之 ...

  9. android sip协议栈,基于Android平台及SIP协议的软电话系统的研究

    摘要: 随着互联网通信技术不断发展以及智能手机的日益流行,VoIP(Voice Over InternetProtocol)技术得到了越来越广泛的应用.VoIP技术能结合这两者改变传统长途电话费用高昂 ...

最新文章

  1. Servlet_urlpartten配置
  2. 我犯的错误--关于数据库类型不对
  3. CRM客户主数据UI上有哪些字段可以触发partner determination
  4. 从零开始学电脑_带你从零开始学装机 打造自己的专属电脑之固态和机械硬盘搭配篇...
  5. pdf文档遇到了共享冲突_如何将链接共享为PDF格式的Google文档链接
  6. navicat远程mysql_navicat 远程连接mysql
  7. RCP:如何移除Toolbar中的Quick Access
  8. Cloud一分钟 | 华为云、腾讯云、阿里云中标「央视2018年租赁公有云服务」项目...
  9. SpringMVC 执行流程解析
  10. Freeswitch NAT问题
  11. Flutter Container 容器以及对齐方式 Alignment
  12. 富文本编辑器CKEditor 5开发环境搭建
  13. 筑龙网下载的文件格式是php_为什么使用迅雷下载的文件都是PHP格式的
  14. spring-第三篇之ApplicationContext的事件机制
  15. WIFI密码破解技巧---简单之成功率极高
  16. Python中hashlib.sha1()和hashlib.MD5()哈希算法的区别
  17. Java实现支付功能(支付宝)
  18. 小波神经网络的基本原理,小波神经网络算法原理
  19. fn映射 mac 键盘_Mac 与PC键盘的对比及快捷键(黑苹果)
  20. JavaScript 25 岁了!

热门文章

  1. SpringMVC学习系列(6) 之 数据验证
  2. SkeyeVSS综合安防监控Onvif、RTSP、GB28181视频云无插件直播点播解决方案之系统参数配置日志管理
  3. 文献翻译:SETNDS: A SET-based Non-dominated Sorting Algorithm for Multi-objective Optimization Problems
  4. java工具类怎么写_常用的Java工具类——十六种
  5. 一键重装Win11系统 Win11系统重装教程
  6. 上海计算机一级二级三级考纲,上海高校计算机一级考纲.doc
  7. 平安好医生遭遇困局:六年亏近47亿元 价值百亿品牌或被舍弃
  8. 移动互联网的5大思维和10个法则
  9. creo打不开stp文件_Creo编辑处理STP文件的方法
  10. SUb Main 的用途