編輯:關於Android編程
【android開發】實現語音數據實時采集/播放。今天無意中看到一篇關於android實現語音數據實時采集/播放的文章,感覺寫得非常棒,挺全面的,所以特地轉載了,還有其實還可以根據這篇博客內容考慮下視頻數據實時采集、播放的實現。
最近做的項目是和語音實時采集並發送,對方實時接收並播放相關,下面記錄下實現的核心代碼。
很多Android開發者應該知道android有個MediaRecorder對象和MediaPlayer對象,用於錄制和播放音頻。這個弊端在於他們不能實時采集並發送出去,所以,我們只能使用AudioRecord和AudioTrack來實現。
記得申明權限:
一、AudioRecord實現核心代碼介紹如下:
1、先申明相關錄制配置參數
private AudioRecord audioRecord;// 錄音對象 private int frequence = 8000;// 采樣率 8000 private int channelInConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;// 定義采樣通道 private int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;// 定義音頻編碼(16位) private byte[] buffer = null;// 錄制的緩沖數組
2、在開始錄制前,我們需要初始化AudioRecord類。
// 根據定義好的幾個配置,來獲取合適的緩沖大小 // int bufferSize = 800; int bufferSize = AudioRecord.getMinBufferSize(frequence, channelInConfig, audioEncoding); // 實例化AudioRecord audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, frequence, channelInConfig, audioEncoding, bufferSize); // 定義緩沖數組 buffer = new byte[bufferSize];
3、准備開始錄制,使用循環不斷讀取數據。
audioRecord.startRecording();// 開始錄制 isRecording = true;// 設置錄制標記為true // 開始錄制 while (isRecording) { // 錄制的內容放置到了buffer中,result代表存儲長度 int result = audioRecord.read(buffer, 0, buffer.length); /*.....result為buffer中錄制數據的長度(貌似基本上都是640)。 剩下就是處理buffer了,是發送出去還是直接播放,這個隨便你。*/ } //錄制循環結束後,記得關閉錄制!! if (audioRecord != null) { audioRecord.stop(); }
二、AudioTrack代碼實現介紹如下:
1、聲明播放相關配置。
private AudioTrack track = null;// 錄音文件播放對象 private int frequence = 8000;// 采樣率 8000 private int channelInConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;// 定義采樣通道 private int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;// 定義音頻編碼(16位) private int bufferSize = -1;// 播放緩沖大小
2、初始化AudioTrack對象(初始化一次,該對象可重復使用)
// 獲取緩沖 大小 bufferSize = AudioTrack.getMinBufferSize(frequence, channelInConfig, audioEncoding); // 實例AudioTrack track = new AudioTrack(AudioManager.STREAM_MUSIC, frequence, channelInConfig, audioEncoding, bufferSize, AudioTrack.MODE_STREAM);
3、使用AudioTrack播放語音數據。
//將語音數據寫入即可。 track.write(dataArray, buffer, len);
問題一:
由於目前的項目是實時采集,實時發送,所以需要考慮到包的大小,經測試,我們使用160個byte作為一個包傳遞可以做到比較良好的播放效果(也就是將一份buffer拆分成四個發送)。處理代碼如下:
// 將數據通過監聽接口回調出去 if (audioRecordingCallback != null) { int offset = result % MAX_DATA_LENGTH > 0 ? 1 : 0; //將一個buffer拆分成幾份小數據包 MAX_DATA_LENGTH 為包的最大byte數 for (int i = 0; i < result / MAX_DATA_LENGTH + offset; i++) { int length = MAX_DATA_LENGTH; if ((i + 1) * MAX_DATA_LENGTH > result) { length = result - i * MAX_DATA_LENGTH; } //寫到回調接口 audioRecordingCallback.onRecording(buffer, i * MAX_DATA_LENGTH, length); } }
問題二:
有時候傳輸的過來播放聲音會一卡一卡的,為了解決這樣的問題,暫時使用了語音雙緩沖機制來解決,問題優化很明顯。代碼和示意圖如下:
基礎介紹異步消息處理線程是指,線程在啟動後會進入一個無線循環體中,沒循環一次,從內部的消息隊列中取出一個一個消息,並回調相應的消息處理函數,執行完一個消息後則繼續循環。如
以前編程的時候,遇到倒計時的功能時,經常自己去寫,但其實Android已經幫封裝好了一個倒計時類CountDownTimer,其實是將後台線程的創建和Handler隊列封
沉浸式狀態欄的來源就是很多手機用的是實體按鍵,沒有虛擬鍵,於是開了沉浸模式就只有狀態欄消失了。於是沉浸模式成了沉浸式狀態欄。我們先來看下具體的效果開啟沉浸模式後,狀態欄消
一、JNI概述 JNI 是Java Native Interface的縮寫,中文翻譯為“Java本地調用”,JNI 是本地編程接口。它使得在 Java 虛擬機 (VM)