录音的两种录音方式

File文件方式录音

public class FileActivity extends AppCompatActivity {
    private TextView mTvPressToSay;
    private TextView mTvLog,mPlay;

    private ExecutorService mExecutorService;
    private MediaRecorder mMediaRecorder;
    private File mAudioFile;
    private long mStartRecordTime,mStopRecordTime;

    private volatile boolean isPlaying;
    private MediaPlayer mMediaPlayer;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_file);
        mTvLog=findViewById(R.id.mTvLog);
        mTvPressToSay=findViewById(R.id.mTvPressToSay);
        mPlay=findViewById(R.id.mPlay);
        mPlay.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //检查当前播放状态 防止多次播放
                if (mAudioFile!=null&& !isPlaying){
                    //设置当前播放状态
                    isPlaying=true;
                    //播放在后台 提交一个后台任务
                    mExecutorService.submit(new Runnable() {
                        @Override
                        public void run() {
                            doPlay(mAudioFile);
                        }
                    });
                }
            }
        });
        //录音 JNI函数不具备线程安全性 所以要用单线程
        mExecutorService= Executors.newSingleThreadExecutor();

        //按下说话
        mTvPressToSay.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()){
                    case MotionEvent.ACTION_DOWN:
                        startRecord();
                    break;
                    case MotionEvent.ACTION_UP:
                    case MotionEvent.ACTION_CANCEL:
                        stopRecord();
                        break;
                }
                return true;
            }
        });
    }



    //开始录音
    public void startRecord(){
        mTvPressToSay.setText("正在说话");
        mExecutorService.submit(new Runnable() {
            @Override
            public void run() {
                //释放之前录音的 recorder
                releaseRecorder();

                //执行录音逻辑 如果失败提示用户
                if (!doStart()){
                    recordFail();
                }
            }
        });

    }

    //结束录音
    public void stopRecord(){
        mTvPressToSay.setText("按住说话");

        mExecutorService.submit(new Runnable() {
            @Override
            public void run() {
                //执行停止录音的逻辑
                if (!doStop()){
                    recordFail();
                }
                releaseRecorder();
            }
        });
    }

    //启动录音逻辑
    private boolean doStart() {
        try {
            //创建一个MediaRecorder
            mMediaRecorder=new MediaRecorder();
            //创建录音文件
            mAudioFile=new File(Environment.getExternalStorageDirectory().getAbsolutePath()
                    +"/iMoocDemo/"+System.currentTimeMillis()+".m4a");
            mAudioFile.getParentFile().mkdirs();
            mAudioFile.createNewFile();

            //配置MeDiaRecorder
            //从麦克风采集
            mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
            //保存文件为MP4
            mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
            //所有安卓系统都支持的才采样频率
            mMediaRecorder.setAudioSamplingRate(44100);
            //通用的aac编码格式
            mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
            //音质比较好的频率
            mMediaRecorder.setAudioEncodingBitRate(96000);
            //设置录音文件位置
            mMediaRecorder.setOutputFile(mAudioFile.getAbsolutePath());

            //开始录音
            mMediaRecorder.prepare();
            mMediaRecorder.start();
            mStartRecordTime=System.currentTimeMillis();

            //记录开始录音的时间,用于统计时常
        } catch (IOException|RuntimeException e) {
            e.printStackTrace();
            return false;
        }


        return true;
    }

    //释放mediaRecorder
    private void releaseRecorder() {
        if (mMediaRecorder!=null){
            mMediaRecorder.release();
            mMediaRecorder=null;
        }

    }

    //录音错误的处理
    private void recordFail() {
        mAudioFile=null;
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(FileActivity.this, "录制失败", Toast.LENGTH_SHORT).show();
            }
        });

    }

    //停止录音逻辑
    private boolean doStop() {
        try {
            //停止录音

            mMediaRecorder.stop();
            //记录停止时间 统计时长
            mStopRecordTime=System.currentTimeMillis();
            //只接受超过3秒的录音 在ui上显示出来
            final int second= (int) ((mStopRecordTime-mStartRecordTime)/1000);
            if (second>3){
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        mTvLog.setText(mTvLog.getText()+"\n 录音成功"+second+"秒");
                    }
                });
            }
        }catch (RuntimeException e){
            e.printStackTrace();
        }


        return true;
    }

    //
    private void doPlay(File mAudioFile) {
        //配置播放器 mediaplayer
        mMediaPlayer=new MediaPlayer();

        try {
            //设置声音文件
            mMediaPlayer.setDataSource(mAudioFile.getAbsolutePath());
            //设置监听回调
            mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                @Override
                public void onCompletion(MediaPlayer mp) {
                    //播放接收 释放播放器
                    stopPlay();
                }
            });

            mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
                @Override
                public boolean onError(MediaPlayer mp, int what, int extra) {
                    //提示用户
                    playFail();
                    //释放播放器
                    stopPlay();
                    //错误自己处理
                    return true;
                }
            });

            //配置音量 是否循环
            mMediaPlayer.setVolume(1,1);
            mMediaPlayer.setLooping(false);
            //准备开始
            mMediaPlayer.prepare();
            mMediaPlayer.start();
        }catch (IOException|RuntimeException e){
            e.printStackTrace();
            //提醒用户
            playFail();

            //释放播放器
            stopPlay();
        }
        //异常处理 防止闪退
    }

    //提示用户播放失败
    private void playFail(){
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(FileActivity.this, "播放失败", Toast.LENGTH_SHORT).show();
            }
        });
    }



    //停止播放逻辑
    private void stopPlay(){
        //重置播放状态
        isPlaying=false;
        //释放播放器
        if (mMediaPlayer!=null){
            //重置我们的监听器防止内存泄漏
            mMediaPlayer.setOnErrorListener(null);
            mMediaPlayer.setOnCompletionListener(null);
            mMediaPlayer.stop();
            mMediaPlayer.reset();
            mMediaPlayer.release();
            mMediaPlayer=null;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mExecutorService.shutdownNow();
        releaseRecorder();
        stopPlay();
    }
}

字节流录音模式

public class StreamActivity extends AppCompatActivity {
    private TextView mStart;
    private TextView mTvLog,mPlay;

    //volatile 保证多线程内存同步
    private volatile boolean mIsRecording,isPlaying;
    private ExecutorService mExecutorService;
    private File mAudioFile;
    private long mStartRecordTime,mStopRecordTime;
    //buffer不能太大秒oom
    private static final int BUFFER_SIZE=2024;
    private byte[] mBuffer;
    private FileOutputStream mFileOutputStream;
    private AudioRecord mAudioRecord;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_stream);
        mTvLog=findViewById(R.id.mTvLog);
        mStart=findViewById(R.id.mStart);
        //录音 JNI函数不具备线程安全性 所以要用单线程
        mExecutorService= Executors.newSingleThreadExecutor();
        mBuffer=new byte[BUFFER_SIZE];
        mPlay=findViewById(R.id.mPlay);
        mPlay.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //检查当前播放状态 防止多次播放
                if (mAudioFile!=null&& !isPlaying){
                    //设置当前播放状态
                    isPlaying=true;
                    //播放在后台 提交一个后台任务
                    mExecutorService.submit(new Runnable() {
                        @Override
                        public void run() {
                            doPlay(mAudioFile);
                        }
                    });
                }
            }
        });
        mStart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mIsRecording){
                    mStart.setText("开始录音");
                    mIsRecording=false;
                }else{
                    mStart.setText("结束录音");
                    //提价一个后台任务开始录音
                    mIsRecording=true;
                    mExecutorService.submit(new Runnable() {
                        @Override
                        public void run() {
                            if (!startRecord()){
                                recodFail();
                            }
                        }
                    });

                }
            }
        });
    }


    private boolean startRecord() {
        try {
            //创建录音文件
            mAudioFile=new File(Environment.getExternalStorageDirectory().getAbsolutePath()
                    +"/iMoocDemo/"+System.currentTimeMillis()+".pcm");
            mAudioFile.getParentFile().mkdirs();
            mAudioFile.createNewFile();
            //创建文件输出流
            mFileOutputStream=new FileOutputStream(mAudioFile);
            //配置Audiorecord
            //从麦克风采集
            int audioSource= MediaRecorder.AudioSource.MIC;
            int sampleRate=44100;//所有安卓系统都支持的频率
            //单声道输入
            int chanelConfig= AudioFormat.CHANNEL_IN_MONO;
            //pcm16是所有安卓系统都支持
            int audioFormat=AudioFormat.ENCODING_PCM_16BIT;
            //计算AudioRecord 内部 buffer最小缓冲区的大小
            int minBufferSize= AudioRecord.getMinBufferSize(sampleRate,chanelConfig,audioFormat);
            //buffer 不能小于最低要求也不能小于我们每次读取的大小
            mAudioRecord=new AudioRecord(audioSource,sampleRate
                    ,chanelConfig,audioFormat,Math.max(minBufferSize,BUFFER_SIZE));

            //开始录音
            mAudioRecord.startRecording();
            //记录开始录音时间 统计时常
            mStartRecordTime=System.currentTimeMillis();
            //循环读取数据 写到输出流中
            while (mIsRecording){
                //只要还在录音状态 ,就一直读取数据
                int read=mAudioRecord.read(mBuffer,0,BUFFER_SIZE);
                if (read>0){
                    //读取成功
                    mFileOutputStream.write(mBuffer,0,read);
                }else{
                    //读取失败,返回false 提示用户
                    return false;
                }
            }
            //退出循环,停止录音释放资源
            return stopRecord();
        }catch (IOException|RuntimeException e){
            e.printStackTrace();
            return false;
        }finally {
            //释放audioRecord资源
            if (mAudioRecord!=null){
                mAudioRecord.release();
            }
        }

    }

    //
    private boolean stopRecord() {
        try {
            //停止录音 关闭文件输出流
            mAudioRecord.stop();
            mAudioRecord.release();
            mAudioRecord=null;
            mFileOutputStream.close();
            //记录当前时间 大于3秒
            mStopRecordTime=System.currentTimeMillis();
            final int second= (int) ((mStopRecordTime-mStartRecordTime)/1000);
            if (second>3){
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        mTvLog.setText(mTvLog.getText()+"\n 录音成功"+second+"秒");
                    }
                });
            }
        }catch (IOException e){
            e.printStackTrace();
            return false;
        }
        return true;
    }

    private void recodFail() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(StreamActivity.this, "录音失败", Toast.LENGTH_SHORT).show();
                //重置录音状态 以及ui状态
                mIsRecording=false;
                mStart.setText("开始录音");
            }
        });
    }


    private void doPlay(File audioFile) {
        //配置播放器
        //音乐类型 扬声器播放
        int streamType= AudioManager.STREAM_MUSIC;
        //录音时采用的采样频率,所以播放时候使用同样的采样频率
        int sampleRate=44100;
        //mono 表示单声道 录音输入单声道,播放输出单声道
        int chanelConfig=AudioFormat.CHANNEL_OUT_MONO;
        //录音时使用16bit 所以播放时同样的格式
        int audioFormat=AudioFormat.ENCODING_PCM_16BIT;
        //流模式
        int mode= AudioTrack.MODE_STREAM;


        int minBufferSize=AudioTrack.getMinBufferSize(sampleRate,chanelConfig,audioFormat);

        //构造audioTrack
        AudioTrack audioTrack=new AudioTrack(streamType,sampleRate,
                chanelConfig,audioFormat,Math.max(minBufferSize,BUFFER_SIZE),mode);
        audioTrack.play();

        //从文件流读取数据
        FileInputStream inputStream=null;
        try {
            inputStream=new FileInputStream(audioFile);
            //循环读取数据写到播放器去播放
            int read;
            while ((read=inputStream.read(mBuffer))>0){
                int ret=audioTrack.write(mBuffer,0,read);
                //检查write返回值 错误处理
                switch (ret){
                    case AudioTrack.ERROR_INVALID_OPERATION:
                    case AudioTrack.ERROR_BAD_VALUE:
                    case AudioTrack.ERROR_DEAD_OBJECT:
                        playFail();
                        return;
                }
            }
            //错误处理防止闪退

        }catch (RuntimeException |IOException e){
            e.printStackTrace();
            playFail();
        }finally {
            isPlaying=false;
            if (inputStream!=null){
                closeQuietly(inputStream);
            }

            resetQuietly(audioTrack);
        }


    }

    private void resetQuietly(AudioTrack audioTrack) {
        try {
            //播放器释放
            audioTrack.stop();
            audioTrack.release();
        }catch (Exception e){
            e.printStackTrace();
        }

    }

    private void closeQuietly(FileInputStream inputStream) {
        try {
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void playFail() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(StreamActivity.this, "播放失败", Toast.LENGTH_SHORT).show();
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mExecutorService.shutdownNow();
    }
}

 

你可能感兴趣的:(技术)