安卓实现录音机的录音功能

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq77485042/article/details/78416935

最近项目中需要做一个录音机的功能,就去研究了一下,安卓中使用录音功能使用的是MediaRecorder类,这个类在android.media包下。
该类的使用方法和MediaPlayer非常相似。

首先先初始化:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_VIDEO" />
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
在清单文件中添加上以上权限

MediaRecorder mRecorder = new MediaRecorder();
//将mRecorder设置成空闲状态
mRecorder.reset();
//设置要用于录制的音频源。 如果没有这个方法调用,输出文件不会包含音轨。(注意该方法必须在setOutputFormat()方法之前)
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
//设置录制时产生的输出文件的格式。(该方法不能再prepare()方法之后调用,不然会抛出IllegalStateException异常)
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);
//设置要生成的输出文件的路径。(简单的说就是生成一个什么文件名,放在哪里)
mRecorder.setOutputFile(mFileName);
//我这里的mFileName
mFileName = getExternalCacheDir().getAbsolutePath();
mFileName += "/" + System.currentTimeMillis();
//找到绝对路径,文件名取名为系统当前时间。(这里注意调用setOutputFile()方法一定要在setOutputFormat()方法之后,在prepare()之前);
//设置完路径之后调用该方法
//设置要用于录制的音频编码器。 如果没有这个方法调用,输出文件不会包含音轨。
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
//准备录音机开始捕获和编码数据。(也就是准备状态)这里需要try catch一个IOException。
mRecorder.prepare();
//开始录音
mRecorder.start();

以上就是录音的全部代码,具体的内容注释已经也已经写得很清楚了。
调用了start方法只后就会看到在该路径下生成了一个不断变大的文件,因为你录的时间越长,当然文件肯定也就越大了。
打开DDMS试图:

这里写图片描述
我这里开始了6次,所以就生成了6个文件。

停止的话,调用stop()方法,
    release()方法是用来释放掉mRecorder的一切资源,为了不浪费内存。
    if (mRecorder != null) {
    mRecorder.stop();
    mRecorder.release();
    mRecorder = null;
    }

调用了stop()方法后又重新调用start()方法会发现又生成了一个新的文件。

当然我们做录音机功能肯定是需要暂停的,怎么办呢???
我们找会发现有个pause()方法,如果需要暂停的

//顾名思义这方法就是暂停的意思,当然需要在调用了start();方法之后调用。
mRecorder.pause();

暂停了之后想要接着录的话怎么办呢???
我们会发现又有个mRecorder.resume();方法。

//该方法也就是重新开始了意思,在调用了pause()方法后调用,如果在start()方法后调用,也没什么关系,只是不会有效果
mRecorder.resume();

以为到这里就完了吧???NO NO NO,你会发现暂停这里有个大坑,因为pause()方法是在API 25(安卓版本7.1.1)的时候才出来的,而resume()方法是在API 19(安卓版本4.4)的时候出来的,如果我们的程序需要向下兼容的话怎么办呢,这个暂停的功能不就没法实现了。(但是,你会发现在7.1.1之前也有暂停的功能的)他们是如何做到的呢???

当然他们肯定也不是因为能提前用API,他们也是点击了暂停之后调用stop();方法,每次点击开始的时候都生成了一个新的文件,只不过他们把那些录音文件拼接起来当你点击保存的时候拼接成了一个录音文件而已。

首先先创建一个集合用来装每段录音文件的路径

private ArrayList<String> list = new ArrayList<>();

每次点击开始的时候把文件路径add进集合中(也就是上面的mFileName)
因为每次点击开始的时候都给新的文件取当前的时间的毫秒值,所以不会出现文件名重复而覆盖掉的情况。

mFileName = getExternalCacheDir().getAbsolutePath();
                mFileName += "/" + System.currentTimeMillis();
                list.add(mFileName);
                startRecording();

    /**
     * 开始录音
     */
    private void startRecording() {
        if (mRecorder == null) {
            mRecorder = new MediaRecorder();
        }
        mRecorder.reset();
        mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        mRecorder.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);
        mRecorder.setOutputFile(mFileName);
        mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
        try {
            mRecorder.prepare();
        } catch (IOException e) {
            Log.e(TAG, e.toString());
        }
        mRecorder.start();
    }

当你点击保存的时候呢,只需要把list集合给传入以下方法中。

//第一个参数就是list集合,第二个参数就是合并后的文件名
public void getInputCollection(List list, String mMinute1) {

        // 创建音频文件,合并的文件放这里
        file1 = new File(getExternalCacheDir().getAbsolutePath(), mMinute1);
        FileOutputStream fileOutputStream = null;

        if (!file1.exists()) {
            try {
                file1.createNewFile();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        try {
            fileOutputStream = new FileOutputStream(file1);

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //list里面为暂停录音 所产生的 几段录音文件的名字,中间几段文件的减去前面的6个字节头文件
        for (int i = 0; i < list.size(); i++) {
            File file = new File((String) list.get(i));
            Log.d("list的长度", list.size() + "");
            try {
                FileInputStream fileInputStream = new FileInputStream(file);
                byte[] myByte = new byte[fileInputStream.available()];
                //文件长度
                int length = myByte.length;

                //头文件
                if (i == 0) {
                    while (fileInputStream.read(myByte) != -1) {
                        fileOutputStream.write(myByte, 0, length);
                    }
                }

                //之后的文件,去掉头文件就可以了
                else {
                    while (fileInputStream.read(myByte) != -1) {

                        fileOutputStream.write(myByte, 6, length - 6);
                    }
                }

                fileOutputStream.flush();
                fileInputStream.close();
                System.out.println("合成文件长度:" + file1.length());

            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }


        }
        //结束后关闭流
        try {
            fileOutputStream.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //千万记住这里需要把集合给清空不然,下次录的时候会把上次录的给带上了
        deleteListRecord();
    }

    /**
     * 合成一个文件后,删除之前暂停录音所保存的零碎合成文件
     */
    private void deleteListRecord() {
        for (int i = 0; i < list.size(); i++) {
            File file = new File(list.get(i));
            if (file.exists()) {
                file.delete();
            }
        }
        //正在暂停后,继续录音的这一段音频文件
    }

这样你就会发现在该路径下新生成了一个录音文件,该录音文件就是你合并后想要的文件。
(如有错误,及时提出修改。谢谢!!!)

猜你喜欢

转载自blog.csdn.net/qq77485042/article/details/78416935