在音视频开发中,录音当然是必不可少的。首先我们要学会单独的录音功能,当然这里说的录音是指用AudioRecord来录音,读取录音原始数据,读到的就是所谓的PCM数据。对于录音来说,最重要的几个参数要搞明白:
1、simpleRate采样率,采样率就是采样频率,每秒钟记录多少个样本。
2、channelConfig通道配置,其实就是所谓的单通道,双通道之类的,AudioFormat.CHANNEL_IN_MONO单通道,AudioFormat.CHANNEL_IN_STEREO双通道,这里只列了这两种,还有其它的,可自行查阅。
3、audioFormat音频格式,其实就是采样的精度,每个样本的位数,AudioFormat.ENCODING_PCM_8BIT每个样本占8位,AudioFormat.ENCODING_PCM_16BIT每个样本占16位,这里也只用了这两个,别的没研究。
在学习过程中会用到的一些参数,我这里封装了一个类,如下
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位,所以用了枚举来限制。
为了方便把录音数据拿出来显示、存储,这里写了一个回调方法如下
public interface RecordCallback { /** * 数据回调 * * @param bytes 数据 * @param len 数据有效长度,-1时表示数据结束 */ void onRecord(byte[] bytes, int len); }
有了这些参数,现在就可以录音了,先看一下样例
public void startRecord(AudioParams params, RecordCallback callback) { int simpleRate = params.simpleRate; int channelConfig = params.getChannelConfig(); int audioFormat = params.getEncodingFormat(); // 根据AudioRecord提供的api拿到最小缓存大小 int bufferSize = AudioRecord.getMinBufferSize(simpleRate, channelConfig, audioFormat); //创建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); // 将数据回调到外部 if (read > 0 && callback != null) { callback.onRecord(buffer, read); } } if (callback != null) { // len 为-1时表示结束 callback.onRecord(buffer, -1); recording = false; } //释放资源 release(); }); recordThread.start(); }
这个方法就是简单的采集音频数据,这个数据就是最原始的pcm数据。
拿到pcm数据以后,如果直接保存到文件是无法直接播放的,因为这只是一堆数据,没有任何格式说明,如果想让普通播放器可以播放,需要在文