关于android:Android-音视频开发二使用AudioRecord采集音频PCM并保存

28次阅读

共计 4749 个字符,预计需要花费 12 分钟才能阅读完成。

一. AudioRecord API 详解

AudioRecord 是安卓零碎提供的用于实现录音的性能类。
依据官网文档:
AndioRecord 类的次要性能就是让各自 JAVA 利用可能治理音频资源,以便它们通过这个类录制硬件设施收集的声音。录音过程,利用须要做的就是调用三个类办法中的一个获取声音数据。

1. read(byte[],int,int)
2. read(short[],int,int)
3. read(ByteBuffer,int)

无论应用哪一个办法,都须要事后设定一个 buffer 用于存储还没有来得及被读取的数据。这个 buffer 的大小能够在结构 AudioRecord 对象的时候指定,一旦确定大小,声音数据从音频硬件中被读出,一次读取的数据大小不能超过该 buffer 的容量。
实现 Android 录音的流程为:

  1. 结构一个 AudioRecord 对象,其中须要的最小录音缓存 buffer 大小能够通过 getMinBufferSize 办法失去,如果 buffer 容量过小,会导致对象结构失败。
  2. 初始化一个 buffer,该 buffer 大于等于 AudioRecord 对象用于写声音数据的 buffer 大小。
  3. 开始录音。
  4. 创立一个数据流,一边从 AudioRecord 中读取声音数据到初始化的 buffer,一边将 buffer 中数据导入数据流。
  5. 敞开数据流。
  6. 进行录音。

二. 应用 AudioRecord 实现录音,并生成.wav 文件

2.1 创立一个 AudioRecord 对象

首先要申明一些全局的变量参数:

private AudioRecord audioRecord = null; // 申明 AudioRecord 对象
private int recordBufSize = 0; // 申明 recordBuffer 的大小字段 

获取 buffer 的大小,并创立 AudioRecord:

public void createAudioRecord(){recordBufSize = AudioRecord.getMinBufferSize(frequency,channelConfiguration,EncodingBitRate);  //audioRecord 能接管的最小的 buffer 大小
    audioRecord = new AudioRecord(MediaRecord.AudioSource.MIC,frequency,channelConfiguration,EncodingBitRate,recordBufSize);
}

2.2 初始化一个 buffer

byte data[] = new byte[recordBufSize];

2.3 开始录音

audioRecord.startRecording();
isRecording = true;

2.4 创立一个数据流,一边从 AudioRecord 中读取声音数据到初始化的 buffer,一边将 buffer 中数据导入数据流

FileOutputStream os = null;

try{os = new FileOutputStream(filename);
}catch(FileNotFoundException e){e.printStackTrace();
}

if(null != os)
{while(isRecording){read = audioRecord.read(data,0,recordBufSize);
        // 如果读取音频数据没有呈现谬误,就将数据写入到文件
        if(AudioRecord.ERROR_INVALID_OPERATION != read){
            try{os.write(data)
            }catch(IOException e){e.printStackTrace();
            }
        }
    }

    try{os.close();
    }catch(IOException e){e.printStackTrace();
    }
}

2.5 敞开数据流

批改标记位:isRecording 为 false,下面的 while 循环就主动进行了,数据流也就进行流动了,Stream 也就被敞开了。

isRecording = false;

2.6 进行录音

进行录音之后,留神要开释资源。

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

最初:增加权限 WRITE_EXTERNAL_STORAGE、RECORD_AUDIO

三. 注意事项

依照上述流程录制出的音频文件是无奈间接进行播放的 raw 文件,如果想要放入播放器中进行播放,须要退出文件头。
增加 wave 文件头的代码如下:

public class PcmToWavUtil {

    /**
     * 缓存的音频大小
     */
    private int mBufferSize;
    /**
     * 采样率
     */
    private int mSampleRate;
    /**
     * 声道数
     */
    private int mChannel;


    /**
     * @param sampleRate sample rate、采样率
     * @param channel channel、声道
     * @param encoding Audio data format、音频格式
     */
    PcmToWavUtil(int sampleRate, int channel, int encoding) {
        this.mSampleRate = sampleRate;
        this.mChannel = channel;
        this.mBufferSize = AudioRecord.getMinBufferSize(mSampleRate, mChannel, encoding);
    }


    /**
     * pcm 文件转 wav 文件
     *
     * @param inFilename 源文件门路
     * @param outFilename 指标文件门路
     */
    public void pcmToWav(String inFilename, String outFilename) {
        FileInputStream in;
        FileOutputStream out;
        long totalAudioLen;
        long totalDataLen;
        long longSampleRate = mSampleRate;
        int channels = mChannel == AudioFormat.CHANNEL_IN_MONO ? 1 : 2;
        long byteRate = 16 * mSampleRate * channels / 8;
        byte[] data = new byte[mBufferSize];
        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 (IOException e) {e.printStackTrace();
        }
    }


    /**
     * 退出 wav 文件头
     */
    private void writeWaveFileHeader(FileOutputStream out, long totalAudioLen,
                                     long totalDataLen, long longSampleRate, int channels, long byteRate)
        throws IOException {byte[] header = new byte[44];
        // RIFF/WAVE header
        header[0] = 'R';
        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);
        //WAVE
        header[8] = 'W';
        header[9] = 'A';
        header[10] = 'V';
        header[11] = 'E';
        // 'fmt' chunk
        header[12] = 'f';
        header[13] = 'm';
        header[14] = 't';
        header[15] = ' ';
        // 4 bytes: size of 'fmt' chunk
        header[16] = 16;
        header[17] = 0;
        header[18] = 0;
        header[19] = 0;
        // format = 1
        header[20] = 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);
        header[28] = (byte) (byteRate & 0xff);
        header[29] = (byte) ((byteRate >> 8) & 0xff);
        header[30] = (byte) ((byteRate >> 16) & 0xff);
        header[31] = (byte) ((byteRate >> 24) & 0xff);
        // block align
        header[32] = (byte) (2 * 16 / 8);
        header[33] = 0;
        // bits per sample
        header[34] = 16;
        header[35] = 0;
        //data
        header[36] = 'd';
        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);
    }
}

四. MediaRecorder 和 AudioRecord

Andorid SDK 提供了两套音视频采集的 API,别离为 MediaRecorder 和 AudioRecord,前者是一个更加下层的 API,它能够间接把手机麦克风录入的音频数据进行压缩编码(如 AMR、MP3 等)并存成文件,而后者更靠近底层,可能更加自在灵便的管制,能够失去原始的一帧帧 PCM 音频数据。 如果想要简略的做一个录音机,录制成能够播放的音频文件,则推举应用 MediaRecord,而如果想要对音频做进一步解决、或者采纳第三方的编码库进行压缩、以及网络传输等利用,则倡议应用 AudioRecord。 其实 MediaRecord 底层也是调用了 AudioRecord 与 Android Framework 层的 AudioFlinger 进行交互的。 直播中实时采集音频天然要有 AudioRecord

五. 源码

http://github.com/renhui/Audi…

正文完
 0