天天看点

Android AudioRecord PCM数据解析

最近上手开发APP,在使用录音接口(AudioRecord)发现使用AudioRecord.read直接在dump出来的缓冲区数据保存为文本后,并不能在Matlab上正确播放声音,发现audiodata的格式受到音频数据格式(AudioFormat)影响。

缓冲区的基本单元是byte,当设置音频数据格式为ENCODING_PCM_8BIT(8位,单声道)时,刚好一个byte能够容纳一个采样点,这样的dump不存在问题;当设置音频数据格式为ENCODING_PCM_16BIT(16位,单声道)时,一个采样点需要2byte才够;当设置音频数据格式为ENCODING_PCM_16BIT(16位,双声道)时,一个采样点需要4byte才够,具体编码方法如下图:

Android AudioRecord PCM数据解析

在我的实验中用到了16位单声道,配置如下:

private int audioSource = MediaRecorder.AudioSource.MIC;
    // 设置音频采样率,44100是目前的标准,某些设备仍然支持22050,16000,11025
    private static int sampleRateInHz = 16000;
    // 设置音频的录制的声道CHANNEL_IN_MONO为单声道
    private static int channelConfig = AudioFormat.CHANNEL_IN_MONO;
    // 音频数据格式:PCM 16位每个样本。保证设备支持。
    private static int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
           

写入方法如下:

/**
     * 将数据写入文件。
     */
    private void writeDateTOFile(String AudioName) {
        // new一个byte数组用来存一些字节数据,大小为缓冲区大小
        String mFileName = "/sdcard/Android/data/com.example.gosleep/cache/audio.raw";
        byte[] audiodata = new byte[bufferSizeInBytes];
        FileOutputStream fos = null;
        FileOutputStream fos1 = null;
        OutputStreamWriter writer = null;
        int readsize = 0;
        int audiodata_len = 0;
        byte bytes[] = new byte[2];
        try {
            File file = new File(AudioName);
            if (file.exists()) {
                file.delete();
            }
            fos = new FileOutputStream(file);// 建立一个可存取字节的文件

            File file1 = new File(mFileName);
            fos1 = new FileOutputStream(file1);
            writer = new OutputStreamWriter(fos1, "utf-8");

        } catch (Exception e) {
            e.printStackTrace();
        }
        while (isRecord == true) {
            readsize = audioRecord.read(audiodata, 0, bufferSizeInBytes);
            if (AudioRecord.ERROR_INVALID_OPERATION != readsize) {
                try {
                    audiodata_len = audiodata.length;
                    for (int i = 0; i < audiodata_len; i += 2) {
                        bytes[0] = audiodata[i];
                        bytes[1] = audiodata[i + 1];
                        writer.write(byte4ToShortInt(bytes, 0) + ",");
                    }
                    fos.write(audiodata);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        try {
            writer.close();
            fos1.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            fos.close();// 关闭写入流
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
           

byte数组转短整数方法如下:

/**
     * byte数组转换为short int整数
     *
     * @param bytes byte数组
     * @param off   开始位置
     * @return int整数
     */
    private short byte4ToShortInt(byte[] bytes, int off) {
        short s = 0;
        short b0 = (short) (bytes[off] & 0xff);
        short b1 = (short) (bytes[off + 1] & 0xff);
        b1 <<= 8;
        s = (short) (b0 | b1);
        return s;
    }
           

参考博客:

1、https://blog.csdn.net/u010983881/article/details/60870360

2、https://blog.csdn.net/ownwell/article/details/8114121