天天看點

Android 實時錄音和回放,邊錄音邊播放 (KTV回音效果)

原文位址為: Android 實時錄音和回放,邊錄音邊播放 (KTV回音效果)

  上一篇介紹了如何使用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的過程中,可能會遇到的傳回值,對于定位問題的原因很有用,解析很簡單,我就不翻譯了。

Android 實時錄音和回放,邊錄音邊播放 (KTV回音效果)

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 

轉載請注明本文位址: Android 實時錄音和回放,邊錄音邊播放 (KTV回音效果)