Android录音上————AudioRecord实现录音功能
16lz
2021-01-25
Android多媒体1————AudioRecord实现录音功能
一.前言
在百度实习的时候,导师让我负责语音助手SDK相关的东西,所以就一直想对其进行整理总结,就先从最基础,最简单AudioRecord类开始。
二.官方文档中的AudioRecord
想要了解一个类的具体说明,首先要看看官方文档:
1.概述
AndioRecordlei类的主要功能是让各种JAVA应用管理音频资源,方便从平台的音频输入硬件录制音频。此功能的实现是通过“pulling”(读取)AndioRecord对象的声音数据来完成。在录制过程中,应用所需要的是通过后面三个类方法中的一个区及时获取AudioRecord对象的录音数据。
开始录音时,AudioRecord需要一个初始化相关联的声音buffer,这个buffer主要用来存储新的声音数据,这个buffer的大小,我们可以在对象的构造期间去指定,它表明一个AudioRecord对象还没用被读取(同步)声音数据前能录多长的音。声音数据从音频硬件被读取出来,数据大小不超过整个录音数据的大小(可以分多次读取),即每次读取初始化buffer容量的数据。
2.实现Android录音的流程
- 构造一个AudioRecord对象,其中需要的最小录音缓存buffer大小通过getMinBufferSize得到,如果buffer容量过小,将导致对象构造的失败
- 初始化一个buffer,该buffer大于等于AudioRecord对象用于声音数据的buffer大小
- 开始录音
- 创建一个数据流,一边从AudioRecord中读取数据初始化的buffer,一边将buffer中的数据导入数据流中
- 关闭数据流
- 停止录音
三.相关的API
1.构造方法
AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes)
参数简介:
- audioSource:指的是从哪里采集音频。这里我们当然是从麦克风采集音频,所以此参数的值为MIC
- sampleRateInHz:音频的采样频率,每秒钟能够采样的次数,采样率越高,音质越高。给出的实例是44100、22050、11025但不限于这几个参数。例如要采集低质量的音频就可以使用4000、8000等低采样率。
- channelConfig:android支持双声道和单道声,MONO单声道,STEREO立体声
- audioFormat:采集来的数据使用PCM编码,Android支持的采用大小为16bit或者8bit。采样越大,信息量越多,音质也越高可以在getMinBufferSize()查看。
- bufferSizeInBytes:采集数据需要缓存区的大小,如果不知道最小需要的大小
2.公共方法
- int getAudioFormat():返回配置的音频数据格式
- int getAudioSessionId():返回音频会话 id。
- int getAudioSource():返回音频录制源。
- int getChannelConfiguration():返回配置的通道配置。
- int getChannelCount():返回配置的通道数。
- static int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat):返回成功创建 audio 记录对象所需的最小缓冲区大小 (以字节为单位)。
- int getNotificationMarkerPosition():返回以框架表示的通知标记位置。
- int getPositionNotificationPeriod():返回以框架表示的通知更新期间。
- int getRecordingState():返回音频记录实例的录制状态。
- int getSampleRate():返回以 hz 为单位的配置音频数据采样率
- int getState():返回音频记录实例的状态。
- int read(short[] audioData, int offsetInShorts, int sizeInShorts):从音频硬件读取音频数据, 以便录制到缓冲区中。
- int read(byte[] audioData, int offsetInBytes, int sizeInBytes):从音频硬件读取音频数据, 以便录制到缓冲区中。
- int read(ByteBuffer audioBuffer, int sizeInBytes):从音频硬件读取音频数据, 以便录制到缓冲区中。
- void release():释放本机AudioRecord资源
- int setNotificationMarkerPosition(int markerInFrames)
- int setPositionNotificationPeriod(int periodInFrames)
- void setRecordPositionUpdateListener(AudioRecord.OnRecordPositionUpdateListener listener, Handler handler):设置AudioRecord通知的侦听器,当达到先前设置的标记时,或每次定期记录头位置更新时。
- void startRecording():从AudioRecord实例开始记录。
- void startRecording(MediaSyncEvent syncEvent):当指定的同步事件在指定的音频会话上发生时,从AudioRecord实例开始记录。
- void stop():停止记录
四.使用示例
public class AudioRecordImpl { private static final String TAG = "AudioRecordImpl"; // 采样率 private static final int SAMPLE_RATE_HZ = 16000; private static final int BUFFER_SIZE = 640; private AudioRecord audioRecord; private Thread recordThread; //采样频率 private int mAudioSampleRate = SAMPLE_RATE_HZ; //音频源 private int mAudioSource = MediaRecorder.AudioSource.MIC; //编码大小 private int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT; //选择声道 private int mAudioChannel = AudioFormat.CHANNEL_IN_MONO; // 用于数据统计 private volatile boolean isQueryLog; private volatile boolean isStartRecord = false; public AudioRecordImpl() { setAudio(SAMPLE_RATE_HZ, MediaRecorder.AudioSource.MIC, AudioFormat.ENCODING_PCM_16BIT, AudioFormat.CHANNEL_IN_MONO); } //默认设置 public void setAudio(int sampleRate, int source, int format, int channel) { mAudioSampleRate = sampleRate; mAudioSource = source; mAudioFormat = format; mAudioChannel = channel; } //开始录音 public v startRecord() { stopRecord(); if (recordThread != null) { try { //t.join()方法阻塞调用此方法的线程(calling thread), // 直到线程t完成,此线程再继续 recordThread.join(); } catch (InterruptedException e) { e.printStackTrace(); } } //设置线程优先级,android.os.Process.THREAD_PRIORITY_AUDIO-标准音乐播放使用的线程优先级 android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_AUDIO); //获取最小buffer final int bufferSize = AudioRecord.getMinBufferSize( mAudioSampleRate, mAudioChannel, mAudioFormat); try { // 防止某些手机崩溃 //创建audioRecord对象 audioRecord = new AudioRecord(mAudioSource, mAudioSampleRate, mAudioChannel, mAudioFormat, bufferSize * 10); } catch (Exception e) { e.printStackTrace(); LogUtil.dcf(TAG, "new AudioRecord() IllegalStateException ", e); } isStartRecord = true; recordThread = new Thread() { @Override public void run() { super.run(); try { // 防止某些手机崩溃 if (audioRecord != null) { audioRecord.startRecording(); } } catch (IllegalStateException e) { e.printStackTrace(); LogUtil.dcf(TAG, "startRecording IllegalStateException ", e); isStartRecord = false; } isQueryLog = true; while (isStartRecord) { try { //读取语音数据 byte[] buffer = new byte[BUFFER_SIZE]; int readBytes = audioRecord.read(buffer, 0, buffer.length); if (readBytes > 0) { //处理语音数据 fireData(buffer); } } } catch (Exception e) { e.printStackTrace(); LogUtil.ecf(TAG, "audio recorder exception," + e); isStartRecord = false; } } // 释放资源 try { if (audioRecord != null) { audioRecord.release(); LogUtil.ic(TAG, "audioRecorder release "); } } catch (Exception e) { e.printStackTrace(); LogUtil.wcf(TAG, "stop and release IllegalStateException ", e); } finally { audioRecord = null; } } }; recordThread.start(); } //停止录音 public void stopRecord() { LogUtil.dc(TAG, "stopRecord"); isStartRecord = false; } //释放资源 public void release() { //释放资源 LogUtil.dc(TAG, "release"); stopRecord(); }}
五.参考资料
官方文档
Android 音视频开发(二):使用 AudioRecord 采集音频PCM并保存到文件
更多相关文章
- “罗永浩抖音首秀”销售数据的可视化大屏是怎么做出来的呢?
- Nginx系列教程(三)| 一文带你读懂Nginx的负载均衡
- 不吹不黑!GitHub 上帮助人们学习编码的 12 个资源,错过血亏...
- Android去除TextView文本中的默认内边距
- android wear端数据和手机端数据
- 五步学会Android的ListView控件
- Android(安卓)PopupWindow with ListView的一些问题
- Android(安卓)重要数据目录
- understand and use android mvc(理解及使用android mvc)