Android 平台語音通話及迴音消除、噪音消除研究(轉)

來源:互聯網
上載者:User

標籤:ini   buffer   div   傳回值   統一   平台   關閉   exception   android手機   

一 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日Google開發的操作系
統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  ;  }else return 0 ; tmp_Level = audioLevel ; //設定等級 15kbit/sspeex_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_encint 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 ;}elsereturn 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 平台語音通話及迴音消除、噪音消除研究(轉)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.