日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術(shù)文章
文章詳情頁

Android用AudioRecord進行錄音

瀏覽:174日期:2022-09-21 11:21:55

在音視頻開發(fā)中,錄音當然是必不可少的。首先我們要學會單獨的錄音功能,當然這里說的錄音是指用AudioRecord來錄音,讀取錄音原始數(shù)據(jù),讀到的就是所謂的PCM數(shù)據(jù)。對于錄音來說,最重要的幾個參數(shù)要搞明白:

1、simpleRate采樣率,采樣率就是采樣頻率,每秒鐘記錄多少個樣本。

2、channelConfig通道配置,其實就是所謂的單通道,雙通道之類的,AudioFormat.CHANNEL_IN_MONO單通道,AudioFormat.CHANNEL_IN_STEREO雙通道,這里只列了這兩種,還有其它的,可自行查閱。

3、audioFormat音頻格式,其實就是采樣的精度,每個樣本的位數(shù),AudioFormat.ENCODING_PCM_8BIT每個樣本占8位,AudioFormat.ENCODING_PCM_16BIT每個樣本占16位,這里也只用了這兩個,別的沒研究。

在學習過程中會用到的一些參數(shù),我這里封裝了一個類,如下

public class AudioParams { enum Format { SINGLE_8_BIT, DOUBLE_8_BIT, SINGLE_16_BIT, DOUBLE_16_BIT } private Format format; int simpleRate; AudioParams(int simpleRate, Format f) { this.simpleRate = simpleRate; this.format = f; } AudioParams(int simpleRate, int channelCount, int bits) { this.simpleRate = simpleRate; set(channelCount, bits); } int getBits() { return (format == Format.SINGLE_8_BIT || format == Format.DOUBLE_8_BIT) ? 8 : 16; } int getEncodingFormat() { return (format == Format.SINGLE_8_BIT || format == Format.DOUBLE_8_BIT) ? AudioFormat.ENCODING_PCM_8BIT : AudioFormat.ENCODING_PCM_16BIT; } int getChannelCount() {return (format == Format.SINGLE_8_BIT || format == Format.SINGLE_16_BIT) ? 1 : 2;} int getChannelConfig() { return (format == Format.SINGLE_8_BIT || format == Format.SINGLE_16_BIT) ? AudioFormat.CHANNEL_IN_MONO : AudioFormat.CHANNEL_IN_STEREO; } int getOutChannelConfig() { return (format == Format.SINGLE_8_BIT || format == Format.SINGLE_16_BIT) ? AudioFormat.CHANNEL_OUT_MONO : AudioFormat.CHANNEL_OUT_STEREO; } void set(int channelCount, int bits) { if ((channelCount != 1 && channelCount != 2) || (bits != 8 && bits != 16)) { throw new IllegalArgumentException('不支持其它格式 channelCount=$channelCount bits=$bits'); } if (channelCount == 1) { if (bits == 8) {format = Format.SINGLE_8_BIT; } else {format = Format.SINGLE_16_BIT; } } else { if (bits == 8) {format = Format.DOUBLE_8_BIT; } else {format = Format.DOUBLE_16_BIT; } } }}

這里固定使用了單通道8位,雙通道8位,單通道16位,雙通道16位,所以用了枚舉來限制。

為了方便把錄音數(shù)據(jù)拿出來顯示、存儲,這里寫了一個回調(diào)方法如下

public interface RecordCallback { /** * 數(shù)據(jù)回調(diào) * * @param bytes 數(shù)據(jù) * @param len 數(shù)據(jù)有效長度,-1時表示數(shù)據(jù)結(jié)束 */ void onRecord(byte[] bytes, int len); }

有了這些參數(shù),現(xiàn)在就可以錄音了,先看一下樣例

public void startRecord(AudioParams params, RecordCallback callback) { int simpleRate = params.simpleRate; int channelConfig = params.getChannelConfig(); int audioFormat = params.getEncodingFormat(); // 根據(jù)AudioRecord提供的api拿到最小緩存大小 int bufferSize = AudioRecord.getMinBufferSize(simpleRate, channelConfig, audioFormat); //創(chuàng)建Record對象 record = new AudioRecord(MediaRecorder.AudioSource.MIC, simpleRate, channelConfig, audioFormat, bufferSize); recordThread = new Thread(() -> { byte[] buffer = new byte[bufferSize]; record.startRecording(); recording = true; while (recording) {int read = record.read(buffer, 0, bufferSize);// 將數(shù)據(jù)回調(diào)到外部if (read > 0 && callback != null) { callback.onRecord(buffer, read);} } if (callback != null) {// len 為-1時表示結(jié)束callback.onRecord(buffer, -1);recording = false; } //釋放資源 release(); }); recordThread.start(); }

這個方法就是簡單的采集音頻數(shù)據(jù),這個數(shù)據(jù)就是最原始的pcm數(shù)據(jù)。

拿到pcm數(shù)據(jù)以后,如果直接保存到文件是無法直接播放的,因為這只是一堆數(shù)據(jù),沒有任何格式說明,如果想讓普通播放器可以播放,需要在文件中加入文件頭,來告訴播放器這個數(shù)據(jù)的格式,這里是直接保存成wav格式的數(shù)據(jù)。下面就是加入wav格式文件頭的方法

private static byte[] getWaveFileHeader(int totalDataLen, int sampleRate, int channelCount, int bits) { byte[] header = new byte[44]; // RIFF/WAVE header header[0] = ’R’; header[1] = ’I’; header[2] = ’F’; header[3] = ’F’; int fileLength = totalDataLen + 36; header[4] = (byte) (fileLength & 0xff); header[5] = (byte) (fileLength >> 8 & 0xff); header[6] = (byte) (fileLength >> 16 & 0xff); header[7] = (byte) (fileLength >> 24 & 0xff); //WAVE header[8] = ’W’; header[9] = ’A’; header[10] = ’V’; header[11] = ’E’; // ’fmt ’ chunk header[12] = ’f’; header[13] = ’m’; header[14] = ’t’; header[15] = ’ ’; // 4 bytes: size of ’fmt ’ chunk header[16] = 16; header[17] = 0; header[18] = 0; header[19] = 0; // pcm format = 1 header[20] = 1; header[21] = 0; header[22] = (byte) channelCount; header[23] = 0; header[24] = (byte) (sampleRate & 0xff); header[25] = (byte) (sampleRate >> 8 & 0xff); header[26] = (byte) (sampleRate >> 16 & 0xff); header[27] = (byte) (sampleRate >> 24 & 0xff); int byteRate = sampleRate * bits * channelCount / 8; header[28] = (byte) (byteRate & 0xff); header[29] = (byte) (byteRate >> 8 & 0xff); header[30] = (byte) (byteRate >> 16 & 0xff); header[31] = (byte) (byteRate >> 24 & 0xff); // block align header[32] = (byte) (channelCount * bits / 8); header[33] = 0; // bits per sample header[34] = (byte) bits; header[35] = 0; //data header[36] = ’d’; header[37] = ’a’; header[38] = ’t’; header[39] = ’a’; header[40] = (byte) (totalDataLen & 0xff); header[41] = (byte) (totalDataLen >> 8 & 0xff); header[42] = (byte) (totalDataLen >> 16 & 0xff); header[43] = (byte) (totalDataLen >> 24 & 0xff); return header; }

根據(jù)幾個參數(shù)設(shè)置一下文件頭,然后直接寫入錄音采集到的pcm數(shù)據(jù),就可被正常播放了。wav文件頭格式定義,可點擊這里查看或自行百度。

如果想要通過AudioRecord錄音直接保存到文件,可參考下面方法

public void startRecord(String filePath, AudioParams params, RecordCallback callback) { int channelCount = params.getChannelCount(); int bits = params.getBits(); final boolean storeFile = filePath != null && !filePath.isEmpty(); startRecord(params, (bytes, len) -> { if (storeFile) {if (file == null) { File f = new File(filePath); if (f.exists()) { f.delete(); } try { file = new RandomAccessFile(f, 'rw'); file.write(getWaveFileHeader(0, params.simpleRate, channelCount, bits)); } catch (IOException e) { e.printStackTrace(); }}if (len > 0) { try { file.write(bytes, 0, len); } catch (IOException e) { e.printStackTrace(); }} else { try { // 因為在前面已經(jīng)寫入頭信息,所以這里要減去頭信息才是數(shù)據(jù)的長度 int length = (int) file.length() - 44; file.seek(0); file.write(getWaveFileHeader(length, params.simpleRate, channelCount, bits)); file.close(); } catch (IOException e) { e.printStackTrace(); }} } if (callback != null) {callback.onRecord(bytes, len); } }); }

先通過RandomAccessFile創(chuàng)建文件,先寫入文件頭,由于暫時我們不知道會錄多長,有多少pcm數(shù)據(jù),長度先用0表示,等錄音結(jié)束后,通過seek(int)方法重新寫入文件頭信息,也可以先把pcm數(shù)據(jù)保存到臨時文件,然后再寫入到一個新的文件中,這里就不舉例說明了。

最后放入完整類的代碼

package cn.sskbskdrin.record.audio;import android.media.AudioRecord;import android.media.MediaRecorder;import java.io.File;import java.io.IOException;import java.io.RandomAccessFile;/** * @author sskbskdrin * @date 2019/April/3 */public class AudioRecordManager { private AudioParams DEFAULT_FORMAT = new AudioParams(8000, 1, 16); private AudioRecord record; private Thread recordThread; private boolean recording = false; private RandomAccessFile file; public void startRecord(String filePath, RecordCallback callback) { startRecord(filePath, DEFAULT_FORMAT, callback); } public void startRecord(String filePath, AudioParams params, RecordCallback callback) { int channelCount = params.getChannelCount(); int bits = params.getBits(); final boolean storeFile = filePath != null && !filePath.isEmpty(); startRecord(params, (bytes, len) -> { if (storeFile) {if (file == null) { File f = new File(filePath); if (f.exists()) { f.delete(); } try { file = new RandomAccessFile(f, 'rw'); file.write(getWaveFileHeader(0, params.simpleRate, channelCount, bits)); } catch (IOException e) { e.printStackTrace(); }}if (len > 0) { try { file.write(bytes, 0, len); } catch (IOException e) { e.printStackTrace(); }} else { try { // 因為在前面已經(jīng)寫入頭信息,所以這里要減去頭信息才是數(shù)據(jù)的長度 int length = (int) file.length() - 44; file.seek(0); file.write(getWaveFileHeader(length, params.simpleRate, channelCount, bits)); file.close(); } catch (IOException e) { e.printStackTrace(); }} } if (callback != null) {callback.onRecord(bytes, len); } }); } public void startRecord(AudioParams params, RecordCallback callback) { int simpleRate = params.simpleRate; int channelConfig = params.getChannelConfig(); int audioFormat = params.getEncodingFormat(); // 根據(jù)AudioRecord提供的api拿到最小緩存大小 int bufferSize = AudioRecord.getMinBufferSize(simpleRate, channelConfig, audioFormat); //創(chuàng)建Record對象 record = new AudioRecord(MediaRecorder.AudioSource.MIC, simpleRate, channelConfig, audioFormat, bufferSize); recordThread = new Thread(() -> { byte[] buffer = new byte[bufferSize]; record.startRecording(); recording = true; while (recording) {int read = record.read(buffer, 0, bufferSize);// 將數(shù)據(jù)回調(diào)到外部if (read > 0 && callback != null) { callback.onRecord(buffer, read);} } if (callback != null) {// len 為-1時表示結(jié)束callback.onRecord(buffer, -1);recording = false; } //釋放資源 release(); }); recordThread.start(); } public void stop() { recording = false; } public void release() { recording = false; if (record != null) { record.stop(); record.release(); } record = null; file = null; recordThread = null; } private static byte[] getWaveFileHeader(int totalDataLen, int sampleRate, int channelCount, int bits) { byte[] header = new byte[44]; // RIFF/WAVE header header[0] = ’R’; header[1] = ’I’; header[2] = ’F’; header[3] = ’F’; int fileLength = totalDataLen + 36; header[4] = (byte) (fileLength & 0xff); header[5] = (byte) (fileLength >> 8 & 0xff); header[6] = (byte) (fileLength >> 16 & 0xff); header[7] = (byte) (fileLength >> 24 & 0xff); //WAVE header[8] = ’W’; header[9] = ’A’; header[10] = ’V’; header[11] = ’E’; // ’fmt ’ chunk header[12] = ’f’; header[13] = ’m’; header[14] = ’t’; header[15] = ’ ’; // 4 bytes: size of ’fmt ’ chunk header[16] = 16; header[17] = 0; header[18] = 0; header[19] = 0; // pcm format = 1 header[20] = 1; header[21] = 0; header[22] = (byte) channelCount; header[23] = 0; header[24] = (byte) (sampleRate & 0xff); header[25] = (byte) (sampleRate >> 8 & 0xff); header[26] = (byte) (sampleRate >> 16 & 0xff); header[27] = (byte) (sampleRate >> 24 & 0xff); int byteRate = sampleRate * bits * channelCount / 8; header[28] = (byte) (byteRate & 0xff); header[29] = (byte) (byteRate >> 8 & 0xff); header[30] = (byte) (byteRate >> 16 & 0xff); header[31] = (byte) (byteRate >> 24 & 0xff); // block align header[32] = (byte) (channelCount * bits / 8); header[33] = 0; // bits per sample header[34] = (byte) bits; header[35] = 0; //data header[36] = ’d’; header[37] = ’a’; header[38] = ’t’; header[39] = ’a’; header[40] = (byte) (totalDataLen & 0xff); header[41] = (byte) (totalDataLen >> 8 & 0xff); header[42] = (byte) (totalDataLen >> 16 & 0xff); header[43] = (byte) (totalDataLen >> 24 & 0xff); return header; } public interface RecordCallback { /** * 數(shù)據(jù)回調(diào) * * @param bytes 數(shù)據(jù) * @param len 數(shù)據(jù)有效長度,-1時表示數(shù)據(jù)結(jié)束 */ void onRecord(byte[] bytes, int len); }}

如有不對之處還請評論指正

以上就是Android用AudioRecord進行錄音的詳細內(nèi)容,更多關(guān)于Android AudioRecord的資料請關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標簽: Android
相關(guān)文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
国产成年精品| 久久精品国产999大香线蕉| 91精品二区| 三级在线看中文字幕完整版| 亚洲欧美日韩国产综合精品二区 | 免播放器亚洲| 五月激情久久| 国产精品二区不卡| 欧美精品国产一区| 日韩三级视频| 在线视频日韩| 免费视频一区二区| 日欧美一区二区| 激情亚洲影院在线观看| av在线日韩| 中文字幕系列一区| 在线亚洲欧美| 蜜桃91丨九色丨蝌蚪91桃色| 夜久久久久久| 国产成年精品| 亚洲免费专区| 国产乱码精品一区二区三区亚洲人 | 国产精品国产一区| 麻豆国产精品视频| 99国产精品99久久久久久粉嫩| 视频一区二区国产| 亚洲日本在线观看视频| 国产精品久av福利在线观看| 国产精品成人自拍| 日本精品不卡| 丝袜亚洲精品中文字幕一区| 日韩精彩视频在线观看| 97在线精品| 免费人成在线不卡| 亚洲精品福利电影| 99视频精品全国免费| 国产91在线播放精品| 欧美精品91| sm捆绑调教国产免费网站在线观看| 国产精品天天看天天狠| 国产精品蜜月aⅴ在线| 精品国产一区二区三区性色av| 加勒比视频一区| 影音国产精品| 国产一区二区视频在线看| 久草精品视频| 亚洲精品美女91| 奶水喷射视频一区| 美女网站一区| 欧美激情91| 蜜桃传媒麻豆第一区在线观看| 亚洲国产一区二区三区在线播放| 亚洲无线观看| 欧美日韩免费看片| 久久久精品区| 亚洲3区在线| 蜜桃传媒麻豆第一区在线观看| 伊人久久av| 久久国产麻豆精品| 亚洲日本欧美| 亚洲精品伦理| 日韩激情啪啪| 欧美日韩午夜电影网| 视频在线观看一区| 日本精品一区二区三区在线观看视频| 欧美精品高清| 国产 日韩 欧美 综合 一区| 亚洲一区二区三区四区五区午夜 | 中文视频一区| 色综合视频一区二区三区日韩 | 国内亚洲精品| 国产情侣久久| 亚洲日产国产精品| 欧美在线影院| 欧美日韩四区| 综合五月婷婷| 日本国产一区| 国产精品第一| 日韩a一区二区| 免费视频一区三区| 免费欧美日韩| 亚洲一区二区三区高清| 伊人影院久久| 国产精品久久久久久久久久白浆 | 国产夫妻在线| 人人爱人人干婷婷丁香亚洲| 国产视频一区二| 午夜国产精品视频| 国产精品亚洲一区二区在线观看| 99精品视频在线| 青草国产精品久久久久久| 91高清一区| 麻豆国产欧美一区二区三区| 国产精品观看| 卡一卡二国产精品| 99久久精品费精品国产| 99成人超碰| 一区二区三区四区在线观看国产日韩| 国产精品羞羞答答在线观看| 国产精品亚洲四区在线观看| 久久中文字幕一区二区| 色婷婷狠狠五月综合天色拍| 中文字幕一区二区av| 日韩高清一区| 国产精品黑丝在线播放| 亚洲专区一区| 欧美日韩国产观看视频| 日韩av成人高清| 视频在线观看一区二区三区| 另类综合日韩欧美亚洲| 美女视频黄免费的久久| 91九色精品国产一区二区| 日韩视频一二区| 极品av在线| 国产精品毛片| 日韩av一区二区三区四区| 麻豆精品久久久| aⅴ色国产欧美| 四虎在线精品| 日韩一区精品| 午夜亚洲福利在线老司机| 日韩在线观看不卡| 欧美二三四区| 成人在线超碰| 国产一区二区三区四区五区传媒| 亚洲精品字幕| 视频一区二区中文字幕| 蜜臀av性久久久久蜜臀aⅴ四虎| 韩国久久久久久| 中文字幕在线免费观看视频| 日本午夜精品久久久久| 国产婷婷精品| 国产日本精品| 99热精品久久| 精品一区二区三区免费看| 在线精品国产亚洲| 91福利精品在线观看| 视频一区二区中文字幕| 蜜臀a∨国产成人精品| 91精品蜜臀一区二区三区在线 | 日韩va亚洲va欧美va久久| 热久久久久久久| 日韩欧美中文字幕电影| 日韩精品一卡| 欧美不卡高清一区二区三区| 日韩综合精品| www成人在线视频| 99久久亚洲精品| 99久久久久久中文字幕一区| 91精品一区二区三区综合| 成人免费电影网址| 欧美日韩免费看片| 国产66精品| 97久久亚洲| 偷拍精品精品一区二区三区| 国产va在线视频| 中文字幕在线官网| 国产一区日韩欧美| 国产一级一区二区| 亚洲欧洲日韩| 国产盗摄——sm在线视频| 欧美成人午夜| 欧美国产专区| 国产亚洲精品v| 亚洲资源在线| 日韩激情啪啪| 麻豆中文一区二区| 欧美激情视频一区二区三区免费| 九九久久电影| 日韩av二区在线播放| 午夜精品成人av| 亚洲精品伊人| 九九99久久精品在免费线bt| 九九久久国产| 亚洲尤物在线| 成人av三级| 美女久久精品| 日韩av中文字幕一区二区| 亚洲国产一区二区三区在线播放| 国产精品免费大片| 日本亚洲视频| 激情久久中文字幕| 三级一区在线视频先锋| 91成人超碰| 日韩高清一区二区| 国产不卡精品| 神马日本精品| 亚洲性色视频| 99热精品久久| 欧美亚洲tv| 免费一级欧美在线观看视频 | 色88888久久久久久影院| 蜜桃av一区二区在线观看| 精品一区av| 蜜臀精品一区二区三区在线观看 | 亚洲无线观看| 国产精品久久久久久妇女 | 国产人成精品一区二区三| 国产视频一区二区在线播放| 国产精品黄网站|