美文网首页Android开发Android技术知识
Android录音(AudioRecord)保存本地

Android录音(AudioRecord)保存本地

作者: 拉弓的松鼠在旋转 | 来源:发表于2018-08-22 10:05 被阅读10次

    先看效果:

    09FD1CA8BC9F72021AC66F0BF99BCE07.jpg 91BCDF5D2C2D2935F308673A21F6AF33.jpg

    录音流程:
    根据所需的采样率,声道,位数创建AudioRecord的对象mAudioRecord->
    用线程不断调用mAudioRecord的read(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes)的方法->
    在这个线程里面不断读取audioData,该保存的类型为PCM->
    PCM转成让wav格式(系统可播放)

    权限

        <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
        <uses-permission android:name="android.permission.RECORD_AUDIO" />
        <uses-permission android:name="android.permission.WAKE_LOCK" />
    

    初始化数据

        private void initData() {
            mRecorderBufferSize = AudioRecord.getMinBufferSize(mSampleRateInHZ, mChannelConfig, mAudioFormat);
            mAudioData = new byte[320];
            mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.VOICE_COMMUNICATION, mSampleRateInHZ, mChannelConfig, mAudioFormat, mRecorderBufferSize);
    //        mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, mSampleRateInHZ, mChannelConfig, mAudioFormat, mRecorderBufferSize * 2
    //                , AudioTrack.MODE_STREAM);
        }
    

    不断读取数据,写入文件(pcm格式)

        @OnClick(R.id.start_btn)
        void onClickStart(View view) {
            if (isRecording) {
                showToast("已开始");
                return;
            }
            String tmpName = System.currentTimeMillis() + "_" + mSampleRateInHZ + "";
            final File tmpFile = createFile(tmpName + ".pcm");
            final File tmpOutFile = createFile(tmpName + ".wav");
            mTmpFileAbs = tmpFile.getAbsolutePath();
            mLogTv.setText(tmpFile.getAbsolutePath());
    
    
            isRecording = true;
            mAudioRecord.startRecording();
            mExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        FileOutputStream outputStream = new FileOutputStream(tmpFile.getAbsoluteFile());
    
    
                        while (isRecording) {
                            int readSize = mAudioRecord.read(mAudioData, 0, mAudioData.length);
                            Log.i(TAG, "run: ------>" + readSize);
                            outputStream.write(mAudioData);
                        }
    
                        outputStream.close();
                        pcmToWave(tmpFile.getAbsolutePath(), tmpOutFile.getAbsolutePath());
                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    
        private File createFile(String name) {
    
            String dirPath = Environment.getExternalStorageDirectory().getPath() + "/AudioRecord/";
            File file = new File(dirPath);
    
            if (!file.exists()) {
                file.mkdirs();
            }
    
            String filePath = dirPath + name;
            File objFile = new File(filePath);
            if (!objFile.exists()) {
                try {
                    objFile.createNewFile();
                    return objFile;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
    
            return null;
    
    
        }
    
    

    PCM 转 WAV格式

        private void pcmToWave(String inFileName, String outFileName) {
            FileInputStream in = null;
            FileOutputStream out = null;
            long totalAudioLen = 0;
            long longSampleRate = mSampleRateInHZ;
            long totalDataLen = totalAudioLen + 36;
            int channels = 1;//你录制是单声道就是1 双声道就是2(如果错了声音可能会急促等)
            long byteRate = 16 * longSampleRate * channels / 8;
    
            byte[] data = new byte[mRecorderBufferSize];
            try {
                in = new FileInputStream(inFileName);
                out = new FileOutputStream(outFileName);
    
                totalAudioLen = in.getChannel().size();
                totalDataLen = totalAudioLen + 36;
                writeWaveFileHeader(out, totalAudioLen, totalDataLen, longSampleRate, channels, byteRate);
                while (in.read(data) != -1) {
                    out.write(data);
                }
    
                in.close();
                out.close();
            } catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    
        }
    
    
        /*
        任何一种文件在头部添加相应的头文件才能够确定的表示这种文件的格式,wave是RIFF文件结构,每一部分为一个chunk,其中有RIFF WAVE chunk,
        FMT Chunk,Fact chunk,Data chunk,其中Fact chunk是可以选择的,
         */
        private void writeWaveFileHeader(FileOutputStream out, long totalAudioLen, long totalDataLen, long longSampleRate,
                                         int channels, long byteRate) throws IOException {
            byte[] header = new byte[44];
            header[0] = 'R'; // RIFF
            header[1] = 'I';
            header[2] = 'F';
            header[3] = 'F';
            header[4] = (byte) (totalDataLen & 0xff);//数据大小
            header[5] = (byte) ((totalDataLen >> 8) & 0xff);
            header[6] = (byte) ((totalDataLen >> 16) & 0xff);
            header[7] = (byte) ((totalDataLen >> 24) & 0xff);
            header[8] = 'W';//WAVE
            header[9] = 'A';
            header[10] = 'V';
            header[11] = 'E';
            //FMT Chunk
            header[12] = 'f'; // 'fmt '
            header[13] = 'm';
            header[14] = 't';
            header[15] = ' ';//过渡字节
            //数据大小
            header[16] = 16; // 4 bytes: size of 'fmt ' chunk
            header[17] = 0;
            header[18] = 0;
            header[19] = 0;
            //编码方式 10H为PCM编码格式
            header[20] = 1; // format = 1
            header[21] = 0;
            //通道数
            header[22] = (byte) channels;
            header[23] = 0;
            //采样率,每个通道的播放速度
            header[24] = (byte) (longSampleRate & 0xff);
            header[25] = (byte) ((longSampleRate >> 8) & 0xff);
            header[26] = (byte) ((longSampleRate >> 16) & 0xff);
            header[27] = (byte) ((longSampleRate >> 24) & 0xff);
            //音频数据传送速率,采样率*通道数*采样深度/8
            header[28] = (byte) (byteRate & 0xff);
            header[29] = (byte) ((byteRate >> 8) & 0xff);
            header[30] = (byte) ((byteRate >> 16) & 0xff);
            header[31] = (byte) ((byteRate >> 24) & 0xff);
            // 确定系统一次要处理多少个这样字节的数据,确定缓冲区,通道数*采样位数
            header[32] = (byte) (1 * 16 / 8);
            header[33] = 0;
            //每个样本的数据位数
            header[34] = 16;
            header[35] = 0;
            //Data chunk
            header[36] = 'd';//data
            header[37] = 'a';
            header[38] = 't';
            header[39] = 'a';
            header[40] = (byte) (totalAudioLen & 0xff);
            header[41] = (byte) ((totalAudioLen >> 8) & 0xff);
            header[42] = (byte) ((totalAudioLen >> 16) & 0xff);
            header[43] = (byte) ((totalAudioLen >> 24) & 0xff);
            out.write(header, 0, 44);
        }
    
    

    项目Demo链接

    相关文章

      网友评论

        本文标题:Android录音(AudioRecord)保存本地

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