Android Audio——使用AudioRecord录制音频

一、android平台上的音频采集

Android SDK 提供了两套音频采集的API,分别是:MediaRecorder 和 AudioRecord,前者是一个更加上层一点的 API,它可以直接把手机麦克风录入的音频数据进行编码压缩(如 AMR、MP3 等)并存成文件,而后者则更接近底层,能够更加自由灵活地控制,可以得到原始的一帧帧 PCM 音频数据。

二、AudioRecord音频采集的基本流程

  1. 构造一个 AudioRecord 对象。

  2. 开始采集。

  3. 读取采集的数据。

  4. 停止采集。

三、AudioRecord的基本参数

  •  audioSource 音频采集的来源,参考MediaRecorder.AudioSource

  •  sampleRateInHz 音频采样率

  •  channelConfig 声道,CHANNEL_IN_MONO(单声道),CHANNEL_IN_STEREO(双声道)

  •  audioFormat 音频采样精度,指定采样的数据的格式和每次采样的大小

  •  bufferSizeInBytes AudioRecord 采集到的音频数据所存放的缓冲区大小

四、AudioRecord类的主要方法

方法描述

AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes)

构造函数

static int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat)

计算最小缓冲区大小,参数同构造函数中三个参数。

Builder setAudioSource(int audioSource)

设置音频采集来源

void startRecording()

开始录制

int read(byte[] audioData, int offsetInBytes, int sizeInBytes)

int read(ByteBuffer audioBuffer, int sizeInBytes)

int read(short[] audioData, int offsetInShorts, int sizeInShorts)

从硬件读取音频数据保存到缓冲区有三个方法,都返回读取的数据个数

void stop()

停止录制

void release()

释放资源

int getState()

获取状态

int getRecordingState()

获取录制状态

五、代码实现

1)权限

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

2)AudioRecord 类的接口简单封装

public class AudioCapturer {
    private static final String TAG = "AudioCapturer";


    private static final int DEFAULT_SOURCE = MediaRecorder.AudioSource.MIC;
    private static final int DEFAULT_SAMPLE_RATE = 44100;
    private static final int DEFAULT_CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_STEREO;
    private static final int DEFAULT_AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT;


    private AudioRecord mAudioRecord;
    private int mMinBufferSize = 0;
    private Thread mCaptureThread;
    private boolean mIsCaptureStarted = false;
    private volatile boolean mIsLoopExit = false;
    private OnAudioFrameCapturedListener mAudioFrameCapturedListener;


    public interface OnAudioFrameCapturedListener {
        public void onAudioFrameCaptured(byte[] audioData);
    }


    public boolean isCaptureStarted() {
        return mIsCaptureStarted;
    }


    public void setOnAudioFrameCapturedListener(OnAudioFrameCapturedListener listener) {
        mAudioFrameCapturedListener = listener;
    }


    public boolean startCapture() {
        return startCapture(DEFAULT_SOURCE, DEFAULT_SAMPLE_RATE, DEFAULT_CHANNEL_CONFIG,
                DEFAULT_AUDIO_FORMAT);
    }


    @SuppressLint("MissingPermission")
    public boolean startCapture(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat) {
        if (mIsCaptureStarted) {
            Log.e(TAG, "Capture already started !");
            return false;
        }


        mMinBufferSize = AudioRecord.getMinBufferSize(sampleRateInHz,channelConfig,audioFormat);
        if (mMinBufferSize == AudioRecord.ERROR_BAD_VALUE) {
            Log.e(TAG, "Invalid parameter !");
            return false;
        }
        Log.d(TAG , "getMinBufferSize = "+mMinBufferSize+" bytes !");
        mAudioRecord = new AudioRecord(audioSource,sampleRateInHz,channelConfig,audioFormat,mMinBufferSize);
        if (mAudioRecord.getState() == AudioRecord.STATE_UNINITIALIZED) {
            Log.e(TAG, "AudioRecord initialize fail !");
            return false;
        }


        mAudioRecord.startRecording();
        mIsLoopExit = false;
        mCaptureThread = new Thread(new AudioCaptureRunnable());
        mCaptureThread.start();
        mIsCaptureStarted = true;
        Log.d(TAG, "Start audio capture success !");
        return true;
    }


    public void stopCapture() {
        if (!mIsCaptureStarted) {
            return;
        }
        mIsLoopExit = true;
        try {
            mCaptureThread.interrupt();
            mCaptureThread.join(1000);
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (mAudioRecord.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING) {
            mAudioRecord.stop();
        }
        mAudioRecord.release();
        mIsCaptureStarted = false;
        mAudioFrameCapturedListener = null;
        Log.d(TAG, "Stop audio capture success !");
    }


    private class AudioCaptureRunnable implements Runnable {
        @Override
        public void run() {
            while (!mIsLoopExit) {
                byte[] buffer = new byte[mMinBufferSize];
                int ret = mAudioRecord.read(buffer, 0, mMinBufferSize);
                if (ret == AudioRecord.ERROR_INVALID_OPERATION) {
                    Log.e(TAG , "Error ERROR_INVALID_OPERATION");
                }
                else if (ret == AudioRecord.ERROR_BAD_VALUE) {
                    Log.e(TAG , "Error ERROR_BAD_VALUE");
                }
                else {
                    if (mAudioFrameCapturedListener != null) {
                        mAudioFrameCapturedListener.onAudioFrameCaptured(buffer);
                    }
                    Log.d(TAG , "OK, Captured "+ret+" bytes !");
                }
                SystemClock.sleep(10);
            }
        }
    }
}
  • 17
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
使用AudioRecord录制音频并转换成wav格式,需要进行以下步骤: 1. 设置录音参数:采样率、音频通道、编码格式等 2. 创建一个AudioRecord对象 3. 开始录制音频,将音频数据写入到一个缓存区 4. 录制完成后,停止录音并释放AudioRecord对象 5. 将缓存区中的音频数据写入到一个wav文件中 下面是一个简单的示例代码,演示如何使用AudioRecord录制音频并将其转换成wav格式: ``` // 设置录音参数 int sampleRateInHz = 44100; int channelConfig = AudioFormat.CHANNEL_IN_MONO; int audioFormat = AudioFormat.ENCODING_PCM_16BIT; int bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat); // 创建AudioRecord对象 AudioRecord audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRateInHz, channelConfig, audioFormat, bufferSizeInBytes); // 开始录音 audioRecord.startRecording(); // 定义缓存区 byte[] buffer = new byte[bufferSizeInBytes]; // 定义输出文件 String outputFileName = "output.wav"; File outputFile = new File(Environment.getExternalStorageDirectory(), outputFileName); // 定义输出流 FileOutputStream outputStream = new FileOutputStream(outputFile); // 写入wav文件头 WaveHeader waveHeader = new WaveHeader(sampleRateInHz, channelConfig, audioFormat, bufferSizeInBytes); waveHeader.write(outputStream); // 写入音频数据 int readSize; while ((readSize = audioRecord.read(buffer, 0, bufferSizeInBytes)) != AudioRecord.ERROR_INVALID_OPERATION) { outputStream.write(buffer, 0, readSize); } // 停止录音并释放资源 audioRecord.stop(); audioRecord.release(); // 关闭输出流 outputStream.close(); ``` 在上述代码中,我们使用了一个自定义的WaveHeader类,用于生成wav文件头信息。该类的实现可以参考下面的示例代码: ``` public class WaveHeader { private int sampleRate; private int channelCount; private int audioFormat; private int audioDataLength; public WaveHeader(int sampleRate, int channelCount, int audioFormat, int audioDataLength) { this.sampleRate = sampleRate; this.channelCount = channelCount; this.audioFormat = audioFormat; this.audioDataLength = audioDataLength; } public void write(OutputStream outputStream) throws IOException { outputStream.write("RIFF".getBytes()); outputStream.write(intToByteArray(36 + audioDataLength), 0, 4); outputStream.write("WAVE".getBytes()); outputStream.write("fmt ".getBytes()); outputStream.write(intToByteArray(16), 0, 4); outputStream.write(shortToByteArray((short) 1), 0, 2); outputStream.write(shortToByteArray((short) channelCount), 0, 2); outputStream.write(intToByteArray(sampleRate), 0, 4); outputStream.write(intToByteArray(sampleRate * channelCount * audioFormat / 8), 0, 4); outputStream.write(shortToByteArray((short) (channelCount * audioFormat / 8)), 0, 2); outputStream.write(shortToByteArray((short) audioFormat), 0, 2); outputStream.write("data".getBytes()); outputStream.write(intToByteArray(audioDataLength), 0, 4); } private byte[] intToByteArray(int value) { byte[] byteArray = new byte[4]; byteArray[0] = (byte) (value & 0xff); byteArray[1] = (byte) ((value >> 8) & 0xff); byteArray[2] = (byte) ((value >> 16) & 0xff); byteArray[3] = (byte) ((value >> 24) & 0xff); return byteArray; } private byte[] shortToByteArray(short value) { byte[] byteArray = new byte[2]; byteArray[0] = (byte) (value & 0xff); byteArray[1] = (byte) ((value >> 8) & 0xff); return byteArray; } } ``` 通过以上代码,我们可以实现将AudioRecord录制音频转换成wav格式并保存到文件中。需要注意的是,由于Android 6.0及以上版本需要动态获取录音权限,因此在使用前需要先请求录音权限。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值