一、AudioRecord类的介绍
AudioRecord构造函数:
/** * @param audioSource :录音源 * 这里选择使用麦克风:MediaRecorder.AudioSource.MIC * @param sampleRateInHz: 采样率 * @param channelConfig:声道数 * @param audioFormat: 采样位数. * See {@link AudioFormat#ENCODING_PCM_8BIT}, {@link AudioFormat#ENCODING_PCM_16BIT}, * and {@link AudioFormat#ENCODING_PCM_FLOAT}. * @param bufferSizeInBytes: 音频录制的缓冲区大小 * See {@link #getMinBufferSize(int, int, int)} */public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes)
getMinBufferSize()
/** * 获取AudioRecord所需的最小缓冲区大小 * @param sampleRateInHz: 采样率 * @param channelConfig:声道数 * @param audioFormat: 采样位数. */public static int getMinBufferSize (int sampleRateInHz, int channelConfig, int audioFormat)
getRecordingState()
/** * 获取AudioRecord当前的录音状态 * @see AudioRecord#RECORDSTATE_STOPPED * @see AudioRecord#RECORDSTATE_RECORDING */public int getRecordingState()
startRecording()
/** * 开始录制 */ public int startRecording()
startRecording()
/** * 停止录制 */ public int stop()
read()
/** * 从录音设备中读取音频数据 * @param audioData 音频数据写入的byte[]缓冲区 * @param offsetInBytes 偏移量 * @param sizeInBytes 读取大小 * @return 返回负数则表示读取失败 * see {@link #ERROR_INVALID_OPERATION} -3 : 初始化错误 {@link #ERROR_BAD_VALUE} -3: 参数错误 {@link #ERROR_DEAD_OBJECT} -6: {@link #ERROR} */public int read(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes)
二、实现
实现过程就是调用上面的API的方法,构造AudioRecord实例后再调用startRecording(),开始录音,并通过read()方法不断获取录音数据记录下来,生成PCM文件。涉及耗时操作,所以最好在子线程中进行。
/** * @author zhaolewei on 2018/7/10. */public class RecordHelper { //0.此状态用于控制线程中的循环操作,应用volatile修饰,保持数据的一致性 private volatile RecordState state = RecordState.IDLE; private AudioRecordThread audioRecordThread; private File tmpFile = null; public void start(String filePath, RecordConfig config) { if (state != RecordState.IDLE) { Logger.e(TAG, "状态异常当前状态: %s", state.name()); return; } recordFile = new File(filePath); String tempFilePath = getTempFilePath(); Logger.i(TAG, "tmpPCM File: %s", tempFilePath); tmpFile = new File(tempFilePath); //1.开启录音线程并准备录音 audioRecordThread = new AudioRecordThread(); audioRecordThread.start(); } public void stop() { if (state == RecordState.IDLE) { Logger.e(TAG, "状态异常当前状态: %s", state.name()); return; } state = RecordState.STOP; } private class AudioRecordThread extends Thread { private AudioRecord audioRecord; private int bufferSize; AudioRecordThread() { //2.根据录音参数构造AudioRecord实体对象 bufferSize = AudioRecord.getMinBufferSize(currentConfig.getFrequency(), currentConfig.getChannel(), currentConfig.getEncoding()) * RECORD_AUDIO_BUFFER_TIMES; audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, currentConfig.getFrequency(), currentConfig.getChannel(), currentConfig.getEncoding(), bufferSize); } @Override public void run() { super.run(); state = RecordState.RECORDING; Logger.d(TAG, "开始录制"); FileOutputStream fos = null; try { fos = new FileOutputStream(tmpFile); audioRecord.startRecording(); byte[] byteBuffer = new byte[bufferSize]; while (state == RecordState.RECORDING) { //3.不断读取录音数据并保存至文件中 int end = audioRecord.read(byteBuffer, 0, byteBuffer.length); fos.write(byteBuffer, 0, end); fos.flush(); } //4.当执行stop()方法后state != RecordState.RECORDING,终止循环,停止录音 audioRecord.stop(); } catch (Exception e) { Logger.e(e, TAG, e.getMessage()); } finally { try { if (fos != null) { fos.close(); } } catch (IOException e) { Logger.e(e, TAG, e.getMessage()); } } state = RecordState.IDLE; Logger.d(TAG, "录音结束"); } } }
三、其他
这里实现了PCM音频的录制,AudioRecord API中只有开始和停止的方法,在实际开发中可能还需要暂停/恢复的操作,以及PCM转WAV的功能,下一篇再继续完善。
需要录音及文件处理的动态权限
作者:android_赵乐玮
链接:https://www.jianshu.com/p/a72deab95b4c