上一篇介紹了如何使用Mediarecorder來錄音,以及播放錄音。不過並沒有達到我的目的,一邊錄音一邊播放。今天就講解一下如何一邊錄音一邊播放。使用AndioRecord錄音和使用AudioTrack回放。參考了網上一位開發者的例子代碼開發,最后會給出相關Demo。
(PS:新建的QQ群,有興趣可以加入一起討論:Android群:322599434)
1、AndioRecord類介紹
AndioRecord類的主要功能是讓各種JAVA應用能夠管理音頻資源,以便它們通過此類能夠錄制平台的聲音輸入硬件所收集的聲音。此功能的實現就是通過”pulling同步”(reading讀取)AudioRecord對象的聲音數據來完成的。在錄音過程中,應用所需要做的就是通過后面三個類方法中的一個去及時地獲取AudioRecord對象的錄音數據. AudioRecord類提供的三個獲取聲音數據的方法分別是read(byte[], int, int), read(short[], int, int), read(ByteBuffer, int)。 無論選擇使用那一個方法都必須事先設定方便用戶的聲音數據的存儲格式。然后再使用AudioTrack實時回放聲音即可。
下面是使用AudioRecord的過程中,可能會遇到的返回值,對於定位問題的原因很有用,解析很簡單,我就不翻譯了。
2、AudioRecord初始化
//Edited by mythou
//http://www.cnblogs.com/mythou/
// AudioRecord 得到錄制最小緩沖區的大小 m_in_buf_size = AudioRecord.getMinBufferSize(8000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);
// 實例化播放音頻對象 m_in_rec = new AudioRecord(MediaRecorder.AudioSource.MIC, 8000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, m_in_buf_size);
AudioRecord的初始化參數比較多,需要注意設置。這幾個參數都是標准的聲音采集的參數,下面我針對這幾個參數做個介紹,實際使用的時候,你可以根據你的情況設置。
AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes)
AudioRecord構造參數的參數解析,可以根據實際情況調整:
audioSource | 音頻源:指的是從哪里采集音頻。這里我們是從麥克風采集音頻,所以此參數的值為MIC。可以參考MediaRecorder.AudioSource類,查看其他音頻源。 |
sampleRateInHz | 采樣率:音頻的采樣頻率,每秒鍾能夠采樣的次數,采樣率越高,音質越高。給出的實例是44100、22050、11025但不限於這幾個參數。例如要采集低質量的音頻就可以使用4000、8000等低采樣率。 |
channelConfig | 聲道設置:android支持雙聲道立體聲和單聲道。MONO單聲道,STEREO立體聲 |
audioFormat | 編碼制式和采樣大小:采集來的數據當然使用PCM編碼(脈沖代碼調制編碼,即PCM編碼。PCM通過抽樣、量化、編碼三個步驟將連續變化的模擬信號轉換為數字編碼。) android支持的采樣大小16bit 或者8bit。當然采樣大小越大,那么信息量越多,音質也越高,現在主流的采樣大小都是16bit,在低質量的語音傳輸的時候8bit 足夠了。 |
bufferSizeInBytes | 采集數據需要的緩沖區的大小,如果不知道最小需要的大小可以在getMinBufferSize()查看。 |
上面是針對AudioRecord的初始化參數做了詳細闡述,這個對於使用AudioRecord十分重要,也影響了錄音和后期播放的效果,所以在你使用AudioRecord進行錄音前,請仔細熟悉上面參數。
3、錄音
//Edited by mythou
//http://www.cnblogs.com/mythou/
// 錄音線程 class recordSound implements Runnable { @Override public void run() { Log.d(TAG, "........recordSound run()......"); byte[] bytes_pkg; // 開始錄音 m_in_rec.startRecording(); while (flag) { m_in_rec.read(m_in_bytes, 0, m_in_buf_size); bytes_pkg = m_in_bytes.clone(); Log.i(TAG, "........recordSound bytes_pkg==" + bytes_pkg.length); if (m_in_q.size() >= 2) { m_in_q.removeFirst(); } m_in_q.add(bytes_pkg); } } }
這里錄音使用的是read()方法來讀取錄音的數據,並且把錄音放到一個獨立線程執行,讀取到的錄音數據,放入到隊列里面,供播放線程使用。下面我們看看播放線程:
4、播放錄音
//Edited by mythou
//http://www.cnblogs.com/mythou/
//播放線程 class playRecord implements Runnable { @Override public void run() { Log.d(TAG, "........playRecord run()......"); byte[] bytes_pkg = null; // 開始播放 m_out_trk.play(); while (flag) { try { m_out_bytes = m_in_q.getFirst(); bytes_pkg = m_out_bytes.clone(); m_out_trk.write(bytes_pkg, 0, bytes_pkg.length); } catch (Exception e) { e.printStackTrace(); } } } }
播放錄音和錄音過程大致一樣,都是一個獨立線程,這里需要注意的是,錄音和播放都是開了獨立的線程,而不是放在UI線程執行,至於原因不用我多說,大家應該都明白。
5、解決異常
下面把我調試過程中遇到的一個問題分享一下:
08-06 20:08:25.032: E/AndroidRuntime(32389): FATAL EXCEPTION: Thread-2063 08-06 20:08:25.032: E/AndroidRuntime(32389): java.lang.IllegalStateException: startRecording() called on an uninitialized AudioRecord. 08-06 20:08:25.032: E/AndroidRuntime(32389): at android.media.AudioRecord.startRecording(AudioRecord.java:540) 08-06 20:08:25.032: E/AndroidRuntime(32389): at com.apical.AuxIn.AudioNowRecord$recordSound.run(AudioNowRecord.java:131) 08-06 20:08:25.032: E/AndroidRuntime(32389): at java.lang.Thread.run(Thread.java:856)
出現上面問題的原因是錄音的硬件資源被申請了,但是沒有釋放,然后你再次申請資源,導致初始化失敗。這里需要注意的是不僅僅需要調用Release()方法。還需要把AudioRecord對象置為null,否則還是釋放失敗。下面是Android 開發網上面的一個對於AudioRecord的釋放說明。
Releases the native AudioRecord resources. The object can no longer be used and the reference should be set to null after a call to release()。
6、結語
上面就是一邊錄音一邊播放的大致代碼流程,主要就是AudioRecord和AudioTrack的使用,實際使用的時候,你需要根據自己的實際情況,調試AudioRecord的音頻采樣參數和回放的參數,達到你想要的效果。另外這個功能也能實現KTV的回聲效果。自己調試一下參數即可。
下面給出一個網絡上的demo,是一位叫吳辰彪的開發者分享的,因為我是在CSDN下載的這個Demo,只從代碼中看到作者名字。感謝這位開發者分享了這個錄音回放的Demo。
錄音回放Demo:RecordPlay2013-8-7.rar
相關文章:
Android 錄音和播放
Edited by mythou
原創博文,轉載請標明出處:http://www.cnblogs.com/mythou/p/3241925.html