android音频学习笔记之写入音频文件

package com.example.audiodemo;

import java.io.DataOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

/**
 * 音频写入文件实现类
 */
public class WavFileWrite {

    private String mFilepath;
    private int mDataSize = 0;
    private DataOutputStream mDataOutputStream;

    /**
     *
     * @param filepath 文件地址
     * @param sampleRateInHz 采样率
     * @param channels 声道数
     * @param bitsPerSample 数据位宽
     * @return true 成功 ,false 失败
     * @throws IOException
     */
    public boolean openFile(String filepath, int sampleRateInHz, int channels, int bitsPerSample) throws IOException {
        if (mDataOutputStream != null) {
            closeFile();
        }
        mFilepath = filepath;
        mDataSize = 0;
        mDataOutputStream = new DataOutputStream(new FileOutputStream(filepath));
        return writeHeader(sampleRateInHz, bitsPerSample, channels);
    }

    public boolean closeFile() throws IOException {
        boolean ret = true;
        if (mDataOutputStream != null) {
            ret = writeDataSize();
            mDataOutputStream.close();
            mDataOutputStream = null;
        }
        return ret;
    }

    /**
     *在音频采集的回调中调用该函数写入音频数据
     * 
     * @param buffer 音频二进制原始数据
     * @param offset 0
     * @param count 音频二进制原始数据的长度 buffer.length
     * @return
     */
    public boolean writeData(byte[] buffer, int offset, int count) {
        if (mDataOutputStream == null) {
            return false;
        }

        try {
            mDataOutputStream.write(buffer, offset, count);
            mDataSize += count;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

        return true;
    }

    /**
     * 写入wav头文件信息,根据各个对应的位置以及占多少位写入
     *
     * @param sampleRateInHz 采样率
     * @param channels 声道数
     * @param bitsPerSample 数据位宽
     * @return true 成功 ,false 失败
     */
    private boolean writeHeader(int sampleRateInHz, int channels, int bitsPerSample) {
        if (mDataOutputStream == null) {
            return false;
        }

        WavFileHeader header = new WavFileHeader(sampleRateInHz, channels, bitsPerSample);

        try {
            mDataOutputStream.writeBytes(header.mChunkID);
            mDataOutputStream.write(intToByteArray(header.mChunkSize), 0, 4);
            mDataOutputStream.writeBytes(header.mFormat);
            mDataOutputStream.writeBytes(header.mSubChunk1ID);
            mDataOutputStream.write(intToByteArray(header.mSubChunk1Size), 0, 4);
            mDataOutputStream.write(shortToByteArray(header.mAudioFormat), 0, 2);
            mDataOutputStream.write(shortToByteArray(header.mNumChannel), 0, 2);
            mDataOutputStream.write(intToByteArray(header.mSampleRate), 0, 4);
            mDataOutputStream.write(intToByteArray(header.mByteRate), 0, 4);
            mDataOutputStream.write(shortToByteArray(header.mBlockAlign), 0, 2);
            mDataOutputStream.write(shortToByteArray(header.mBitsPerSample), 0, 2);
            mDataOutputStream.writeBytes(header.mSubChunk2ID);
            mDataOutputStream.write(intToByteArray(header.mSubChunk2Size), 0, 4);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

        return true;
    }

    /**
     *写入数据大小(整个wav文件的字节数和存储的二进制原始音频数据的长度)
     * @return
     */
    private boolean writeDataSize() {
        if (mDataOutputStream == null) {
            return false;
        }

        try {
            RandomAccessFile wavFile = new RandomAccessFile(mFilepath, "rw");
            wavFile.seek(WavFileHeader.WAV_CHUNKSIZE_OFFSET); //写入ChunkSize大小 :整个 wav 文件的字节数
            wavFile.write(intToByteArray((mDataSize + WavFileHeader.WAV_CHUNKSIZE_EXCLUDE_DATA)), 0, 4);
            wavFile.seek(WavFileHeader.WAV_SUB_CHUNKSIZE2_OFFSET);//写入SubChunk2Size大小:后面存储的二进制原始音频数据的长度
            wavFile.write(intToByteArray((mDataSize)), 0, 4);
            wavFile.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return false;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }

        return true;
    }

    private static byte[] intToByteArray(int data) {
        return ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(data).array();
    }

    private static byte[] shortToByteArray(short data) {
        return ByteBuffer.allocate(2).order(ByteOrder.LITTLE_ENDIAN).putShort(data).array();
    }
}

下面结合音频采集的工具类实现采集并将数据写入到wav文件中

package com.example.audiodemo.test;

import android.os.Environment;

import com.example.audiodemo.AudioCapturer;
import com.example.audiodemo.WavFileWrite;

import java.io.IOException;

public class AudioCapturerTest implements AudioCapturer.OnAudioFrameCapturedListener {

    private static final String AUDIO_FILE_PATH = "/data/data/com.example.audiodemo/test.wav";
    private AudioCapturer mAudioCapturer;
    private WavFileWrite mWavFileWrite;

    /**
     * 开始录音,并将录音写入文件
     * @return true 成功, false 失败
     */
    public boolean startTest(){
        mAudioCapturer = new AudioCapturer();
        mWavFileWrite = new WavFileWrite();
        mAudioCapturer.setAudioFrameCapturedListener(this);
        try {
            mWavFileWrite.openFile(AUDIO_FILE_PATH, 44100, 1, 16);
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return mAudioCapturer.startCapturer();
    }

    /**
     * 关闭录音,并停止写入文件
     * @return true 成功, false 失败
     */
    public boolean stopTest(){
        mAudioCapturer.stopCapturer();
        try {
            mWavFileWrite.closeFile();
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    @Override
    public void onAudioFrameCaptured(byte[] audioData) {
        mWavFileWrite.writeData(audioData, 0, audioData.length);
    }
}

猜你喜欢

转载自blog.csdn.net/qq_42447739/article/details/128096107