常规录音

可以参考传送门_2learn

MediaRecord

传统的android上,最简单的录音方式,莫过于MediaRecord

mMediaRecorder = new MediaRecorder();//初始实例化。
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);//音频输入源
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_WB);//设置输出格式
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_WB);//设置编码格式
mMediaRecorder.setAudioEncodingBitRate(16000);
mMediaRecorder.setOutputFile(file.getAbsolutePath());//设置输出文件的路径
mMediaRecorder.prepare();//准备录制
mMediaRecorder.start();//开始录制

MediaRecord主要用于直接录音压缩率比较高的成品文件,不对中间的buffer进行二次加工的应用场景。
优点:实现简单,直接调用相关接口即可,代码量小;通过设置编码器,压缩录音文件的大小;
缺点:无法实时处理音频;输出的音频格式不多,如没有输出mp3格式文件。

AudioRecord

稍微进阶一点的录音方式,就是AudioRecord

mMinBufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE, CANNEL_CONFIG, FORMAT);
mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLE_RATE,CANNEL_CONFIG, FORMAT, mMinBufferSize);
mData = new byte[mMinBufferSize];
mAudioRecord.startRecording();...
while (mIsRecording) {int read = mAudioRecord.read(mData, 0, mMinBufferSize);
}

AudioRecord的参数设置与MediaRecord大同小异,区别在于AudioRecord将读取到的data传递给程序员,让程序员自己操作,因此录制出来的是比较原始的PCM音频格式。如果想要压缩大小需要配合AudioEncoder使用自己编写编码器,相对复杂一些。

优点:可以对实时语音的实时处理(变声软件,ASR识别等);
缺点:录制文件较大,需要自己封装。

OpenSL ES

这种方式相对复杂一些,主要是面向native开发者,提供标准化,高性能,低响应时间的音频功能。

slCreateEngine(&engineObject, 1, EngineOption, 0, NULL, NULL);
...
(*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
...result = (*engineEngine)->CreateAudioRecorder(engineEngine, &recorderObject , &recSource, &dataSink, NUM_EXPLICIT_INTERFACES_FOR_RECORDER, iids, required);
result = (*recorderObject)->GetInterface(recorderObject, SL_IID_RECORD, &recordItf);
...result = (*recordItf)->RegisterCallback(recordItf, recCallback, NULL);result = (*recBuffQueueItf)->RegisterCallback(recBuffQueueItf, recBufferQueueCallback, &cntxt)
...

参考

优点:追求极致效率,比如结合C++的推流或者其他native的业务,减少java和native的拷贝;面向ndk开发;
缺点:实现复杂;AudioRecord足以胜任。

非常规录音

在Linux系统中,所有的设备最终都是抽象成一个或者多个用户空间可以访问的设备文件,用户空间的进程通过这些设备文件的读写来达到控制硬件的目的。而这些设备文件都是由内核空间中的驱动程序创建、实现的。手机上的音频设备、接口比较多,对应的设备文件自然也比较多。对于播放声音或者录制声音来说,Audio HAL层是通过对PCM设备文件的读写来实现的。
所以,在常规录音之外还有1种方案,通过JNI直接读取音频设备节点。这种方案,要求对具体设备和平台的情况有十分的了解,属于定制开发,因为它的适配性不强,针对某一款设备的设备节点的编写,不一定适配其他平台和厂商。

PCM设备

接下来,稍微展开介绍一下:

设备上面,ls /dev/snd/,可以看到所有的音频设备:

crw-rw----  1 system audio 116,   2 2020-08-19 16:42 controlC0
crw-rw----  1 system audio 116,   6 2020-08-19 16:42 controlC1
crw-rw----  1 system audio 116,   9 2020-08-19 16:42 controlC2
crw-rw----  1 system audio 116,   4 2020-08-19 16:42 pcmC0D0c 录音
crw-rw----  1 system audio 116,   3 2020-08-19 16:42 pcmC0D0p
crw-rw----  1 system audio 116,   5 2020-08-19 16:42 pcmC0D1c 录音
crw-rw----  1 system audio 116,   8 2020-08-19 16:42 pcmC1D0c 录音
crw-rw----  1 system audio 116,   7 2020-08-19 16:42 pcmC1D0p
crw-rw----  1 system audio 116,  11 2020-08-19 16:42 pcmC2D0c 录音
crw-rw----  1 system audio 116,  10 2020-08-19 16:42 pcmC2D0p
crw-rw----  1 system audio 116,  33 2020-08-19 16:42 timer

那些以pcm打头的设备就是提供播放或录音的设备即本文要探讨的PCM设备,其他的设备提供效果、合成等功能。音频设备的命名规则为[device type]C[card index]D[device index][capture/playback],即名字中含有4部分的信息:

  1. device type
    设备类型,通常只有compr/hw/pcm这3种。从上图可以看到声卡会管理很多设备,PCM设备只是其中的一种设备。

  2. card index
    声卡的id,代表第几块声卡。通常都是0,代表第一块声卡。手机上通常都只有一块声卡。

  3. device index
    设备的id,代表这个设备是声卡上的第几个设备。设备的ID只和驱动中配置的DAI link的次序有关。如果驱动没有改变,那么这些ID就是固定的。

  4. capture/playback
    只有PCM设备才有这部分,只有c和p两种。c代表capture,说明这是一个提供录音的设备,p代表palyback,说明这是一个提供播放的设备。

系统会在/proc/asound/pcm文件中列出所有的音频设备的信息,/proc/asound/pcm中的信息会更直观一些。

cat /proc/asound/pcm
00-00: ff070000.i2s-rk817-hifi rk817-hifi-0 :  : playback 1 : capture 1
00-01: ff0a0000.pdm-rk817-voice rk817-voice-1 :  : capture 1
01-00: ff060000.i2s-rk618-hifi rk618-hifi-0 :  : playback 1 : capture 1
02-00: ff080000.i2s-bt-sco-pcm bt-sco-pcm-0 :  : playback 1 : capture 1

tinyAlsa

对于普通的字符型设备(查看附录),我们都是通过系统调用open/read/write/close来访问,有些设备支持随机访问,我们还可以使用lseek调用。PCM设备文件也是类似,不一样的是,我们可以使用open/close来打开/关闭设备,读取/写入文件却不是通过read/write,而都是通过ioctl来操作的。

在Android Audio HAL层中,是通过TinyAlsa来访问PCM设备文件的。TinyAlsa封装了一系列接口用于PCM设备的访问,这些接口被Audio Hal调用以后,最终又会被Frameworks调用。接口包括:

struct pcm *pcm_open(unsigned int card, unsigned int device, unsinged int flags, struct pcm_config *config)
int pcm_close(struct pcm* pcm)
int pcm_write(struct pcm *pcm, const void* data, unsigned int count)
int pcm_read(struct pcm* pcm, void* data, unsigned int count)

从pcm_open这个接口可以看到,它通过几个参数获得了一个句柄,之后所有的操作都通过这个句柄来完成。这些参数里面,card代表第几块声卡,device就是上面提到的device index,它跟驱动中配置的DAI link的次序有关,flags参数中会指明这个设备是capture类型还是playback类型。通过这3个参数,就可以找到对应的PCM设备文件,例如 /dev/snd/pcmC0D5p,然后就可以去获取操作它的句柄,然后做更多的操作。

我们可以通过集成tinycap的代码,编写JNI代码来实现从JNI直接读取buffer。tinyalsa的源码可以在github上,随便搜搜一份,大同小异,自行实现jni源码:

struct pcm_config config;
//...init config
pcm_open(card, device, PCM_IN, &config);
//... buff size
size = pcm_frames_to_bytes(pcm, pcm_get_buffer_size(pcm));
buffer = (char*)malloc(size);
// read
while (!pcm_read(pcm, buffer, size)) {//...
}

调试阶段可以使用tinycap命令:

每个机型,每家方案商的命令可能有差异,因为这个tinycap就是一个cpp代码编译而来的执行文件,因此,参数的入参是他们自己决定的:

tinymix 1 1这个是打开回采的

tinycap /sdcard/record.pcm -D 0 -d 1 -c 4 -r 16000 -b 16

附录

单声道:采样率1600016/81=32000bytes/second; 一分钟就是3200060=1920000bytes≈1.83MB。
单声道:采样率16000
16/82=64000bytes/second; 一分钟就是6400060=3840000bytes≈3.66MB。
(1)字符设备:提供连续的数据流,应用程序可以顺序读取,通常不支持随机存取。相反,此类设备支持按字节/字符来读写数据。举例来说,键盘、串口、调制解调器都是典型的字符设备。我们都是通过系统调用open/read/write/close来访问,有些设备支持随机访问,我们还可以使用lseek调用。

(2)块设备:应用程序可以随机访问设备数据,程序可自行确定读取数据的位置。硬盘、软盘、CD-ROM驱动器和闪存都是典型的块设备,应用程序可以寻址磁盘上的任何位置,并由此读取数据。此外,数据的读写只能以块(通常是512B)的倍数进行。与字符设备不同,块设备并不支持基于字符的寻址。

android录音mediaRecord\AudioRecord\openSL\PCM tinyalsa总结和优缺点相关推荐

  1. Android录音下————AudioRecord源码分析

    Android录音下----AudioRecord源码分析 文章目录 Android录音下----AudioRecord源码分析 一.概述 1.主要分析点 2.储备知识 二.getMinBufferS ...

  2. Android 录音工具AudioRecord使用

    1.工具类代码 import android.media.AudioFormat; import android.media.AudioRecord; import android.media.Med ...

  3. Android 音视频开发(一) -- 使用AudioRecord 录制PCM(录音);AudioTrack播放音频

    前言,音视频这块,确实比较难入门,本着学习的态度,我这边也跟着 Android 音视频开发入门指南 打怪升级,留下个脚印,大家共勉. 音视频 系列文章 Android 音视频开发(一) – 使用Aud ...

  4. android中录音断点播放,Android实现暂停--继续录音(AudioRecord)

    Android提供了两个API用于录音的实现:MediaRecorder 和 AudioRecord,各有优劣. 1.MediaRecorder 已经集成了录音.编码.压缩等,支持少量的录音音频格式, ...

  5. Android 录音实现(AudioRecord)

    AudioRecord 首先看看Android帮助文档中对该类的简单概述: AndioRecord 类的主要功能是让各种 Java 应用能够管理音频资源,以便它们通过此类能够录制平台的声音输入硬件所收 ...

  6. Android使用AudioRecord录制PCM音频、PCM转AAC、使用MediaRecorder直接录制AAC编码音频

    Android为我们提供了两个音频处理的API:AudioRecord和MediaRecorder AudioRecord:偏底层的api MediaRecorder:对AudioRecord进行包装 ...

  7. android 录音原始文件_Android 录音详解(一)—— MediaRecorder、AudioRecord、生成wav格式、边录边播...

    Android 录音详解(一)-- MediaRecorder.AudioRecord.生成wav格式.边录边播 越来越多的 APP 都用到了手机的录音功能,比如搜索.聊天.输入.K歌等... 本系列 ...

  8. Android录音AudioRecord,AudioTrack学习

    音频相关知识讲解了音频相关的基础知识,然后说明了Android中对音频的处理用到的类,接下来将开始讲解利用AudioRecord进行音频录制,和利用AudioTrack对录制的PCM格式文件进行播放. ...

  9. [Android] [音视频系列]在 Android 平台使用 AudioRecord 和 AudioTrack API 完成音频 PCM 数据的采集和播放,并实现读写音频 wav 文件

    参考 官方文档地址:https://developer.android.google.cn/reference/android/media/AudioRecord GitHub 地址:https:// ...

最新文章

  1. 一些关键字表明变量属性值
  2. 用python实现计算器功能_使用python实现计算器功能
  3. R语言数据可视化 ggplot2基础2 创建单图层的散点图 创建facet
  4. php mysql 简单聊天室_聊天室phpmysql(一)
  5. c++ 函数的值传递,引用传递 和 引用返回的探索
  6. django models索引_sql – 为什么Django显式地在唯一字段上创建索引
  7. 通过NGINX location实现一个域名访问多个项目
  8. 第四章、epub文件处理 -- epub文件内部组成
  9. linux指令解压rpm,dpkg rpm apt yum 的常用指令 +linux 各种解压缩方法.docx
  10. python导出mysql授权语句
  11. 组复制官方翻译六、Upgrading Group Replication
  12. 同步代码时忽略maven项目 target目录
  13. 实验2-2-1 计算分段函数[1] (10 分)
  14. 多小区下小区上行速率的计算(2)
  15. excel组合汇总_Excel汇总20151102
  16. 关于NVIDIA显卡驱动更新后,没有NVIDIA 控制面板的解决办法
  17. lpx寒假作业案例15
  18. Mohican_4/22 结构体 typedef 枚举 联合 位段 内存对齐
  19. 面对陌生环境,机器人如何像人一样自由穿行?
  20. linux通讯录软件带头像,Ubuntu联系人应用已支持增强的头像功能

热门文章

  1. java ssm人体健康体检信息管理系统-
  2. python出行轨迹记录软件_看看过去跑过哪些地方,用Python和高德API绘制跑步轨迹...
  3. 手机怎样测海拔高度?手机测量海拔的方法分享。
  4. Cerebral Cortex:初为人父者竟然出现纵向灰质皮层体积减少?两个国际样本提供了这样的证据...
  5. 汉初百年儒家士人与地方社会
  6. 32 《奇特的一生》 -豆瓣评分8.5
  7. 制作仅在xy方向有周期性的夹层结构,且不使用约束平板
  8. 【Android视频 之 阿里云视频播放器 二】
  9. How To JUST DO IT
  10. 三维扫描仪的数据化时代