Android AudioRecorder 实现mp3格式录音

Android提供了AudioRecorder和MediaRecorder两种方法录音,这里介绍AudioRecorder录音的方式,项目需求场景往往需要我们能够长时间录音,并且不影响在一个App内的其他操作,显然,Service是合适的选择,为了能够录出mp3格式的录音,我们需要引入Lame库,边录边转码为mp3格式,好了,先上截图,再上代码.


Android AudioRecorder 实现mp3格式录音_第1张图片
录音截屏.png

1.gradle配置,并将下载好的.so文件放在jniLibs/armeabi目录下

sourceSets {//将so库地址指定为libs目录下
        main {
            jniLibs.srcDirs = ['libs']
        }
    }
Android AudioRecorder 实现mp3格式录音_第2张图片
.so文件位置.png

2.录音核心类Mp3Recorder,initAudioRecorder(),并在录音过程中把录音文件转码为mp3格式:
初始化AudioRecord

     private void initAudioRecorder() throws IOException {
        int bytesPerFrame = audioFormat.getBytesPerFrame();
        /* Get number of samples. Calculate the buffer size (round up to the
           factor of given frame size) */
        int frameSize = AudioRecord.getMinBufferSize(samplingRate,
                channelConfig, audioFormat.getAudioFormat())
                / bytesPerFrame;  //返回字节为单位的创建AudioRecord的最小缓冲区大小
        if (frameSize % FRAME_COUNT != 0) {
            frameSize = frameSize + (FRAME_COUNT - frameSize % FRAME_COUNT);  //设置frameSize为160的整数倍
            Log.d(TAG, "Frame size: " + frameSize);
        }

        bufferSize = frameSize * bytesPerFrame;  //录制过程中写入的缓冲区的总大小
        audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,
                samplingRate, channelConfig, audioFormat.getAudioFormat(),
                bufferSize); //初始化AudioRecord

        // 设置buffer为缓冲区的10倍大小
        // 初始化buffer接受数据
        ringBuffer = new RingBuffer(10 * bufferSize);
        buffer = new byte[bufferSize];

        // Initialize lame buffer
        // mp3 sampling rate is the same as the recorded pcm sampling rate
        // 初始化lame samplingRate采样率,1为声道数,BIT_RATE为比特率
        SimpleLame.init(samplingRate, 1, samplingRate, BIT_RATE);

        mp3File = new File(filePath);
        if (!mp3File.getParentFile().exists()) {
            mp3File.mkdirs();
        }
        os = new FileOutputStream(mp3File);
        // 创建一个线程编码数据
        encodeThread = new DataEncodeThread(ringBuffer, os, bufferSize);
        encodeThread.start();

        //设置audioRecord的监听并且设置监听
        audioRecord.setRecordPositionUpdateListener(encodeThread, encodeThread.getHandler());
        audioRecord.setPositionNotificationPeriod(FRAME_COUNT);
    }

开始录音

    public void startRecording() throws IOException {
        if (isRecording) return;
        Log.d(TAG, "Start recording");
        Log.d(TAG, "BufferSize = " + bufferSize);
        // Initialize audioRecord if it's null.
        if (audioRecord == null) {
            length = 0;
            stopTime = 0;
            startTime = 0;
            initAudioRecorder();
        }
        audioRecord.startRecording();
        startTime = new Date().getTime();
        new Thread() {

            @Override
            public void run() {
                isRecording = true;
                while (isRecording) {
                    int bytes = audioRecord.read(buffer, 0,
                            bufferSize);//读取音频数据至buffer中(读取缓冲区(在过度运行尚未读取读取的数据)的数据至buffer)
                    if (bytes > 0) {
                        ringBuffer.write(buffer, bytes);//写入RingBuffer数据中
                        calculateRealVolume(buffer, bytes);
                    }
                }
            }
        }.start();
    }

停止录音

    public void stopRecording() throws IOException {
        Log.d(TAG, "stop recording");
        isRecording = false;
        calaTime();
        // release and finalize audioRecord
        try {
            //停止录制
            if (audioRecord != null) {
                audioRecord.stop();
                audioRecord.release();
                audioRecord = null;
            }
            // stop the encoding thread and try to wait
            // until the thread finishes its job(发送消息结束工作录制)
            Message msg = Message.obtain(encodeThread.getHandler(),
                    DataEncodeThread.PROCESS_STOP);
            msg.sendToTarget();

            Log.d(TAG, "waiting for encoding thread");
            encodeThread.join();//执行encodeThread线程


            if (listener != null) {
                listener.stop();
            }
            Log.d(TAG, "done encoding thread");
        } catch (InterruptedException e) {
            Log.d(TAG, "Faile to join encode thread");
        } finally {
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

音量计算及回调

 private void calculateRealVolume(byte[] buffer, int readSize) {
        double sum = 0;
        for (int i = 0; i < readSize; i++) {
            sum += buffer[i] * buffer[i];
        }
        if (readSize > 0) {
            double amplitude = sum / readSize;
            mVolume = (int) Math.sqrt(amplitude);
        }
        if (mVolume >= MAX_VOLUME) {
            listener.Volume(MAX_VOLUME);
        }else {
            listener.Volume(mVolume);
        }
    }

3.Service中的使用,实现mp3Recorder接口

 /**
     * 开始录音
     */
    public boolean startRecord() throws IOException {
        // 如果正在录音,则返回
        if (isRecording) {
            return isRecording;
        }

        isRecording = true;

        startTime = System.currentTimeMillis();
        if (mp3Recorder == null) {
            String fileName = TimeUtils.getCurrentTime();
            mp3Path = mp3Floder + fileName + ".mp3";
            mp3Recorder = new Mp3Recorder(mp3Path);
            mp3Recorder.setListener(this);
            mp3Recorder.startRecording();
            Toast.makeText(this, "开始录音!", Toast.LENGTH_SHORT).show();
        } else {
            mp3Recorder.startRecording();
            Toast.makeText(this, "正在录音!", Toast.LENGTH_SHORT).show();
        }

        setFlag(true);
        return isRecording;
    }


    /**
     * 停止录音
     */
    public boolean stopRecordingAndConvertFile() throws IOException {

        if (!isRecording) {
            return isRecording;
        }
        isRecording = false;
        mp3Recorder.stopRecording();

        setFlag(false);
        audioStatusUpdateListener.onStop(mp3Path);
        //通知媒体库更新文件夹
        Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
        Uri uri = Uri.fromFile(new File(mp3Path));
        intent.setData(uri);
        this.sendBroadcast(intent);
        mp3Recorder = null;

        return isRecording;// convertOk==true,return true
    }

    //音量监听回调
    @Override
    public void Volume(final int volume) {

        Message msg = new Message();
        msg.what = 1;
        msg.obj = volume;
        mHandler.sendMessageDelayed(msg, 100);

    }

4.Activity中绑定和使用

//绑定
 intent = new Intent(AudioMp3Activity.this, AudioMp3RecoderService3.class);
        bindService(intent, conn, Context.BIND_AUTO_CREATE);
//按钮录音开始和结束控制
if (RECORD_FLAG == 1) {
                        isRecording = true;
                        startService(intent);
                        try {
                            audioMp3RecordService.startRecord();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        RECORD_FLAG = 2;
                        break;
                    } else if (RECORD_FLAG == 2) {
                        try {
                            audioMp3RecordService.stopRecordingAndConvertFile();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        stopService(intent);
                        isRecording = false;
                        RECORD_FLAG = 1;
                        break;
                    }


9月14日更新

今天调试发现录音功能这个so库只能支持到SDK22,23以上会报出异常,所以需要更新so库

//TODO 更新so库以支持SDK23及以上

好了,基本到这,代码戳https://github.com/willShuhuan/MyDemos

你可能感兴趣的:(Android AudioRecorder 实现mp3格式录音)