美文网首页Android项目
Android AudioRecorder 实现mp3格式录音

Android AudioRecorder 实现mp3格式录音

作者: Man不经心 | 来源:发表于2018-04-03 18:29 被阅读572次

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


    录音截屏.png

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

    sourceSets {//将so库地址指定为libs目录下
            main {
                jniLibs.srcDirs = ['libs']
            }
        }
    
    .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格式录音

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