今天我们介绍一下Android中录音的应用。我们在开发中经常有需要录音的场景,比如语音记录,聊天发送语音。这些情况下我们就要进行录音操作。那么今天我就给大家介绍一下在Android中如何进行录音。

1.媒体录制器MediaRecorder简介

MediaRecorder是Android自带的音频和视频录制工具,它通过操纵摄像头和麦克风完成媒体录制,既可录制视频,又可单独录制音频。

2.MediaRecorder常用方法(录音与录像通用)

  • reset:重置录制资源。
  • prepare:准备录制。
  • start:开始录制。
  • stop:结束录制。
  • release:释放录制资源。
  • setOnErrorListener:设置错误监听器。可监听服务器异常和未知错误的事件。需要实现接口MediaRecorder.OnErrorListener的onError方法。
  • setOnInfoListener:设置信息监听器。可监听录制结束事件,包括达到录制时长或达到录制大小。需要实现接口MediaRecorder.OnInfoListener的onInfo方法。
  • setMaxDuration:设置可录制的最大时长,单位毫秒。
  • setMaxFileSize:设置可录制的最大文件大小,单位字节。
  • setOutputFile:设置输出文件的路径。

3.MediaRecorder用于音频录制的方法

  • setAudioSource:设置音频来源。一般使用麦克风AudioSource.MIC。
  • setOutputFormat:设置媒体输出格式。媒体输出格式的取值说明见表1。

表1

OutputFormat类的输出格式

格式分类

扩展名

格式说明

AMR_NB

音频

.amr

窄带格式

AMR_WB

音频

.amr

宽带格式

AAC_ADTS

音频

.aac

高级的音频传输流格式

MPEG_4

视频

.mp4

MPEG4格式

THREE_GPP

视频

.3gp

3GP格式

  • setAudioEncoder:设置音频编码器。音频编码器的取值说明见表2。注意:该方法应在setOutputFormat方法之后执行,否则会出现setAudioEncoder called in an invalid state(2)的异常。

表2

AudioEncoder类的音频编码器

说明

AMR_NB

窄带编码

AMR_WB

宽带编码

AAC

低复杂度的高级编码

HE_AAC

高效率的高级编码

AAC_ELD

增强型低延时的高级编码

  • setAudioSamplingRate:设置音频的采样率,单位千赫兹(kHz)。AMR_NB格式默认8kHz,AMR_WB格式默认16kHz。
  • setAudioChannels:设置音频的声道数。1表示单声道,2表示双声道。
  • setAudioEncodingBitRate:设置音频每秒录制的字节数。数值越大音频越清晰。

4.音频录制示例

权限添加

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>

布局activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <TextView
        android:id="@+id/tv_record"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:text="录音"
        android:layout_centerInParent="true"
        android:background="@android:color/holo_green_light"
        android:gravity="center"/>
</RelativeLayout>

MainActivity.java

public class MainActivity extends WaterPermissionActivity implements MediaRecorder.OnErrorListener, MediaRecorder.OnInfoListener {

    private TextView tv_record;
    private MediaRecorder mMediaRecorder;
    private String voicePath;

    @Override
    protected MvcBaseModel getModelImp() {
        return null;
    }

    @Override
    protected int getContentLayoutId() {
        return R.layout.activity_main;
    }

    @Override
    protected void initWidget() {
        tv_record = findViewById(R.id.tv_record);
        tv_record.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_DOWN){
                    //开始录制
                    tv_record.setText("松开停止");
                    requestPermission(WRITE_EXTERNAL_STORAGE);
                }else if (event.getAction() == MotionEvent.ACTION_UP){
                    //结束录制
                    tv_record.setText("录音");
                    cancelRecord();
                }
                return true;
            }
        });
    }

    @Override
    protected void doSDWrite() {
        requestPermission(READ_EXTERNAL_STORAGE);
    }

    @Override
    protected void doSDRead() {
        requestPermission(RECORD);
    }

    @Override
    protected void doRecord() {
        getPath();
        startRecord();
    }

    /**
     * 录制前创建一个空文件并获取路径
     */
    private void getPath(){
        List<String> list = new ArrayList<>();
        list.add("record");
        String dirPath = PathGetUtil.getLongwayPath(this,list);
        File fileDir = new File(dirPath);
        if (!fileDir.exists()){
            fileDir.mkdirs();
        }
        File fileVoice = new File(dirPath,"voice"+System.currentTimeMillis()+".amr");
        if (!fileVoice.exists()){
            try {
                fileVoice.createNewFile();
                voicePath = fileVoice.getPath();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 开始录音
     */
    private void startRecord(){
        //开始录音操作
        mMediaRecorder = new MediaRecorder(); // 创建一个媒体录制器
        mMediaRecorder.setOnErrorListener(this); // 设置媒体录制器的错误监听器
        mMediaRecorder.setOnInfoListener(this); // 设置媒体录制器的信息监听器
        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); // 设置音频源为麦克风
        mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_NB); // 设置媒体的输出格式
        mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); // 设置媒体的音频编码器
        // mMediaRecorder.setAudioSamplingRate(8); // 设置媒体的音频采样率。可选
        // mMediaRecorder.setAudioChannels(2); // 设置媒体的音频声道数。可选
        // mMediaRecorder.setAudioEncodingBitRate(1024); // 设置音频每秒录制的字节数。可选
        mMediaRecorder.setMaxDuration(10 * 1000); // 设置媒体的最大录制时长
        // mMediaRecorder.setMaxFileSize(1024*1024*10); // 设置媒体的最大文件大小
        // setMaxFileSize与setMaxDuration设置其一即可
        mMediaRecorder.setOutputFile(voicePath); // 设置媒体文件的保存路径
        try {
            mMediaRecorder.prepare(); // 媒体录制器准备就绪
            mMediaRecorder.start(); // 媒体录制器开始录制
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 取消录制操作
    private void cancelRecord() {
        if (mMediaRecorder != null) {
            mMediaRecorder.setOnErrorListener(null); // 错误监听器置空
            mMediaRecorder.setPreviewDisplay(null); // 预览界面置空
            try {
                mMediaRecorder.stop(); // 媒体录制器停止录制
            } catch (Exception e) {
                e.printStackTrace();
            }
            mMediaRecorder.release(); // 媒体录制器释放资源
            mMediaRecorder = null;
        }
    }

    @Override
    public void onError(MediaRecorder mr, int what, int extra) {
        if (mr != null) {
            mr.reset(); // 重置媒体录制器
        }
    }

    @Override
    public void onInfo(MediaRecorder mr, int what, int extra) {
        // 录制达到最大时长,或者达到文件大小限制,都停止录制
        if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED
                || what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED) {
            cancelRecord();
        }
    }
}

老规矩,动态权限大家根据自身情况进行申请。触发开始录制是执行getPath()和startRecord()两个方法,一个是获取一个新的文件路径,用来放音频文件。另一个是开始真正的录制。停止录制调用cancelRecord()方法。其他处理可以按照示例代码中的进行配置。参数可以根据项目实际情况进行修改。