1. 程式人生 > >Android P2P語音通話實現(思路探討)

Android P2P語音通話實現(思路探討)

最近在在研究語音通話的實現,現在把我的實現思路記錄在這裡。不過,由於初次接觸語音通話,所以這是一個簡單的思路,也是經過google以及baidu之後的一個學習總結。

  我認為一個語音通話系統至少有四個模組。分別是PCM(Pulse Code Modulation,即 脈碼編碼調製)語音採集,編解碼,網路傳輸以及語音播放。如果算上UI互動的話,就是五個模組了。

  整體流程大概是:A打電話給B,A聲音通過MIC被採集成PCM原始資料,然後經過編碼壓縮,再通過網路(建立P2P連線)將編碼後的資料傳輸出去;B端通過網路收到資料後進行解碼處理,然後呼叫播放模組,進行播放資料。

  一、語音採集模組

  Android平臺上的實現是通過AudioRecord介面來實現PCM資料的採集,這一步比較容易的。但需要注意的是AudioRecord介面的使用方法。構造AudioRecord 例項需要引數

public AudioRecord (int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes)

audioSource the recording source. See MediaRecorder.AudioSource for recording source definitions.
sampleRateInHz the sample rate expressed in Hertz. 44100Hz is currently the only rate that is guaranteed to work on all devices, but other rates such as 22050, 16000, and 11025 may work on some devices.
channelConfig describes the configuration of the audio channels. See CHANNEL_IN_MONO and CHANNEL_IN_STEREOCHANNEL_IN_MONOis guaranteed to work on all devices.
audioFormat
bufferSizeInBytes the total size (in bytes) of the buffer where audio data is written to during the recording. New audio data can be read from this buffer in smaller chunks than this size. See 
getMinBufferSize(int, int, int)
 to determine the minimum required buffer size for the successful creation of an AudioRecord instance. Using values smaller than getMinBufferSize() will result in an initialization failure.
  1. audioSource:這裡可以是MediaRecorder.AudioSource.MIC
  2. sampleRateInHz:錄製頻率,可以為8000hz或11025hz等,不同的硬體裝置這個值不同
  3. audioFormat:錄製編碼格式,可以為AudioFormat.ENCODING_16BIT和8BIT,其中16BIT的模擬性比8BIT好,但是需要消耗更多的電量和儲存空間
  4. bufferSizeInBytes:錄製緩衝大小:可以通過getMinBufferSize()方法來獲取

  二、語音播放

  當語音資料採集好了之後,接著可以實現語音播放模組。Android上實現PCM資料的播放也很簡單,直接使用AudioTrack這個介面就行了。同樣需要注意該介面的使用方法。

  AudioTrack的構造方式跟AudioRecord是對應的

public AudioTrack (int streamType, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes, int mode)

sampleRateInHz the sample rate expressed in Hertz.
channelConfig
audioFormat
bufferSizeInBytes the total size (in bytes) of the buffer where audio data is read from for playback. If using the AudioTrack in streaming mode, you can write data into this buffer in smaller chunks than this size. If using the AudioTrack in static mode, this is the maximum size of the sound that will be played for this instance. See getMinBufferSize(int, int, int) to determine the minimum required buffer size for the successful creation of an AudioTrack instance in streaming mode. Using values smaller than getMinBufferSize() will result in an initialization failure.
mode

以上兩個模組的實現是比較好實現的。當這兩個模組實現好了,就可以實現網路上許多例子說明AudioRecord與AudioTrack用法時的“邊錄邊播”的效果。當然這不是我的目標,只是我們可以這樣測試自己的採集的資料是否正確。

  其實這個邊錄邊播的效果如果使用擴音器的話迴音是很嚴重的,而且噪音也很嚴重的,這也是一個問題!因此要進行下一步,編解碼!

  三、語音編解碼

  採集到的PCM資料是原始的語音資料,如果我們直接進行網路傳輸,那是不可取的。因此,要進行打包編碼。

  編碼我們需要第三方的庫,目前我使用的庫是speex(http://www.speex.org)。我看到許多SIP語音電話都使用到了這個庫進行編解碼。當然也有對這個庫評價不好的說法,但我覺得作為學習還是可取的,因為speex使用起來很方便。

  不過,我使用speex的時候,噪音是降低了,但使用擴音器的時候,還是有很大的迴音,但是效果已經好很多了。從speex的官網上可以知道,最新的speex版本添加了迴音以及降噪的處理,但我把迴音以及降噪模組加進去的時候,沒有明顯的效果,所以這是我使用speex庫時遇到的一個問題,目前還在研究中。知道原因的同學留個言學習一下哈。

  四、網路傳輸

  打包編碼之後就是網路傳輸了。網路傳輸主要是使用RTP(實時傳輸協議)。目前我使用的庫是jlibrtp庫http://sourceforge.net/projects/jlibrtp/?source=directory,這是一個java版本的實現。不過,這個庫有丟包的問題,以及會拋庫內的一些異常。由於我沒有找到更好的RTP傳輸的庫,所以只好使用這個庫了。喜歡研究的同學也可以研究一下Sipdroid的RTP實現,我也有在看,不過還沒有研究透。有研究過的同學,可以留言,我們一起學習探討一下哈。

  這個就是一個簡單P2P語音通話的實現思路。不過此思路,還沒有實現伺服器端。所以這個思路實現只能在區域網內通話。要實現P2P通話還需要NAT打洞的技術,這也是一個難點。我覺得難點就是用來攻破的。

  對於程式碼:由於是公司專案,不大方便貼出,之後有時間整理一下,再貼吧。

  本文為原創部落格,如果轉載請註明原文連結,謝謝!