美文网首页
音频录制(一)

音频录制(一)

作者: 々志尚 | 来源:发表于2018-08-14 12:09 被阅读0次

    MediaRecorder.AudioSource音频参数说明

    MediaRecorder.AudioSource.MIC参数说明

    其中第一个参数就是选择录音源的,其可选参数如下:

    MediaRecorder.AudioSource.CAMCORDER   // 设定录音来源于同方向的相机麦克风相同,若相机无内置相机或无法识别,则使用预设的麦克风 MediaRecorder.AudioSource.DEFAULT  // 默认音频源
    MediaRecorder.AudioSource.MIC  // 设定录音来源为主麦克风。
    MediaRecorder.AudioSource.VOICE_CALL  // 设定录音来源为语音拨出的语音与对方说话的声音MediaRecorder.AudioSource.VOICE_COMMUNICATION  // 摄像头旁边的麦克风
    MediaRecorder.AudioSource.VOICE_DOWNLINK  // 下行声音
    MediaRecorder.AudioSource.VOICE_RECOGNITION  // 语音识别
    MediaRecorder.AudioSource.VOICE_UPLINK  // 上行声音

    音频的两种录制方式-AudioRecord,MediaRecorder的使用及播放

    AudioRecord和MediaRecorder两种都可以录制音频,MediaRecorder已实现大量的封装,操作起来更加简单,而AudioRecord使用起来更加灵活,能实现更多的功能。

    1.AudioRecord(基于字节流录音) 

    优点:可以实现语音的实时处理,进行边录边播,对音频的实时处理。 

    缺点:输出的是PCM的语音数据,如果保存成音频文件是不能被播放器播放的。要用到AudioTrack这个去进行处理。

    2.MediaRecorder(基于文件录音) 

    已集成了录音,编码,压缩等,支持少量的音频格式文件。 

    优点:封装度很高,操作简单 

    缺点:无法实现实时处理音频,输出的音频格式少。

    功能实现:MediaRecorder(这里需要注意,无论录制还是播放都是一个耗时操作,需要在非主线程中去操作)

    //实现触摸录音,松开录音结束tv_press_send.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    switch (event.getAction()) {
                        case MotionEvent.ACTION_DOWN:
                            startRecorder();
                            break;
                        case MotionEvent.ACTION_UP:
                            stopRecorder();
                            break;
                        case MotionEvent.ACTION_CANCEL:
                            break;
                        default:
                            break;
                    }
                    return true;
                }
            });

    开启一个单线程去实现录音功能,及失败操作:

    /**
         * 开启录音
         */
        private void startRecorder() {
            tv_press_send.setText("正在说话...");
            //提交后台任务,开始录音        mExecutorService.submit(new Runnable() {
                @Override
                public void run() {
                    //释放上一次的录音
                    releaseRecorder();
                    //开始录音
                    if (!doStart()) {
                        recorderFial();
                    }
                }
            });
        }

    启动录音,及MediaRecorder的配置:

    /**
     * 启动录音
     * * @return
    */
     private boolean doStart() {
            try {
                //创建MediaRecorder
                mMediaRecorder = new MediaRecorder();
                //创建录音文件
                mRecorderFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath()
                        + "/recorderdemo/" + System.currentTimeMillis() + ".m4a");

                if (!mRecorderFile.getParentFile().exists()) mRecorderFile.getParentFile().mkdirs();
                mRecorderFile.createNewFile();
                //配置MediaRecorder
                //从麦克风采集
                mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
                //保存文件为MP4格式
                mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
                //所有android系统都支持的适中采样的频率
                mMediaRecorder.setAudioSamplingRate(44100);
                //通用的AAC编码格式
                mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
                //设置音质频率
                mMediaRecorder.setAudioEncodingBitRate(96000);
                //设置文件录音的位置
                mMediaRecorder.setOutputFile(mRecorderFile.getAbsolutePath());
                //开始录音
                mMediaRecorder.prepare();
                mMediaRecorder.start();
                startRecorderTime = System.currentTimeMillis();
            } catch (Exception e) {
                Toast.makeText(FileActivity.this, "录音失败,请重试", Toast.LENGTH_SHORT).show();
                return false;
            }
            //记录开始录音时间,用于统计时长,小于3秒中,录音不发送        return true;
        }

    停止录音操作:

    /**
     * 关闭录音 *
     * @return*/
     private boolean doStop() {
            try {
                mMediaRecorder.stop();
                stopRecorderTime = System.currentTimeMillis();
                final int second = (int) (stopRecorderTime - startRecorderTime) / 1000;
                //按住时间小于3秒钟,算作录取失败,不进行发送
                if (second < 3) return false;
                mHander.post(new Runnable() {
                    @Override
                    public void run() {
                        tv_sendmsg.setText("录制成功:" + second + "秒");
                    }
                });
            } catch (Exception e) {
                e.printStackTrace();
            }
            return true;
        }

    释放MediaRecorder:

    /**
      * 释放上一次的录音
      */
        private void releaseRecorder() {
            if (mMediaRecorder != null) {
                mMediaRecorder.release();
                mMediaRecorder = null;
            }
        }

    录音的播放:使用MediaPlayer

    开启一个单线程,去播放:

    /**
     * 播放录音 *
     * @paramview
     */
     public void playrecorder(View view) {
            if (!mIsPlaying) {
                mExecutorService.submit(new Runnable() {
                    @Override
                    public void run() {
                        doPlay(mRecorderFile);
                    }
                });
            } else {
                Toast.makeText(FileActivity.this, "正在播放", Toast.LENGTH_SHORT).show();
            }
        }

    具体播放代码:

    private void doPlay(File audioFile) {
            try {
                //配置播放器 MediaPlayer
                mediaPlayer = new MediaPlayer();
                //设置声音文件
                mediaPlayer.setDataSource(audioFile.getAbsolutePath());
                //配置音量,中等音量
                mediaPlayer.setVolume(1,1);
                //播放是否循环
                mediaPlayer.setLooping(false);
                //设置监听回调 播放完毕
                mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                    @Override
                    public void onCompletion(MediaPlayer mp) {
                        stopPlayer();
                    }
                });
                mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
                    @Override
                    public boolean onError(MediaPlayer mp, int what, int extra) {
                        stopPlayer();
                        Toast.makeText(FileActivity.this,"播放失败",Toast.LENGTH_SHORT).show();
                        return true;
                    }
                });
                //设置播放
                mediaPlayer.prepare();
                mediaPlayer.start();
                //异常处理,防止闪退
            } catch (Exception e) {
                e.printStackTrace();
                stopPlayer();
            }
        }

    activity销毁后的onDestory的处理:

    @Override
     protected void onDestroy() {
            super.onDestroy();
            //当activity关闭时,停止这个线程,防止内存泄漏
            mExecutorService.shutdownNow();
            releaseRecorder();
        }

    MediaRecord完整功能实现代码:

    package com.example.amelon.myapplication;
    import android.media.MediaPlayer;
    import android.media.MediaRecorder;
    import android.os.Environment;
    import android.os.Handler;
    import android.os.Looper;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.view.MotionEvent;
    import android.view.View;
    import android.widget.TextView;
    import android.widget.Toast;
    import java.io.File;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;

    public classFileActivityextendsAppCompatActivity{

        private TextView tv_sendmsg, tv_press_send;
        private ExecutorService mExecutorService;
        private MediaRecorder mMediaRecorder;
        private MediaPlayer mediaPlayer;
        private File mRecorderFile;
        private long startRecorderTime, stopRecorderTime;
        private Handler mHander = new Handler(Looper.getMainLooper());
        private boolean mIsPlaying = false;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_first);
            setTitle("文件录音");
            initView();
            //录音JNI函数不具有线程安全性,因此用单线程        mExecutorService = Executors.newSingleThreadExecutor();
        }

        private void initView() {
            tv_sendmsg = (TextView) findViewById(R.id.tv_sendmsg);
            tv_press_send = (TextView) findViewById(R.id.tv_press_send);
            tv_press_send.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    switch (event.getAction()) {
                        case MotionEvent.ACTION_DOWN:
                            startRecorder();
                            break;
                        case MotionEvent.ACTION_UP:
                            stopRecorder();
                            break;
                        case MotionEvent.ACTION_CANCEL:
                            break;
                        default:
                            break;
                    }
                    return true;
                }
            });
        }

        /**
         * 开启录音
         */
        private void startRecorder() {
            tv_press_send.setText("正在说话...");
            //提交后台任务,开始录音
            mExecutorService.submit(new Runnable() {
                @Override
                public void run() {
                    //释放上一次的录音
                    releaseRecorder();
                    //开始录音
                    if (!doStart()) {
                        recorderFial();
                    }
                }
            });
        }

        /**
         * 释放上一次的录音
         */
        private void releaseRecorder() {
            if (mMediaRecorder != null) {
                mMediaRecorder.release();
                mMediaRecorder = null;
            }
        }

        /**
         * 启动录音    *
         * @return
         */
        private boolean doStart() {
            try {
                //创建MediaRecorder
                mMediaRecorder = new MediaRecorder();
                //创建录音文件
                mRecorderFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath()
                        + "/recorderdemo/" + System.currentTimeMillis() + ".m4a");

                if (!mRecorderFile.getParentFile().exists()) mRecorderFile.getParentFile().mkdirs();
                mRecorderFile.createNewFile();
                //配置MediaRecorder
                //从麦克风采集
                mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
                //保存文件为MP4格式
                mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
                //所有android系统都支持的适中采样的频率
                mMediaRecorder.setAudioSamplingRate(44100);
                //通用的AAC编码格式
                mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
                //设置音质频率
                mMediaRecorder.setAudioEncodingBitRate(96000);
                //设置文件录音的位置
                mMediaRecorder.setOutputFile(mRecorderFile.getAbsolutePath());
                //开始录音
                mMediaRecorder.prepare();
                mMediaRecorder.start();
                startRecorderTime = System.currentTimeMillis();
            } catch (Exception e) {
                Toast.makeText(FileActivity.this, "录音失败,请重试", Toast.LENGTH_SHORT).show();
                return false;
            }
            //记录开始录音时间,用于统计时长,小于3秒中,录音不发送        return true;
        }

        /**
         * 关闭录音    *
         * @return*/
        private boolean doStop() {
            try {
                mMediaRecorder.stop();
                stopRecorderTime = System.currentTimeMillis();
                final int second = (int) (stopRecorderTime - startRecorderTime) / 1000;
                //按住时间小于3秒钟,算作录取失败,不进行发送            if (second < 3) return false;
                mHander.post(new Runnable() {
                    @Override
                    public void run() {
                        tv_sendmsg.setText("录制成功:" + second + "秒");
                    }
                });
            } catch (Exception e) {
                e.printStackTrace();
            }
            return true;
        }

        /**
         * 录音失败逻辑
         */
        private void recorderFial() {
            mRecorderFile = null;
            mHander.post(new Runnable() {
                @Override            public void run() {
                    tv_press_send.setText("录音失败请重新录音");
                }
            });
        }

        /**
         * 停止录音
         */
        private void stopRecorder() {
            tv_press_send.setText("开始录音");
            //提交后台任务,停止录音
            mExecutorService.submit(new Runnable() {
                @Override
                public void run() {
                    if (!doStop()) {
                        recorderFial();
                    }
                    releaseRecorder();
                }
            });
        }

        /**
         * 播放录音    * 
        * @paramview
         */ 
       public void playrecorder(View view) {
            if (!mIsPlaying) {
                mExecutorService.submit(new Runnable() {
                    @Override
                    public void run() {
                        doPlay(mRecorderFile);
                    }
                });
            } else {
                Toast.makeText(FileActivity.this, "正在播放", Toast.LENGTH_SHORT).show();
            }
        }
        private void doPlay(File audioFile) {
            try {
                //配置播放器 MediaPlayer
                mediaPlayer = new MediaPlayer();
                //设置声音文件
                mediaPlayer.setDataSource(audioFile.getAbsolutePath());
                //配置音量,中等音量
                mediaPlayer.setVolume(1,1);
                //播放是否循环
                mediaPlayer.setLooping(false);
                //设置监听回调 播放完毕
                mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                    @Override
                    public void onCompletion(MediaPlayer mp) {
                        stopPlayer();
                    }
                });

                mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
                    @Override
                    public boolean onError(MediaPlayer mp, int what, int extra) {
                        stopPlayer();
                        Toast.makeText(FileActivity.this,"播放失败",Toast.LENGTH_SHORT).show();
                        return true;
                    }
                });

                //设置播放
                mediaPlayer.prepare();
                mediaPlayer.start();
                //异常处理,防止闪退
            } catch (Exception e) {
                e.printStackTrace();
                stopPlayer();
            }
        }

        private void stopPlayer(){
            mIsPlaying=false;
            mediaPlayer.release();
            mediaPlayer=null;
        }

        @Override
        protected void onDestroy() {
            super.onDestroy();
            //当activity关闭时,停止这个线程,防止内存泄漏
            mExecutorService.shutdownNow();
            releaseRecorder();
        }
    }

    xml布局文件:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/activity_first"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="vertical"
     android:padding="2dp"
     tools:context="com.example.amelon.myapplication.FileActivity">


    <Button
     android:onClick="playrecorder"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:text="播放"
     android:paddingLeft="3dp"
     android:paddingRight="3dp" />

    <TextView
     android:id="@+id/tv_sendmsg"
     android:layout_weight="8"
     android:layout_width="wrap_content"
     android:layout_height="0dp"
     android:layout_marginTop="30dp"
     android:onClick="filerecord"
     android:text="文件录音:" />

    < TextView
     android:id="@+id/tv_press_send"
     android:layout_width="match_parent"
     android:layout_weight="1"
     android:background="@android:color/darker_gray"
     android:gravity="center"
     android:layout_height="0dp"
     android:textSize="24sp"
     android:textColor="#70ffffff"
     android:paddingLeft="10dp"
     android:paddingRight="10dp"
     android:text="按下说话" />

    < /LinearLayout>

    AudioRecord的功能实现: 

    实现一个点击button进行录音,再次点击停止录音功能

    开启录音和停止录音:

    public void recorderaudio(View view) {
            if (mIsRecording) {
                bt_stream_recorder.setText("开始录音");
                //在开始录音中如果这个值没有变false,则一直进行,当再次点击变false时,录音才停止
                mIsRecording = false;
                //执行停止录音逻辑,这块不用下面代码,只需上面变换mIsRecording这个状态就可以了,下面一直走while
              /*  mExecutorService.submit(new Runnable() {
                    @Override
                    public void run() {
                        stopRecorder();
                    }
                });*/ 
           } else {
                bt_stream_recorder.setText("停止录音");
                //提交后台任务,执行录音逻辑
                mIsRecording = true;
                //提交后台任务,执行录音逻辑
                mExecutorService.submit(new Runnable() {
                    @Override
                    public void run() {
                        startRecorder();
                    }
                });
            }
        }

    开启录音:

    /**
         * 开始录音
         */
        private void startRecorder() {
            // realeseRecorder();
            if (!dostart()) recorderFail();
        }

    AudioRecord的配置及功能实现具体代码:

    private boolean dostart() {
            try {
                //记录开始录音时间
                startRecorderTime = System.currentTimeMillis();
                //创建录音文件
                mAudioRecordFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() +
                        "/recorderdemo/" + System.currentTimeMillis() + ".pcm");
                if (!mAudioRecordFile.getParentFile().exists())
                    mAudioRecordFile.getParentFile().mkdirs();
                mAudioRecordFile.createNewFile();
                //创建文件输出流
                mFileOutputStream = new FileOutputStream(mAudioRecordFile);
                //配置AudioRecord
                int audioSource = MediaRecorder.AudioSource.MIC;
                //所有android系统都支持
                int sampleRate = 44100;
                //单声道输入
                int channelConfig = AudioFormat.CHANNEL_IN_MONO;
                //PCM_16是所有android系统都支持的
                int autioFormat = AudioFormat.ENCODING_PCM_16BIT;
                //计算AudioRecord内部buffer最小
                int minBufferSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, autioFormat);
                //buffer不能小于最低要求,也不能小于我们每次我们读取的大小。
                mAudioRecord = new AudioRecord(audioSource, sampleRate, channelConfig, autioFormat, Math.max(minBufferSize, BUFFER_SIZE));
                //开始录音
                mAudioRecord.startRecording();
                //循环读取数据,写入输出流中
                while (mIsRecording) {
                    //只要还在录音就一直读取
                    int read = mAudioRecord.read(mBuffer, 0, BUFFER_SIZE);
                    if(read<=0){
                        return false;
                    }else {
                        mFileOutputStream.write(mBuffer, 0, read);
                    }
                }
                //退出循环,停止录音,释放资源
                stopRecorder();
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            } finally {
                if (mAudioRecord != null) {
                    mAudioRecord.release();
                }
            }
            return true;
        }

    再次点击停止录音操作代码:

    private boolean doStop() {
            //停止录音,关闭文件输出流
            mAudioRecord.stop();
            mAudioRecord.release();
            mAudioRecord = null;
            //记录结束时间,统计录音时长
            stopRecorderTime = System.currentTimeMillis();
            //大于3秒算成功,在主线程更新UI
            final int send = (int) (stopRecorderTime - startRecorderTime) / 1000;
            if (send > 3) {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        tv_stream_msg.setText("录音成功:" + send + "秒");
                        bt_stream_recorder.setText("开始录音");
                    }
                });
            } else {
                recorderFail();
                return false;
            }
            return true;
        }

    录取失败,更新UI操作:

    private boolean recorderFail() {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    bt_stream_recorder.setText("开始录音");
                    tv_stream_msg.setText("录取失败,请重新录入");
                    mIsRecording=false;
                    Log.i("Tag8", "go here111111111");
                }
            });
            return false;
        }

    播放录音代码:

    /** * 播放声音
     * @paramview
     */
     public void player(View view){
            mExecutorService.submit(new Runnable() {
                @Override
                public void run() {
                    if(!mIsPlaying){
                        Log.i("Tag8","go here");
                        mIsPlaying=true;
                        doPlay(mAudioRecordFile);
                    }
                }
            });
        }

    播放录音具体实现,AudioTrack的使用:

    private void doPlay(File audioFile) {
            if(audioFile !=null){
                Log.i("Tag8","go there");
                //配置播放器
                //音乐类型,扬声器播放
                int streamType= AudioManager.STREAM_MUSIC;
                //录音时采用的采样频率,所以播放时同样的采样频率
                int sampleRate=44100;
                //单声道,和录音时设置的一样
                int channelConfig=AudioFormat.CHANNEL_OUT_MONO;
                //录音时使用16bit,所以播放时同样采用该方式
                int audioFormat=AudioFormat.ENCODING_PCM_16BIT;
                //流模式
                int mode= AudioTrack.MODE_STREAM;
                //计算最小buffer大小
                int minBufferSize=AudioTrack.getMinBufferSize(sampleRate,channelConfig,audioFormat);
                //构造AudioTrack  不能小于AudioTrack的最低要求,也不能小于我们每次读的大小
                AudioTrack audioTrack=new AudioTrack(streamType,sampleRate,channelConfig,audioFormat,
                        Math.max(minBufferSize,BUFFER_SIZE),mode);
                //从文件流读数据
                FileInputStream inputStream=null;
                try{
                    //循环读数据,写到播放器去播放
                    inputStream=new FileInputStream(audioFile);
                    //循环读数据,写到播放器去播放
                    int read;
                    //只要没读完,循环播放
                    while ((read=inputStream.read(mBuffer))>0){
                        Log.i("Tag8","read:"+read);
                        int ret=audioTrack.write(mBuffer,0,read);
                        //检查write的返回值,处理错误
                        switch (ret){
                            case AudioTrack.ERROR_INVALID_OPERATION:
                            case AudioTrack.ERROR_BAD_VALUE:
                            case AudioManager.ERROR_DEAD_OBJECT:
                                playFail();
                                return;
                            default:
                                break;
                        }
                    }
                }catch (Exception e){
                    e.printStackTrace();
                    //读取失败
                    playFail();
                }finally {
                    mIsPlaying=false;
                    //关闭文件输入流 
                   if(inputStream !=null){
                        closeStream(inputStream);
                    }
                    //播放器释放
                    resetQuietly(audioTrack);
                }
            }
        }

    播放失败:更新UI操作

    /**
         * 播放失败
         */
        private void playFail() {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    tv_stream_msg.setText("播放失败");
                }
            });
        }

    activity销毁处理代码:

    //防止内存泄漏
    @Override protected void onDestroy() {
            super.onDestroy();
            if (mExecutorService != null) {
                mExecutorService.shutdownNow();
            }
            if (mAudioRecord != null) {
                mAudioRecord.stop();
                mAudioRecord.release();
                mAudioRecord = null;
            }
        }

    AudioRecord的功能实现完整代码:

    package com.example.amelon.myapplication;

    import android.media.AudioFormat;
    import android.media.AudioManager;
    import android.media.AudioRecord;
    import android.media.AudioTrack;
    import android.media.MediaRecorder;
    import android.os.Environment;
    import android.os.Handler;
    import android.os.Looper;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.util.Log;import android.view.View;
    import android.widget.Button;
    import android.widget.TextView;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;

    public classStreamActivityextendsAppCompatActivity{ private Button bt_stream_recorder;
        private TextView tv_stream_msg;
        private ExecutorService mExecutorService;
        private long startRecorderTime, stopRecorderTime;
        private volatile boolean mIsRecording = false;
        private AudioRecord mAudioRecord;
        private FileOutputStream mFileOutputStream;
        private File mAudioRecordFile;
        private byte[] mBuffer;
        //buffer值不能太大,避免OOM
        private static final int BUFFER_SIZE = 2048;
        private boolean mIsPlaying=false;
        private Handler mHandler = new Handler(Looper.getMainLooper());
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_stream);
            setTitle("字节流录音");
            initView();
            mExecutorService = Executors.newSingleThreadExecutor();
            mBuffer = new byte[BUFFER_SIZE];
        }

        private void initView() {
            bt_stream_recorder = (Button) findViewById(R.id.bt_stream_recorder);
            tv_stream_msg = (TextView) findViewById(R.id.tv_stream_msg);
        }

        public void recorderaudio(View view) {
            if (mIsRecording) {
                bt_stream_recorder.setText("开始录音");
                //在开始录音中如果这个值没有变false,则一直进行,当再次点击变false时,录音才停止
                mIsRecording = false;
                //执行停止录音逻辑,这块不用下面代码,只需上面变换mIsRecording这个状态就可以了,下面一直走while
              /*  mExecutorService.submit(new Runnable() {
                    @Override
                    public void run() {
                        stopRecorder();
                    }
                });*/
            } else {
                bt_stream_recorder.setText("停止录音");
                //提交后台任务,执行录音逻辑
                mIsRecording = true;
                //提交后台任务,执行录音逻辑
                mExecutorService.submit(new Runnable() {
                    @Override
                    public void run() {
                        startRecorder();
                    }
                });
            }
        }

        /**
         * 开始录音
         */
        private void startRecorder() {
            // realeseRecorder();
            if (!dostart()) recorderFail();
        }

        /**
         * 停止录音
         */
        private void stopRecorder() {
            mIsRecording=false;
            if (!doStop()) recorderFail();
        }
        private boolean dostart() {
            try {
                //记录开始录音时间
                startRecorderTime = System.currentTimeMillis();
                //创建录音文件
                mAudioRecordFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() +
                        "/recorderdemo/" + System.currentTimeMillis() + ".pcm");
                if (!mAudioRecordFile.getParentFile().exists())
                    mAudioRecordFile.getParentFile().mkdirs();
                mAudioRecordFile.createNewFile();
                //创建文件输出流
                mFileOutputStream = new FileOutputStream(mAudioRecordFile);
                //配置AudioRecord
                int audioSource = MediaRecorder.AudioSource.MIC;
                //所有android系统都支持
                int sampleRate = 44100;
                //单声道输入
                int channelConfig = AudioFormat.CHANNEL_IN_MONO;
                //PCM_16是所有android系统都支持的
                int autioFormat = AudioFormat.ENCODING_PCM_16BIT;
                //计算AudioRecord内部buffer最小
                int minBufferSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, autioFormat);
                //buffer不能小于最低要求,也不能小于我们每次我们读取的大小。
                mAudioRecord = new AudioRecord(audioSource, sampleRate, channelConfig, autioFormat, Math.max(minBufferSize, BUFFER_SIZE));
                //开始录音            mAudioRecord.startRecording();
                //循环读取数据,写入输出流中
                while (mIsRecording) {
                    //只要还在录音就一直读取
                    int read = mAudioRecord.read(mBuffer, 0, BUFFER_SIZE);
                    if(read<=0){
                        return false;
                    }else {
                        mFileOutputStream.write(mBuffer, 0, read);
                    }
                }
                //退出循环,停止录音,释放资源
                stopRecorder();
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            } finally {
                if (mAudioRecord != null) {
                    mAudioRecord.release();
                }
            }
            return true;
        }

        private boolean recorderFail() {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    bt_stream_recorder.setText("开始录音");
                    tv_stream_msg.setText("录取失败,请重新录入");
                    mIsRecording=false;
                    Log.i("Tag8", "go here111111111");
                }
            });
            return false;
        }

        private void realeseRecorder() {
            mAudioRecord.release();
        }

        private boolean doStop() {
            //停止录音,关闭文件输出流        mAudioRecord.stop();
            mAudioRecord.release();
            mAudioRecord = null;
            Log.i("Tag8", "go here");
            //记录结束时间,统计录音时长
            stopRecorderTime = System.currentTimeMillis();
            //大于3秒算成功,在主线程更新UI
            final int send = (int) (stopRecorderTime - startRecorderTime) / 1000;
            if (send > 3) {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        tv_stream_msg.setText("录音成功:" + send + "秒");
                        bt_stream_recorder.setText("开始录音");
                        Log.i("Tag8", "go there");
                    }
                });
            } else {
                recorderFail();
                return false;
            }
            return true;
        }

        /**
         * 播放声音
         * @paramview
         */
        public void player(View view){
            mExecutorService.submit(new Runnable() {
                @Override
                public void run() {
                    if(!mIsPlaying){
                        Log.i("Tag8","go here");
                        mIsPlaying=true;
                        doPlay(mAudioRecordFile);
                    }
                }
            });
        }

        private void doPlay(File audioFile) {
            if(audioFile !=null){
                Log.i("Tag8","go there");
                //配置播放器
                //音乐类型,扬声器播放
                int streamType= AudioManager.STREAM_MUSIC;
                //录音时采用的采样频率,所以播放时同样的采样频率
                int sampleRate=44100;
                //单声道,和录音时设置的一样
                int channelConfig=AudioFormat.CHANNEL_OUT_MONO;
                //录音时使用16bit,所以播放时同样采用该方式
                int audioFormat=AudioFormat.ENCODING_PCM_16BIT;
                //流模式
                int mode= AudioTrack.MODE_STREAM;
                //计算最小buffer大小
                int minBufferSize=AudioTrack.getMinBufferSize(sampleRate,channelConfig,audioFormat);
                //构造AudioTrack  不能小于AudioTrack的最低要求,也不能小于我们每次读的大小
                AudioTrack audioTrack=new AudioTrack(streamType,sampleRate,channelConfig,audioFormat,
                        Math.max(minBufferSize,BUFFER_SIZE),mode);
                //从文件流读数据            FileInputStream inputStream=null;
                try{
                    //循环读数据,写到播放器去播放
                    inputStream=new FileInputStream(audioFile);
                    //循环读数据,写到播放器去播放
                    int read;
                    //只要没读完,循环播放
                    while ((read=inputStream.read(mBuffer))>0){
                        Log.i("Tag8","read:"+read);
                        int ret=audioTrack.write(mBuffer,0,read);
                        //检查write的返回值,处理错误
                        switch (ret){
                            case AudioTrack.ERROR_INVALID_OPERATION:
                            case AudioTrack.ERROR_BAD_VALUE:
                            case AudioManager.ERROR_DEAD_OBJECT:
                                playFail();
                                return;
                            default:
                                break;
                        }
                    }
                }catch (Exception e){
                    e.printStackTrace();
                    //读取失败
                    playFail();
                }finally {
                    mIsPlaying=false;
                    //关闭文件输入流
                    if(inputStream !=null){
                        closeStream(inputStream);
                    }
                    //播放器释放
                    resetQuietly(audioTrack);
                }
                //循环读数据,写到播放器去播放
                //错误处理,防止闪退        }
        }
        /**
         * 关闭输入流
         * @paraminputStream
         */
        private void closeStream(FileInputStream inputStream){
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        private void resetQuietly(AudioTrack audioTrack){
            try{
                audioTrack.stop();
                audioTrack.release();
            }catch (Exception e){
                e.printStackTrace();
            }
        }

        /**
         * 播放失败
         */
        private void playFail() {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    tv_stream_msg.setText("播放失败");
                }
            });
        }

        @Override
        protected void onDestroy() {
            super.onDestroy();
            if (mExecutorService != null) {
                mExecutorService.shutdownNow();
            }
            if (mAudioRecord != null) {
                mAudioRecord.stop();
                mAudioRecord.release();
                mAudioRecord = null;
            }
        }
    }

    xml布局文件:

    <?xml version="1.0" encoding="utf-8"?>

    < LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/activity_stream"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:padding="2dp"
     android:orientation="vertical"
     tools:context="com.example.amelon.myapplication.StreamActivity">

    < LinearLayout
     android:layout_width="match_parent"
     android:layout_height="0dp"
     android:layout_weight="3"
     android:orientation="vertical" >

    < Button
     android:onClick="recorderaudio"
     android:id="@+id/bt_stream_recorder"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:background="#50000000"
     android:layout_margin="10dp"
     android:textSize="24sp"
     android:textColor="#fff"
     android:padding="10dp"
     android:text="开始录音" />

    < Button
     android:onClick="player"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:background="#50000000"
     android:layout_margin="10dp"
     android:textSize="24sp"
     android:textColor="#fff"
     android:padding="10dp"
     android:text="播 放" />

    < /LinearLayout>

    < TextView
     android:id="@+id/tv_stream_msg"
     android:layout_weight="7"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:textSize="24sp"
     android:padding="10dp"
     android:text="录音结果" />

    < /LinearLayout>

    相关文章

      网友评论

          本文标题:音频录制(一)

          本文链接:https://www.haomeiwen.com/subject/yavmbftx.html