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

來源:互聯網
上載者:User

  最近在在研究語音通話的實現,現在把我的實現思路記錄在這裡。不過,由於初次接觸語音通話,所以這是一個簡單的思路,也是經過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 the format in which the audio data is represented. See ENCODING_PCM_16BIT and ENCODING_PCM_8BIT
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. channelConfig:錄製通道,可以為AudioFormat.CHANNEL_IN_MONO and AudioFormat.CHANNEL_IN_STEREO. AudioFormat.CHANNEL_IN_MONO
  4. audioFormat:錄製編碼格式,可以為AudioFormat.ENCODING_16BIT和8BIT,其中16BIT的模擬性比8BIT好,但是需要消耗更多的電量和儲存空間
  5. bufferSizeInBytes:錄製緩衝大小:可以通過getMinBufferSize()方法來擷取

調用AudioRecord的 read(byte[], int, int)read(short[], int, int) or read(ByteBuffer, int)方法就可以採集PCM語音資料了。

  二、語音播放

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

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

public AudioTrack (int streamType, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes, int mode)
streamType the type of the audio stream. See STREAM_VOICE_CALLSTREAM_SYSTEMSTREAM_RINGSTREAM_MUSICSTREAM_ALARM, and STREAM_NOTIFICATION.
sampleRateInHz the sample rate expressed in Hertz.
channelConfig describes the configuration of the audio channels. See CHANNEL_OUT_MONO and CHANNEL_OUT_STEREO
audioFormat the format in which the audio data is represented. See ENCODING_PCM_16BIT and ENCODING_PCM_8BIT
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 streaming or static buffer. See MODE_STATIC and MODE_STREAM

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

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

  三、語音編解碼

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

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

  speex是一個c庫(當然也有java版本的,http://code.google.com/p/speexdroid/,但我還是建議使用c庫,因為java版本的speex效率可能不是很高),因此我們需要用到jni。如果沒有使用過jni的話,這也是一個學習的機會。可以參考sipdroid http://code.google.com/p/sipdroid/ 如果還是覺得麻煩的話可以參考這個開源項目 http://code.google.com/p/android-recorder/

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

  四、網路傳輸

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

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

  對於代碼:由於是公司項目,不大方便貼出,之後有時間整理一下,再貼吧。

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

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.