Android上的应用一般都是通过AudioTrack类来播放音频,通过AudioRecord类来录制音频。AudioTrack类和AudioRecord类是Android Frameworks封装提供给应用使用的音频接口类。这些类经过层层的Binder、JNI等调用后会调用Audio HAL层提供的相关接口。这些接口实现了对音频设备、通路等一系列操作。就这样最终完成Android App和硬件的交互,实现声音的播放或者录制。
我们知道,在Linux系统中,所有的设备最终都是抽象成一个或者多个用户空间可以访问的设备文件,用户空间的进程通过这些设备文件的读写来达到控制硬件的目的。而这些设备文件都是由内核空间中的驱动程序创建、实现的。手机上的音频设备、接口比较多,对应的设备文件自然也比较多。对于播放声音或者录制声音来说,Audio HAL层是通过对PCM设备文件的读写来实现的。

查看PCM设备列表
如果手机的音频系统正常工作,我们可以通过adb去查看系统中的所有音频设备文件。如下图所示:

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

device type
设备类型,通常只有compr/hw/pcm这3种。从上图可以看到声卡会管理很多设备,PCM设备只是其中的一种设备。
card index
声卡的id,代表第几块声卡。通常都是0,代表第一块声卡。手机上通常都只有一块声卡。
device index
设备的id,代表这个设备是声卡上的第几个设备。设备的ID只和驱动中配置的DAI link的次序有关。如果驱动没有改变,那么这些ID就是固定的。
capture/playback
只有PCM设备才有这部分,只有c和p两种。c代表capture,说明这是一个提供录音的设备,p代表palyback,说明这是一个提供播放的设备。
系统会在/proc/asound/pcm文件中列出所有的音频设备的信息,如果是肉眼查看,/proc/asound/pcm中的信息会更直观一些:


PCM设备文件的访问
查看PCM设备文件的属性,可看到它们都是字符型设备:

对于普通的字符型设备,我们都是通过系统调用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,然后就可以去获取操作它的句柄,然后做更多的操作。

PCM设备的管理 —— PCM ID
如果我们查看不同型号的手机上的音频设备列表,可以看到它们几乎都是不一样的,有的手机设备文件多,有的手机设备文件少。实际上不只是设备文件个数的差别,还有可能出现在A型号手机上speaker对应的PCM设备文件是/dev/snd/pcmC0D4p,而在B型号手机上speaker对应的PCM设备文件却是/dev/snd/pcmC0D7P。因此,Audio HAL中需要考虑到这种场景差异的影响。
我们已经知道,使用TinyAlsa接口访问PCM设备的时候,需要知道设备的id,这个id我们称为PCM ID,那么如何知道某一个设备例如speaker的PCM ID呢?另外,在不接耳机的时候,我们希望声音从speaker出来,这时候需要知道的是speaker的PCM ID,如果接了耳机,我们又希望声音从耳机出来,这时候需要知道的是耳机的PCM ID。
针对这些问题、需求,Audio HAL的设计是根据使用场景(USECASE)来决定要使用哪些设备的,即为各个USECASE分别定义好要使用的PCM设备的ID。Frameworks通过USECASE来指定PCM设备,而Audio HAL通过USECASE来找到PCM设备文件路径。
如下图所示,Audio HAL通过pcm_device_table这张表完成USECASE到PCM ID的映射。因此,PCM设备的管理实际上就是管理这张映射表。

USECASE与PCM ID的映射关系可以通过配置文件来修改,这样的好处就是所有产品可以使用同一套代码,差异的地方可以通过控制配置文件的内容就可以简单的区分开来,Audio HAL会解析这个配置文件,然后更新映射表内容。使用adb shell cat /system/etc/audio_platform_info.xml可以看到如下配置:

如上图,就会把USECASE_AUDIO_PLAYBACK_LOW_LATENCY这个使用场景的PCM ID更新为12。其他应用场景的PCM ID更新也是类似。

Android中的PCM设备相关推荐

  1. android pcm文件大小_Android中的PCM设备

    Android上的应用一般都是通过AudioTrack类来播放音频,通过AudioRecord类来录制音频.AudioTrack类和AudioRecord类是Android Frameworks封装提 ...

  2. Android中获取手机设备信息、RAM、ROM存储信息,如宽、高、厂商名、手机品牌

    借鉴:https://www.jianshu.com/p/ca869aa2fd72 今天有两个工具类总结,代码里都有注释,直接看代码. 一.首先第一个,主要获取手机设备信息DeviceInfoUtil ...

  3. android蓝牙连接耳机分析,如何在android中获取蓝牙耳机设备的信息(特别是耳机设备名称)...

    我终于解决了这个问题 . 以前我从"BluetoothAdpter"类获得了所有绑定设备的"getBondedDevices()"方法 . 但我通过使用&quo ...

  4. PCM设备在电网系统中的应用介绍

    近年来,随着我国社会经济的快速发展和电力通信行业的不断进步,通信网络技术和网络系统不断完善和改进的同时,网络系统运行过程中也出现了很多的问题,要对其进行优化,否则可能影响电力通信网络的正常运行电力通信 ...

  5. PCM设备在雷达通信系统应用

    PCM设备系统是目前国内企业最常用的综合接入通信设备,PCM设备所具优势众多,因此它能成为目前企业最常用的通信传输接入设备之一,而且在类似雷达通信系统等重要行业中广泛应用着. PCM设备利用标准的E1 ...

  6. android 使用kotlin 获取设备id

    在 Android 中,获取设备的唯一标识符是一项常见的任务.以下是使用 Kotlin 语言获取设备 ID 的步骤: 1. 在 AndroidManifest.xml 文件中添加以下权限: <u ...

  7. android中调用fft函数,J使用PCM数据在Android中转换FFT(JTransforms FFT in Android from PCM data)...

    J使用PCM数据在Android中转换FFT(JTransforms FFT in Android from PCM data) 我一直在玩这个游戏已经有一段时间了,我无法弄清楚我在这里要做的事情. ...

  8. android 打开wifi并链接到制定ip,当设备连接到Android中的WiFi时,如何获取蜂窝网络的IP地址...

    有没有办法我可以在 Android中同时获取WiFi和蜂窝网络的IP地址.我尝试使用很多例子,但是只能获得WiFi网络的地址而不是蜂窝网络.我启用了WiFi和蜂窝网络,设备正在通过WiFi上网. 以下 ...

  9. android 删除模拟器,android – 如何从avd设备中删除脱机模拟器?

    我在Android Studio中创建了几个AVD-s.他们在模拟器端口5554上启动.然后我通过android avd应用程序创建了另一个AVD,他们从端口5556开始. 现在运行一个模拟器,我从a ...

  10. Android调用uc播放器,在UC android浏览器中使用摄像头设备(WebRTC API)

    我们正在开发Web应用程序,它应该使用摄像头设备(WebRTC标准)来读取QR码,并且我们是UC Android浏览器中的严重问题. 这里是我们的应用程序的例子https://www.publicst ...

最新文章

  1. (C++)1008 数组元素循环右移问题
  2. 特征工程学习,19 项实践 Tips!代码已开源!
  3. 干货丨从概念到案例:初学者须知的十大机器学习算法
  4. linux c strdup 字符串拷贝
  5. Java中的泛型方法
  6. 003_JSONNull对象介绍
  7. Windows环境下利用VS和mingw编译LLVM
  8. springboot不能加载https的证书文件(二)
  9. PAT (Advanced Level) 1016 Phone Bills(恶心模拟)
  10. Spring5参考指南:事件Event
  11. js打乱数组的顺序_如何用 js 实现一个类似微信红包的随机算法
  12. Oracle AWR ASH
  13. python代码片段_Python 常用代码片段
  14. 0x29——如何把自己iphone app传到iphone上
  15. python词云图_人生苦短我用Python——词云图的绘制
  16. 【TensorFlow-windows】(五) CNN(卷积神经网络)对cifar10的识别
  17. 李飞飞李佳“逆风翻盘”:谷歌全新AutoML产品发布,AI客服规模化商用
  18. 计算机发展史的第五个阶段,信息技术的发展历程是怎样的? 信息技术的发展历程分五个阶段...
  19. 解决阿里云轻量应用服务器不能安装应用
  20. 地图开发实战案例:高德地图弧线连接线标注

热门文章

  1. sqlalchemy的基本操作大全
  2. 鲍斯科机器人_芜湖鲍斯柯机器人有限公司、上海富治机械科技有限公司服务合同纠纷二审民事判决书...
  3. 百度地图api去除logo,以及三维按钮
  4. Android 项目必备(二十三)-->减小 APK 大小
  5. 实现汉字的凯撒密码(内容包括:去掉字符串中的转义字符、汉字的unicode转换)
  6. matlab构建boost电路,基于matlab的boost电路仿真.doc
  7. mysql查看表编码_MySQL中使用SQL语句查看某个表的编码方法
  8. 利用Python的sympy包求解一元三次方程
  9. 超级简单的三次方程求解!
  10. 综合布线(楼栋)设计报告