本篇項目地址,名字是AudioRecord錄音(能暫停,將pch轉換爲wav),求star
https://github.com/979451341/Audio-and-video-learning-materials
先來段官方說明
1.AndioRecord大概說明
AndioRecord類的主要功能是讓各種JAVA應用能夠管理音頻資源,以便它們通過此類能夠錄製聲音相關的硬件所收集的聲音。此功能的實現就是通過”pulling”(讀取)AudioRecord對象的聲音數據來完成的。在錄音過程中,應用所需要做的就是通過後面三個類方法中的一個去及時地獲取AudioRecord對象的錄音數據. AudioRecord類提供的三個獲取聲音數據的方法分別是read(byte[], int, int), read(short[], int, int), read(ByteBuffer, int). 無論選擇使用那一個方法都必須事先設定方便用戶的聲音數據的存儲格式。
開始錄音的時候,AudioRecord需要初始化一個相關聯的聲音buffer, 這個buffer主要是用來保存新的聲音數據。這個buffer的大小,我們可以在對象構造期間去指定。它表明一個AudioRecord對象還沒有被讀取(同步)聲音數據前能錄多長的音(即一次可以錄製的聲音容量)。聲音數據從音頻硬件中被讀出,數據大小不超過整個錄音數據的大小(可以分多次讀出),即每次讀取初始化buffer容量的數據。
2.AudioRecord對象創建
AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes)
audioSource
音頻源:指的是從哪裏採集音頻。這裏我們當然是從麥克風採集音頻,所以此參數的值爲MIC
sampleRateInHz
採樣率:音頻的採樣頻率,每秒鐘能夠採樣的次數,採樣率越高,音質越高。給出的實例是44100、22050、11025但不限於這幾個參數。例如要採集低質量的音頻就可以使用4000、8000等低採樣率。
channelConfig
聲道設置:android支持雙聲道立體聲和單聲道。MONO單聲道,STEREO立體聲
audioFormat
編碼制式和採樣大小:採集來的數據當然使用PCM編碼(脈衝代碼調製編碼,即PCM編碼。PCM通過抽樣、量化、編碼三個步驟將連續變化的模擬信號轉換爲數字編碼。) android支持的採樣大小16bit 或者8bit。當然採樣大小越大,那麼信息量越多,音質也越高,現在主流的採樣大小都是16bit,在低質量的語音傳輸的時候8bit足夠了。
bufferSizeInBytes
採集數據需要的緩衝區的大小,如果不知道最小需要的大小可以在getMinBufferSize()查看。
AudioRecord.getMinBufferSize(sampleRateInHz,
channelConfig, channelConfig);
3.PCM和WAV文件
PCM
PCM是在由模擬信號向數字信號轉化的一種常用的編碼格式,稱爲脈衝編碼調製,PCM將模擬信號按照一定的間距劃分爲多段,然後通過二進制去量化每一個間距的強度。PCM表示的是音頻文件中隨着時間的流逝的一段音頻的振幅。Android在WAV文件中支持PCM的音頻數據。
WAV文件
WAV,MP3等是我們比較常見的音頻格式,不同的編碼格式對原始音頻採用的編碼方式也是不同的,通常爲了方便傳輸等問題,會對原始音頻進行壓縮,同時爲了能夠使得播放器能夠識別該種格式,所以在每種格式的頭文件都是特定的,有一定的規則,來讓播放器識別出是該種格式,然後按着相應的解碼算法去播放後面的音頻文件。
4.代碼運行過程
首先是創建和配置AudioRecord
//音頻輸入-麥克風
private final static int AUDIO_INPUT = MediaRecorder.AudioSource.MIC;
//採用頻率
//44100是目前的標準,但是某些設備仍然支持22050,16000,11025
//採樣頻率一般共分爲22.05KHz、44.1KHz、48KHz三個等級
private final static int AUDIO_SAMPLE_RATE = 16000;
//聲道 單聲道
private final static int AUDIO_CHANNEL = AudioFormat.CHANNEL_IN_MONO;
//編碼
private final static int AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;
// 緩衝區字節大小
private int bufferSizeInBytes = 0;
//錄音對象
private AudioRecord audioRecord;
/**
* 創建默認的錄音對象
*
* @param fileName 文件名
*/
public void createDefaultAudio(String fileName) {
// 獲得緩衝區字節大小
bufferSizeInBytes = AudioRecord.getMinBufferSize(AUDIO_SAMPLE_RATE,
AUDIO_CHANNEL, AUDIO_ENCODING);
audioRecord = new AudioRecord(AUDIO_INPUT, AUDIO_SAMPLE_RATE, AUDIO_CHANNEL, AUDIO_ENCODING, bufferSizeInBytes);
this.fileName = fileName;
status = Status.STATUS_READY;
}
開始錄音,同時開個子線程將錄音的數據放入pcm文件
audioRecord.startRecording();
new Thread(new Runnable() {
@Override
public void run() {
writeDataTOFile(listener);
}
}).start();
如何將音頻寫入文件是重點,我寫個僞代碼,說明這個代碼運行順序
首先創建pcm文件,得到他的FileOutputStream,然後不斷循環AudioRecord通過read將錄音的數據放入字節數組裏,當錄音結束的時候要記得停止這個循環
// new一個byte數組用來存一些字節數據,大小爲緩衝區大小
byte[] audiodata = new byte[bufferSizeInBytes];
FileOutputStream fos = null;
int readsize = 0;
try {
File file = new File(currentFileName);
if (file.exists()) {
file.delete();
}
fos = new FileOutputStream(file);// 建立一個可存取字節的文件
} catch (IllegalStateException e) {
Log.e("AudioRecorder", e.getMessage());
throw new IllegalStateException(e.getMessage());
} catch (FileNotFoundException e) {
Log.e("AudioRecorder", e.getMessage());
}
while (true) {
readsize = audioRecord.read(audiodata, 0, bufferSizeInBytes);
if (AudioRecord.ERROR_INVALID_OPERATION != readsize && fos != null) {
try {
fos.write(audiodata);
} catch (IOException e) {
Log.e("AudioRecorder", e.getMessage());
}
}
}
如何我們要實現能夠暫停錄音,只要AudioRecord.stop就行,然後當繼續錄音時在AudioRecord.start就好了,但是要另創建一個pcm記錄,當錄音結束時我們要將這些pcm一起轉換爲一個wav,
至於pcm轉換爲wav的代碼是固定的,我就不貼出,大家在文章首部代碼地址自取吧