为了账号安全,请及时绑定邮箱和手机立即绑定

Android音频开发(2):使用AudioRecord录制pcm格式音频

一、AudioRecord类的介绍

  1. 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)
  2. getMinBufferSize()

    /**
    * 获取AudioRecord所需的最小缓冲区大小
    * @param sampleRateInHz: 采样率
    * @param channelConfig:声道数  
    * @param audioFormat: 采样位数.
    */public static int getMinBufferSize (int sampleRateInHz, 
                int channelConfig, 
                int audioFormat)
  3. getRecordingState()

    /**
    * 获取AudioRecord当前的录音状态 
    *   @see AudioRecord#RECORDSTATE_STOPPED    
    *   @see AudioRecord#RECORDSTATE_RECORDING
    */public int getRecordingState()
  4. startRecording()

     /**
     * 开始录制
     */
     public int startRecording()
  5. startRecording()

     /**
     * 停止录制
     */
     public int stop()
  6. 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


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消