Android 音视频开发(二):使用 AudioRecord 采集音频PCM并保存到文件(学习笔记)
关于 AudioRecord
Android SDK 提供了两套音频采集的API,分别是:MediaRecorder 和 AudioRecord,前者是一个更加上层一点的API,它可以直接把手机麦克风录入的音频数据进行编码压缩(如AMR、MP3等)并存成文件,而后者则更接近底层,能够更加自由灵活地控制,可以得到原始的一帧帧PCM音频数据。
如果想简单地做一个录音机,录制成音频文件,则推荐使用 MediaRecorder,而如果需要对音频做进一步的算法处理、或者采用第三方的编码库进行压缩、以及网络传输等应用,则建议使用 AudioRecord,其实 MediaRecorder 底层也是调用了 AudioRecord 与 Android Framework 层的 AudioFlinger 进行交互的。
音频的开发,更广泛地应用不仅仅局限于本地录音,因此,我们需要重点掌握如何利用更加底层的 AudioRecord API 来采集音频数据(注意,使用它采集到的音频数据是原始的PCM格式,想压缩为mp3,aac等格式的话,还需要专门调用编码器进行编码)。
AudioRecord 的参数配置
audioSource:音频采集的输入源
可选的值以常量的形式定义在 MediaRecorder.AudioSource 类中,常用的值包括:
- 1. DEFAULT (默认)
- 2. VOICE_RECOGNITION (用于语音识别,等同于 DEFAULT )
- 3. MIC (由手机麦克风输入)
- 4. VOICE_COMMUNICATION (用于 VoIP 应用)等等
sampleRateInHz: 采样率
目前 44100Hz 是唯一可以保证兼容所有 Android 手机的采样率。
channelConfig: 通道数
可选的值以常量的形式定义在 AudioFormat 类中,常用的是
- 1. CHANNEL_IN_MONO (单通道)
- 2. CHANNEL_IN_STEREO(双通道)
audioFormat: 数据位宽
可选的值以常量的形式定义在 AudioFormat 类中,常用的是( 1 是可以保证兼容所有Android手机的)
- 1. ENCODING_PCM_16BIT(16bit)
- 2. ENCODING_PCM_8BIT(8bit)
bufferSizeInBytes:AudioRecord 内部的音频缓冲区的大小
该缓冲区的值不能低于一帧“音频帧”(Frame)的大小:
int size = 采样率 x 位宽 x 采样时间 x 通道数
采样时间一般取 2.5ms~120ms 之间,由厂商或者具体的应用决定,我们其实可以推断,每一帧的采样时间取得越短,产生的延时就应该会越小,当然,碎片化的数据也就会越多。
在Android开发中,AudioRecord 类提供了一个帮助你确定这个 bufferSizeInBytes 的函数,原型如下:
int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat);
不同的厂商的底层实现是不一样的,但无外乎就是根据上面的计算公式得到一帧的大小,音频缓冲区的大小则必须是一帧大小的2~N倍。实际开发中,强烈建议由该函数计算出需要传入的 bufferSizeInBytes,而不是自己手动计算。
流程
设置所有 AudioRecord 参数
// 音频输入-麦克风private final static int AUDIO_INPUT = MediaRecorder.AudioSource.MIC;// 采样频率 一般共分为 22.05KHz、44.1KHz、48KHz 三个等级// 44100 是目前的标准,但是某些设备仍然支持 22050,16000,11025private final static int AUDIO_SAMPLE_RATE = 44100;// 声道 单声道private final static int AUDIO_CHANNEL = AudioFormat.CHANNEL_IN_MONO;// 编码private final static int AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;// 缓冲区字节大小private int bufferSizeInBytes = 0;// 录音对象private AudioRecord audioRecord;
创建 AudioRecord 并且获取缓冲区字节大小
/*** 创建默认的录音对象** @param fileName 文件名*/public void createDefaultAudio(String fileName) {// 获得缓冲区字节大小,AudioRecord 能接受的最小的 buffer 大小bufferSizeInBytes = AudioRecord.getMinBufferSize(AUDIO_SAMPLE_RATE, AUDIO_CHANNEL, AUDIO_ENCODING);// 创建默认的录音对象并且设置一系列配置audioRecord = new AudioRecord(AUDIO_INPUT, AUDIO_SAMPLE_RATE, AUDIO_CHANNEL, AUDIO_ENCODING, bufferSizeInBytes);this.fileName = fileName;}
创建 buffer (用于保存新的声音数据),设置 buffer 大小(录制声音数据容量大小)
// new 一个 byte 数组用来存一些字节数据,大小为缓冲区大小byte[] audiodata = new byte[bufferSizeInBytes];
开始录音
audioRecord.startRecording(); // 标志位, 用于控制停止数据流读写循环 isRecording = true;
开始采集,一边从AudioRecord中读取声音数据到初始化的buffer,一边将buffer中数据导入数据流
// 开个子线程将录音的数据放入pcm文件new Thread(new Runnable() {@Overridepublic void run() {writeDataTOFile(listener);}}).start();// 如何将音频写入文件是重点,我写个伪代码,说明这个代码运行顺序// 首先创建 pcm 文件,得到他的 FileOutputStream,然后不断循环 AudioRecord 通过 read 将录音的数据放入字节数组里,// 当录音结束的时候要记得停止这个循环FileOutputStream fos = null;int readsize = 0;try {File file = new File(currentFileName);if (file.exists()) {file.delete();}// 建立一个可存取字节的文件fos = new FileOutputStream(file);} catch (IllegalStateException e) {Log.e("AudioRecorder", e.getMessage());throw new IllegalStateException(e.getMessage());} catch (FileNotFoundException e) {Log.e("AudioRecorder", e.getMessage());}while (isRecording) {readsize = audioRecord.read(audiodata, 0, bufferSizeInBytes);if (AudioRecord.ERROR_INVALID_OPERATION != readsize && fos != null) {try {fos.write(audiodata);} catch (IOException e) {Log.e("AudioRecorder", e.getMessage());}}}
关闭数据流
修改标志位:isRecording 为false,上面的while循环就自动停止了,数据流也就停止流动了,Stream也就被关闭了。
isRecording = false;
停止录音
只要AudioRecord.stop就可以暂停录音了,然后当继续录音时在AudioRecord.start就好了,但是要另创建一个pcm记录,当录音结束时我们要将这些pcm一起转换为一个wav,
至于pcm转换为wav的代码是固定的
停止录音之后,注意要释放资源。if (null != audioRecord) {audioRecord.stop();audioRecord.release();audioRecord = null;recordingThread = null; }
流程走向
- buffer 从 AudioRecord 中拉取声音数据
- 创建一个数据流,开启一个线程,一边从 AudioRecord 中读取数据,一边将数据导入到数据流中
参考文献
- Android音频开发(2):如何采集一帧音频
- Android 音视频开发(二):使用 AudioRecord 采集音频PCM并保存到文件
- Android 音视频深入
Android 音视频开发(二):使用 AudioRecord 采集音频PCM并保存到文件(学习笔记)相关推荐
- android pcm文件大小_Android 音视频开发(二):使用 AudioRecord 采集音频PCM并保存到文件...
一.AudioRecord API详解 AudioRecord是Android系统提供的用于实现录音的功能类. 要想了解这个类的具体的说明和用法,我们可以去看一下官方的文档: AndioRecord类 ...
- Android 音视频开发(一) -- 使用AudioRecord 录制PCM(录音);AudioTrack播放音频
前言,音视频这块,确实比较难入门,本着学习的态度,我这边也跟着 Android 音视频开发入门指南 打怪升级,留下个脚印,大家共勉. 音视频 系列文章 Android 音视频开发(一) – 使用Aud ...
- Android 音视频开发(二) -- Camera1 实现预览、拍照功能
音视频 系列文章 Android 音视频开发(一) – 使用AudioRecord 录制PCM(录音):AudioTrack播放音频 Android 音视频开发(二) – Camera1 实现预览.拍 ...
- Android音视频开发(二)SurfaceView
简介 官方API文档介绍:SurfaceView是View的子类,它内嵌了一个专门用于绘制的Surface,你可以控制这个Surface的格式和尺寸,Surfaceview控制这个Surface的绘制 ...
- Android 音视频开发学习思路
Android 音视频开发这块目前的确没有比较系统的教程或者书籍,网上的博客文章也都是比较零散的.只能通过一点点的学习和积累把这块的知识串联积累起来. 初级入门篇: Android 音视频开发(一) ...
- android音频开发6,Android 音视频开发(一) : 通过三种方式绘制图片
想要逐步入门音视频开发,就需要一步步的去学习整理,并积累.本文是音视频开发积累的第一篇. 对应的要学习的内容是:在 Android 平台绘制一张图片,使用至少 3 种不同的 API,ImageView ...
- Android 音视频开发(三) -- Camera2 实现预览、拍照功能
音视频 系列文章 Android 音视频开发(一) – 使用AudioRecord 录制PCM(录音):AudioTrack播放音频 Android 音视频开发(二) – Camera1 实现预览.拍 ...
- Android 音视频开发(六) -- Android Mediaprojection 截屏和录屏
Android 音视频开发(一) – 使用AudioRecord 录制PCM(录音):AudioTrack播放音频 Android 音视频开发(二) – Camera1 实现预览.拍照功能 Andro ...
- Android音视频开发基础(七):视频采集-系统API基础
前言 在Android音视频开发中,网上知识点过于零碎,自学起来难度非常大,不过音视频大牛Jhuster提出了<Android 音视频从入门到提高 - 任务列表>.本文是Android音视 ...
最新文章
- ORA-01031: insufficient privileges的解决方法
- 你的神经网络不起作用的37个理由
- P5431 【模板】乘法逆元2(小学数学题,毒瘤鱼,卡常之王yyds)
- 【每日提高之声明式事物】spring声明式事务 同一类内方法调用事务失效
- Linux centosVMware shell中的函数、shell中的数组、
- SAP SF打印次数统计
- 通信 / HTTP Host 请求头的作用
- 介绍一些平时用得到的服务/组件
- CF590E-Birthday【AC自动机,最大独立集】
- 因HTTP的Header长度过长导致下载文件名出现乱码的问题
- 47 SD配置-销售凭证设置-激活项目类别的定价
- 安川伺服调试软件_2020南昌三菱伺服回收广东收购价
- win7c盘空间越来越小_电脑一分钟小技巧:如何更改电脑桌面路径?
- python一般的基础代码-Python入门经典练习题
- mysql自定义序号_mysql序列号生成器 mysql自定义函数生成序列号的例子
- 百度地图API详解之公交路线规划
- 7张图让你看懂互联网营销思维与传统思维本质区别
- WebShell --冰蝎
- c 当前程序的语言,c语言实现获取macos当前的系统语言
- 车托帮APP的顽固残留清除
热门文章
- c语言kbhit函数6,C语言中kbhit()函数怎么复位
- 【小米手环7】使用 Zeus + 表盘自定义工具 为小米手环7开发和安装小程序
- 计算机access分数比例,[access查询]关于分数段统计问题
- 伦敦 quant_伦敦统一用户组8
- ArcMAP实现矢量数据平移
- ANTLR4(二) Vistor Listener
- 模拟外线O口呼入时,看不到来电显示号码?
- 《Python 数据科学实践指南》读书笔记
- 【懒懒的Python学习笔记一】
- 哥谭第一季/全集Gotham迅雷下载