安卓AudioRecord实现录音和播放,可以暂停和获取声音的大小,格式为amr和wav,可以对音频进行加密

最近项目要求做一个录音功能,要可以暂停的,然后对音频进行加密解密,还要根据声音大小做一个自定义的柱形图,废话不多说,下面进行录音功能实现:

项目大概长这样:

 

设计的思路:
由于自带的AudioRecord没有pauseRecord()方法,我把开始录音-->(暂停/继续录音)...-->停止录音叫做一次录音,点击一次暂停就会产生一个文件(.pcm),再点击的时候对文件进行继续写入。

 

对类的说明:

  1. AudioRecorder:封装了录音的方法:创建录音对象、开始、暂停、停止、取消,使用静态枚举类Status来记录录音的状态。
  2. AudioFileUtils:文件工具类,用于文件路径的获取
  3. AudioEncoder:对文件进行转码的父类,采用mvp模式,具体实现看子类的
  4. AmrEncoder:继承AudioEncoder,实现父类的转码方法,amr格式。
  5. WavEncoder:继承AudioEncoder,实现父类的转码方法,wav格式。
  6. WaveHeader: wav文件头
  7. onVoluneListener:监听录音分贝大小,用于拓展业务的处理。
  8. RecordService:将录音功能集成封装在服务里面,暴露几个方法调用的接口
  9. AESUtils:用aes对音频文件进行加解密,提高用户信息的安全性。

开始之前记得添加权限:

 <!-- 获取手机录音机使用权限,听写、识别、语义理解需要用到此权限 -->
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <!-- 假如我们要保存录音,还需要以下权限 -->
    <!-- 在SDCard中创建与删除文件权限 -->
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
    <!-- SD卡权限 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />

 

接下来就是关键代码:

1、AudioRecorder类:

package com.zqr.snake.mytest.record3;

import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.text.TextUtils;
import android.util.Log;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class AudioRecorder {
    private static final String TAG = "AudioRecorder";
    private int audioInput = MediaRecorder.AudioSource.MIC;//来源
    private int audioSampleRate = 8000;//频率
    private int audioChannel = AudioFormat.CHANNEL_IN_MONO;//声道
    private int audioEncode = AudioFormat.ENCODING_PCM_16BIT;//编码样式

    private int bufferSizeInBytes = 0;
    private AudioRecord audioRecord;
    private Status status = Status.STATUS_NO_READY;
    protected String pcmFileName;

    private Timer timer;

    private TimerTask timerTask;
    private int currentPosition = 0;
    private CallBack callBack;
    private int lastVolumn = 0;//录音的分贝
    private AudioEncoder encoder;//编码格式

    public AudioRecorder(CallBack callBack, AudioEncoder encoder) {
        String fileName = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
        pcmFileName = AudioFileUtils.getPcmFileAbsolutePath(fileName);
        this.encoder = encoder;

//        encoder.init(audioSampleRate, 16, 1);
        File file = new File(pcmFileName);
        if (file.exists()) {
            file.delete();
        }
        status = Status.STATUS_READY;
        this.callBack = callBack;
    }


    public void setAudioInput(int audioInput) {
        this.audioInput = audioInput;
    }

    public void setAudioSampleRate(int audioSampleRate) {
        this.audioSampleRate = audioSampleRate;
    }

    public void setAudioChannel(int audioChannel) {
        this.audioChannel = audioChannel;
    }


    public void setEncoder(AudioEncoder encoder) {
        this.encoder = encoder;
    }

    private void startTimer() {
        if (timer == null)
            timer = new Timer();
        if (timerTask != null) {
            timerTask.cancel();
        }
        timerTask = new TimerTask() {
            @Override
            public void run() {
                currentPosition++;
                if (callBack != null && status == Status.STATUS_START) {
                    callBack.recordProgress(currentPosition);
                    callBack.volumn(lastVolumn);
                }

            }
        };
        timer.schedule(timerTask, 0, 100);
    }

    private void stopTimer() {
        if (timer != null) {
            timer.cancel();
            timer = null;
        }
        if (timerTask != null) {
            timerTask.cancel();
            timerTask = null;
        }
    }

    public void startRecord() {

        bufferSizeInBytes = AudioRecord.getMinBufferSize(audioSampleRate,
                audioChannel, audioEncode);
        audioRecord = new AudioRecord(audioInput, audioSampleRate, audioChannel, audioEncode, bufferSizeInBytes);
        if (status == Status.STATUS_NO_READY) {
            return;
//            throw new IllegalStateException("not init");
        }
        if (status == Status.STATUS_START) {
            return;
//            throw new IllegalStateException("is recording ");
        }
        Log.d("AudioRecorder2", "===startRecord===" + audioRecord.getState());
        audioRecord.startRecording();

        new Thread(new Runnable() {
            @Override
            public void run() {
                recordToFile();
            }
        }).start();
        startTimer();
    }

    public void stop() {
        currentPosition = 0;
        if (status != Status.STATUS_START && status != Status.STATUS_PAUSE) {
            return;
//            throw new IllegalStateException("not recording");
        } else {
            stopRecorder();
            makeDestFile();
            status = Status.STATUS_READY;
        }
    }


    //文件进行转码
    private void makeDestFile() {
        if (encoder == null)
            return;
        new Thread() {
            @Override
            public void run() {
                encoder.init(audioSampleRate, audioSampleRate * 16 * audioRecord.getChannelCount(), audioRecord.getChannelCount());
                encoder.encode(pcmFileName);
                releaseRecorder();
            }
        }.run();
    }

    /**
     * 取消录音
     */
    public void release() {
        Log.d("AudioRecorder2", "===release===");
        stopRecorder();
        releaseRecorder();
        status = Status.STATUS_READY;
        clearFiles();
    }

   //释放资源
    private void releaseRecorder() {

        if (audioRecord != null) {
            audioRecord.release();
            audioRecord = null;
        }
    }

    //停止录音
    private void stopRecorder() {
        stopTimer();
        if (audioRecord != null) {
            try {
                audioRecord.stop();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 清除文件
     */
    public void clearFiles() {
        try {
        File pcmfile = new File(pcmFileName);
        if (pcmfile.exists())
            pcmfile.delete();

        if (encoder != null && !TextUtils.isEmpty(encoder.getDestFile())) {
            File file = new File(encoder.getDestFile());
            if (file.exists())
                file.delete();
        }
        }catch (Exception e){
            e.printStackTrace();
        }

    }

    //将音频写入文件
    private void recordToFile() {
        byte[] audiodata = new byte[bufferSizeInBytes];
        FileOutputStream fos = null;
        int readsize = 0;
        try {
            fos = new FileOutputStream(pcmFileName, true);
        } catch (FileNotFoundException e) {
            Log.e("AudioRecorder", e.getMessage());
        }
        status = Status.STATUS_START;
        while (status == Status.STATUS_START && audioRecord != null) {
            readsize = audioRecord.read(audiodata, 0, bufferSizeInBytes);
            if (AudioRecord.ERROR_INVALID_OPERATION != readsize && fos != null) {
                try {
                    //get the volumn  1--10
                    int sum = 0;
                    for (int i = 0; i < readsize; i++) {
                        sum += Math.abs(audiodata[i]);
                    }

                    if (readsize > 0) {
                        int raw = sum / readsize;
                        lastVolumn = raw > 10 ? raw - 10 : 0;
                        Log.i(TAG, "writeDataTOFile: volumn -- " + raw + " / lastvolumn -- " + lastVolumn);
                    }
                    if (readsize > 0 && readsize <= audiodata.length)
                        fos.write(audiodata, 0, readsize);
                } catch (IOException e) {
                    Log.e("AudioRecorder", e.getMessage());
                }
            }
        }
        try {
            if (fos != null) {
                fos.close();
            }
        } catch (IOException e) {
            Log.e("AudioRecorder", e.getMessage());
        }
    }

    public int getCurrentPosition() {
        return currentPosition;
    }


    /**
     * 获取当前的录音状态
     * @return
     */
    public Status getStatus() {
        return status;
    }

    /**
     * 获取当前的录音文件的位置
     * @return
     */
    public String getVoiceFilePath() {
        return encoder == null ? pcmFileName : encoder.getDestFile();
    }

    /**
     * 录音的状态
     */
    public enum Status {
        STATUS_NO_READY,
        STATUS_READY,
        STATUS_START,
        STATUS_PAUSE,
        STATUS_STOP
    }

    public interface CallBack {
        public void recordProgress(int progress);

        public void volumn(int volumn);
    }





    /**
     * 暂停录音
     */
    public void pauseRecord() {
        Log.d("AudioRecorder2","===pauseRecord===");
        if (status != Status.STATUS_START) {
            throw new IllegalStateException("没有在录音");
        } else {
            stopRecorder();
//            audioRecord.stop();
            status = Status.STATUS_PAUSE;
        }
    }



}

 

 

2.AudioEncoder类:

 

package com.zqr.snake.mytest.record3;

import android.annotation.TargetApi;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.os.Build;
import android.support.annotation.NonNull;

import java.io.IOException;

/**
 * 
 */

public abstract class AudioEncoder {
    protected int SAMPLE_RATE = 8000;
    protected int BIT_RATE = 64;
    protected int CHANNEL_COUNT = 1;
    protected String destinationFile;

    public void init(int SAMPLE_RATE, int BIT_RATE, int CHANNEL_COUNT) {
        this.SAMPLE_RATE = SAMPLE_RATE;
        this.BIT_RATE = BIT_RATE;
        this.CHANNEL_COUNT = CHANNEL_COUNT;
    }

    public String getDestFile() {
        return destinationFile;
    }


    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    @NonNull
    protected MediaFormat getMediaFormat(String sourceFile) throws IOException {
        MediaExtractor mex = new MediaExtractor();
        mex.setDataSource(sourceFile);
        return mex.getTrackFormat(0);
    }
    public abstract void encode(String sourceFile);



}

3.AmrEncoder(这里我只分享amr的类)

 

 

package com.zqr.snake.mytest.record3;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.media.MediaCodec;
import android.media.MediaFormat;
import android.os.Build;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 
 */

public class AmrEncoder extends AudioEncoder {

    private static byte[] header = new byte[]{'#', '!', 'A', 'M', 'R', '\n'};





    @Override
    public void init(int SAMPLE_RATE, int BIT_RATE, int CHANNEL_COUNT) {
        super.init(SAMPLE_RATE, BIT_RATE, CHANNEL_COUNT);
        String fileName = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
        destinationFile = AudioFileUtils.getAmrFileAbsolutePath(fileName);
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    @SuppressLint("WrongConstant")
    @Override
    public void encode(String sourceFile) {
        try {
            MediaCodec encoder = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_AUDIO_AMR_NB);
            MediaFormat format = new MediaFormat();
            format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_AUDIO_AMR_NB);
            format.setInteger(MediaFormat.KEY_SAMPLE_RATE, SAMPLE_RATE);
            format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, CHANNEL_COUNT);
            format.setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE);


            encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
            File pcmFile = new File(sourceFile);
            FileInputStream fis = new FileInputStream(pcmFile);
            File armFIle = new File(destinationFile);
            FileOutputStream fos = new FileOutputStream(armFIle);
            fos.write(header);
            encoder.start();

            ByteBuffer[] codecInputBuffers = encoder.getInputBuffers();
            ByteBuffer[] codecOutputBuffers = encoder.getOutputBuffers();
            byte[] tempBuffer = new byte[88200];
            boolean hasMoreData = true;
            MediaCodec.BufferInfo outBuffInfo = new MediaCodec.BufferInfo();
            double presentationTimeUs = 0;
            int totalBytesRead = 0;
            do {
                int inputBufIndex = 0;
                while (inputBufIndex != -1 && hasMoreData) {
                    inputBufIndex = encoder.dequeueInputBuffer(0);

                    if (inputBufIndex >= 0) {
                        ByteBuffer dstBuf = codecInputBuffers[inputBufIndex];
                        dstBuf.clear();


                        int bytesRead = fis.read(tempBuffer, 0, dstBuf.limit());
                        if (bytesRead == -1) { // -1 implies EOS
                            hasMoreData = false;
                            encoder.queueInputBuffer(inputBufIndex, 0, 0, (long) presentationTimeUs, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
                        } else {
                            totalBytesRead += bytesRead;
                            dstBuf.put(tempBuffer, 0, bytesRead);
                            encoder.queueInputBuffer(inputBufIndex, 0, bytesRead, (long) presentationTimeUs, 0);
                            presentationTimeUs = 1000000l * (totalBytesRead / 2) / SAMPLE_RATE;
                        }
                    }
                }
                // Drain audio
                int outputBufIndex = 0;
                while (outputBufIndex != MediaCodec.INFO_TRY_AGAIN_LATER) {
                    outputBufIndex = encoder.dequeueOutputBuffer(outBuffInfo, 0);
                    if (outputBufIndex >= 0) {
                        ByteBuffer encodedData = codecOutputBuffers[outputBufIndex];
                        encodedData.position(outBuffInfo.offset);
                        encodedData.limit(outBuffInfo.offset + outBuffInfo.size);
                        byte[] outData = new byte[outBuffInfo.size];
                        encodedData.get(outData, 0, outBuffInfo.size);
                        fos.write(outData, 0, outBuffInfo.size);
                        encoder.releaseOutputBuffer(outputBufIndex, false);
                    }
                }
            } while (outBuffInfo.flags != MediaCodec.BUFFER_FLAG_END_OF_STREAM);


            if (fis != null) {
                fis.close();
                fis = null;
            }
            if (fos != null) {
                fos.flush();
                fos.close();
            }
             File oldfile = new File(sourceFile);
            if (oldfile.exists()) {
                oldfile.delete();
            }
            AESUtils.Encrypt(destinationFile,"key");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


}

 

 

 

4.AudioFileUtils(文件管理的类)

 

package com.zqr.snake.mytest.record3;

import android.os.Environment;
import android.text.TextUtils;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class AudioFileUtils {

    private static String rootPath = "audiorecord";
    private final static String AUDIO_PCM_BASEPATH = "/" + rootPath + "/pcm/";
    private final static String AUDIO_WAV_BASEPATH = "/" + rootPath + "/wav/";
    private final static String AUDIO_AMR_BASEPATH = "/" + rootPath + "/amr/";
    private final static String AUDIO_TEMP_BASEPATH = "/" + rootPath + "/temp/";//临时文件

    public static void setRootPath(String rootPath) {
        AudioFileUtils.rootPath = rootPath;
    }

    public static String getPcmFileAbsolutePath(String fileName) {
        if (TextUtils.isEmpty(fileName)) {
            throw new NullPointerException("fileName isEmpty");
        }
        String mAudioRawPath = "";
        if (!fileName.endsWith(".pcm")) {
            fileName = fileName + ".pcm";
        }
        String fileBasePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + rootPath + "/pcm/";
        File file = new File(fileBasePath);
        if (!file.exists()) {
            file.mkdirs();
        }
        mAudioRawPath = fileBasePath + fileName;

        return mAudioRawPath;
    }


    public static String getWavFileAbsolutePath(String fileName) {
        if (fileName == null) {
            throw new NullPointerException("fileName can't be null");
        }

        String mAudioWavPath = "";
        if (!fileName.endsWith(".wav")) {
            fileName = fileName + ".wav";
        }
        String fileBasePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + rootPath + "/wav/";
        File file = new File(fileBasePath);
        if (!file.exists()) {
            file.mkdirs();
        }
        mAudioWavPath = fileBasePath + fileName;
        return mAudioWavPath;
    }

    public static String getAmrFileAbsolutePath(String fileName) {
        if (fileName == null) {
            throw new NullPointerException("fileName can't be null");
        }

        String mAudioWavPath = "";
        if (!fileName.endsWith(".amr")) {
            fileName = fileName + ".amr";
        }
        String fileBasePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + rootPath + "/amr/";
        File file = new File(fileBasePath);
        if (!file.exists()) {
            file.mkdirs();
        }
        mAudioWavPath = fileBasePath + fileName;
        return mAudioWavPath;
    }

    //获取临时文件的方法名字
    public static String getTempFileAbsolutePath(String fileName) {
        if (fileName == null) {
            throw new NullPointerException("fileName can't be null");
        }

        String mAudioWavPath = "";
        if (!fileName.endsWith(".amr")) {
            fileName = fileName + ".amr";
        }
        String fileBasePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + rootPath + "/temp/";
        File file = new File(fileBasePath);
        if (!file.exists()) {
            file.mkdirs();
        }
        mAudioWavPath = fileBasePath + fileName;
        return mAudioWavPath;
    }


    /**
     * 获取全部amr文件列表
     *
     * @return
     */
    public static List<File> getAmrFiles() {
        List<File> list = new ArrayList<>();
        String fileBasePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + rootPath + "/amr/";

        File rootFile = new File(fileBasePath);
        if (!rootFile.exists()) {
        } else {
            File[] files = rootFile.listFiles();
            for (File file : files) {
                list.add(file);
            }

        }
        Collections.reverse(list); //倒序排列
        return list;
    }

}

 

 

5.对音频文件进行加解密的类AESUtils:

 

package com.zqr.snake.mytest.record3;

import android.util.Log;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class AESUtils {
    /* 加密 */
    private static byte[] encryptVoice(String seed, byte[] clearbyte)
            throws Exception {
        byte[] rawKey = getRawKey(seed.getBytes());
        byte[] result = encrypt(rawKey, clearbyte);
        return result;
    }

    /* 解密 */
    private static byte[] decryptVoice(String seed, byte[] encrypted)
            throws Exception {
        byte[] rawKey = getRawKey(seed.getBytes());
        byte[] result = decrypt(rawKey, encrypted);
        return result;
    }

    private static byte[] getRawKey(byte[] seed) throws Exception {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        SecureRandom sr = SecureRandom.getInstance("SHA1PRNG", "Crypto");
        sr.setSeed(seed);
        kgen.init(128, sr);
        SecretKey skey = kgen.generateKey();
        byte[] raw = skey.getEncoded();
        return raw;
    }

    private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception {
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(
                new byte[cipher.getBlockSize()]));
        byte[] encrypted = cipher.doFinal(clear);
        return encrypted;
    }

    private static byte[] decrypt(byte[] raw, byte[] encrypted)
            throws Exception {
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(
                new byte[cipher.getBlockSize()]));
        byte[] decrypted = cipher.doFinal(encrypted);
        return decrypted;
    }


    /**
     * 加密 - AES
     */
    public static void Encrypt(String Path,String seed) {
//        Log.d("加密 - AES", "----加密开始时间: " + new Date().getTime()/1000);
        FileInputStream fis = null;
        FileOutputStream fos = null;
        boolean isSuccess = true;
        try {
            File oldFile = new File(Path);
            fis = new FileInputStream(oldFile);
            byte[] oldByte = new byte[(int) oldFile.length()];
            fis.read(oldByte); // 读取
            byte[] newByte = AESUtils.encryptVoice(seed, oldByte);
            // 加密
            fos = new FileOutputStream(oldFile);
            fos.write(newByte);

        } catch (FileNotFoundException e) {
            isSuccess = false;
            e.printStackTrace();
        } catch (IOException e) {
            isSuccess = false;
            e.printStackTrace();
        } catch (Exception e) {
            isSuccess = false;
            e.printStackTrace();
        } finally {
            try {
                fis.close();
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (isSuccess)
        Log.d("加密 - AES", "加密成功");
        else
            Log.d("加密 - AES", "加密失败");
//        Log.d("加密 - AES", "----加密结束时间: " + new Date().getTime()/1000);
//        Log.i("加密 - AES", "保存成功");
    }


    /**
     * 解密 - AES
     */
    public static String Decrypt(String playerPath,String seed) {
//        Log.d("解密 - AES", "----解密开始时间: " + new Date().getTime());
        File oldFile = new File(playerPath);
//        File tempFile = new File(AudioFileUtils.getTempFileAbsolutePath(new SimpleDateFormat("yyyyMMddHHmmss").format(new Date())));
        File tempFile = new File(AudioFileUtils.getTempFileAbsolutePath(oldFile.getName()));
        FileInputStream fis = null;
        FileOutputStream fos = null;
        boolean isSuccess = true;
        byte[] oldByte = new byte[(int) oldFile.length()];
        try {
            fis = new FileInputStream(oldFile);
            fis.read(oldByte);
            byte[] newByte = AESUtils.decryptVoice(seed, oldByte);
            // 解密
            fos = new FileOutputStream(tempFile);
            fos.write(newByte);

        } catch (FileNotFoundException e) {
            isSuccess = false;
            e.printStackTrace();
        } catch (IOException e) {
            isSuccess = false;
            e.printStackTrace();
        } catch (Exception e) {
            isSuccess = false;
            e.printStackTrace();
        }
        try {
            fis.close();
            fos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
//        Log.d("解密 - AES", "----解密结束时间: " + new Date().getTime());
        if (isSuccess){
            Log.i("解密 - AES", "解密成功");
            return tempFile.getPath();
        } else {
            Log.i("解密 - AES", "解密失败");
            return "";
        }


    }



}  

 

 

 

最后就是对这些功能进行封装在服务RecordService:

 

package com.zqr.snake.mytest.record3;

import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Binder;
import android.os.IBinder;
import android.text.TextUtils;
import android.util.Log;

import java.io.File;

public class RecordService extends Service {
    private MyIBinder myIBinder;
    private AudioRecorder audioRecorder;
    private MediaPlayer mediaPlayer;
    private int mVolume;
    private String currentPlayPath;
    /**
     * 更新分贝的回调接口
     */
    private onVoluneListener listener;

    /**
     * 注册回调接口的方法,供外部调用
     * @param onProgressListener
     */
    public void setOnProgressListener(onVoluneListener onProgressListener) {
        this.listener = onProgressListener;
    }
    @Override
    public IBinder onBind(Intent intent) {
        return myIBinder; //返回的MyIBinder对象会在onServiceConnected()中调用
    }

    @Override
    public void onCreate() {
        super.onCreate();
        myIBinder =new MyIBinder();//启动服务时即创建Binder对象
        initRecorder();
        initPlayer();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    private void initPlayer() {
        mediaPlayer = new MediaPlayer();
        mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
            @Override
            public void onPrepared(MediaPlayer mp) {
                mediaPlayer.start();
            }
        });
        mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mp) {
                if (!TextUtils.isEmpty(currentPlayPath)){
                File file = new File(currentPlayPath);
                if (file.exists()) file.delete();
                currentPlayPath = "";
            }
            }
        });


    }

    private void initRecorder() {
        audioRecorder = new AudioRecorder(new AudioRecorder.CallBack() {
            @Override
            public void recordProgress(final int progress) {
               if (listener != null){
                   listener.recordProgress(progress);
               }
            }

            @Override
            public void volumn(int volumn) {
                if (listener != null){
                    listener.volume(volumn);
                }
            }
        }, new AmrEncoder());
    }



    //代理人
    public class MyIBinder extends Binder implements RecordInterface{

        /**
         * 获取当前Service的实例
         * @return
         */
        public RecordService getService(){
            return RecordService.this;
        }


        /**
         * 开始录制
         */
        @Override
        public void start() {
            RecordService.this.startReecrd();
        }
        /**
         * 暂停录制
         */
        @Override
        public AudioRecorder.Status pause() {
           return RecordService.this.pauseReecrd();
        }

        /**
         * 开始播放
         */
        @Override
        public void paly() {
            RecordService.this.palyReecrd();
        }

        /**
         * 取消录制
         */
        @Override
        public void cancle() {
            RecordService.this.cancleReecrd();
        }
        /**
         * 停止录制
         */
        @Override
        public void stop() {
            RecordService.this.stopReecrd();
        }

        /**
         * 获取实时分贝大小
         */
        @Override
        public int getVolume() {
            return mVolume;
        }
        /**
         * 设置录制保存路径
         */
        @Override
        public void setPath(String path) {
            RecordService.this.setRootPath(path);
        }
        /**
         * 停止播放
         */
        @Override
        public void stopPlay() {
            RecordService.this.stopPalyReecrd();
        }


    }


    public void startReecrd(){
        audioRecorder.startRecord();
    }

     public void cancleReecrd(){
         audioRecorder.release();
    }

    public AudioRecorder.Status pauseReecrd(){
        try {
            if (audioRecorder.getStatus() == AudioRecorder.Status.STATUS_START) {
                //暂停录音
                audioRecorder.pauseRecord();
//                btn_pause.setText("继续录音");
            } else {
                audioRecorder.startRecord();
//                btn_pause.setText("暂停录音");
            }
        } catch (IllegalStateException e) {
            e.printStackTrace();
        }finally {
            return audioRecorder.getStatus();
        }
    }

    public void stopReecrd(){
        audioRecorder.stop();
    }

    public void setRootPath(String path){
       AudioFileUtils.setRootPath(path);
    }

    public void palyReecrd(){
        try {
            if (mediaPlayer == null) initPlayer();
            String path = AESUtils.Decrypt(audioRecorder.getVoiceFilePath(),"key");
            if (TextUtils.isEmpty(path)) return;
            mediaPlayer.reset();
            mediaPlayer.setDataSource(path);
            currentPlayPath = path;
            mediaPlayer.prepareAsync();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void stopPalyReecrd(){
        if (mediaPlayer != null) {
            mediaPlayer.release();
            mediaPlayer = null;
        }
    }






    public interface RecordInterface {
        void start();
        AudioRecorder.Status pause();
        void paly();
        void cancle();
        void stop();
        int getVolume();
        void setPath(String path);
        void stopPlay();

    }
}

 

 

 

最后项目源码下载地址:https://download.csdn.net/download/zqr772791008/11197086

 

 

 

欢迎大家一起来学习!!!

 

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
在Android中实现录音断点播放,可以使用AudioRecord进行录音,并使用MediaPlayer类进行播放。为了实现暂停和继续录音,我们需要在录音过程中使用一个标志位来控制录音暂停状态,并在录音暂停时保存录音的状态(例如,当前录音的位置和录音数据),以便在继续录音时能够从上次暂停的位置继续录音。 以下是一个简单的实现示例: ```java public class AudioRecorder { private AudioRecord mAudioRecord; private boolean mIsRecording = false; private boolean mIsPaused = false; private int mBufferSize; private byte[] mBuffer; private File mOutputFile; private FileOutputStream mFileOutputStream; private int mBytesWritten; public AudioRecorder(File outputFile) { mOutputFile = outputFile; mBufferSize = AudioRecord.getMinBufferSize(44100, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT); mBuffer = new byte[mBufferSize]; mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, 44100, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, mBufferSize); } public void start() { mIsRecording = true; mIsPaused = false; mAudioRecord.startRecording(); new Thread(new Runnable() { @Override public void run() { try { mFileOutputStream = new FileOutputStream(mOutputFile); while (mIsRecording) { if (!mIsPaused) { int bytesRead = mAudioRecord.read(mBuffer, 0, mBufferSize); mFileOutputStream.write(mBuffer, 0, bytesRead); mBytesWritten += bytesRead; } } mFileOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } }).start(); } public void pause() { mIsPaused = true; } public void resume() { mIsPaused = false; } public void stop() { mIsRecording = false; mAudioRecord.stop(); mAudioRecord.release(); } public boolean isRecording() { return mIsRecording; } public boolean isPaused() { return mIsPaused; } public int getBytesWritten() { return mBytesWritten; } } ``` 在这个示例中,我们创建了一个AudioRecorder类来封装录音功能。在start()方法中,我们启动了一个新的线程来执行录音任务。在这个线程中,我们使用一个while循环来读取录音数据,并将其写入文件中。如果mIsPaused标志被设置为true,则录音任务将暂停,直到mIsPaused标志被设置为false。 在pause()和resume()方法中,我们分别设置mIsPaused标志为true和false,以控制录音任务的暂停和继续。 在stop()方法中,我们将mIsRecording标志设置为false,以停止录音任务,并释放AudioRecord资源。 最后,我们还提供了一些辅助方法,例如isRecording()、isPaused()和getBytesWritten()方法,用于查询录音状态和已写入的字节数。 请注意,这只是一个简单的示例,实际应用中可能需要更复杂的逻辑来处理录音暂停和继续的情况。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值