需要实现的功能:
输入:hdmiin、uvc、mic可以实时切换
输出:耳机和HDMI OUT同时输出声音
这里注意:mic是存在hedset情况,4节耳机,即可输出又可输出同时进行
开发情况:
一、先熟悉大致的Android的音频架构及流程:
1.apk想要录音,播音的接口:常用接口
AudioManager:音频管理器,包括音量管理、AudioFocus管理、音频设备管理、模式管理;
录音:AudioRecord、MediaRecorder;
播放:AudioTrack、MedaiPlayer、SoundPool、ToneGenerator;
编解码:MediaCodec,音视频数据 编解码接口。
2.JNI
与 android.media 关联的 JNI 代码会调用较低级别的原生代码来访问音频硬件。JNI 位于 frameworks/base/core/jni/ 和 frameworks/base/media/jni 中。
3.Native framework 原生框架
原生框架提供相当于 android.media 软件包的原生软件包,它调用 Binder IPC 代理来访问媒体服务器的音频专属服务。 原生框架代码位于 frameworks/av/media/libmedia 中。
原生框架代码位于 frameworks/av/media/libmedia 或frameworks/av/media/libaudioclient中(不同版本,位置有所改变)。
4.Binder IPC
Binder IPC 代理用于促进跨越进程边界的通信。代理位于 frameworks/av/media/libmedia 中,并以字母“I”开头。
5.Audio Server 媒体服务器
Audio系统在Android中负责音频方面的数据流传输和控制功能,也负责音频设备的管理。这个部分作为Android的Audio系统的输入/输出层次,一般负责播放PCM声音输出和从外部获取PCM声音,以及管理声音设备和设置(注意:解码功能不在这里实现,在android系统里音频视频的解码是opencore或stagefright完成的,在解码之后才调用音频系统的接口,创建音频流并播放)。Audio服务在Android N(7.0)之前存在于mediaserver中,Android N开始以audioserver形式存在,这些音频服务是与HAL 实现进行交互的实际代码。媒体服务器位于 frameworks/av/services/audioflinger 和frameworks/av/services/audiopolicy中。
6.Audio服务包含AudioFlinger 和AudioPolicyService:
AudioFlinger:主要负责音频流设备的管理以及音频流数据的处理传输,⾳量计算,重采样、混⾳、⾳效等。
AudioPolicyService:主要负责⾳频策略相关,⾳量调节⽣效,设备选择,⾳频通路选择等。
7.hal层
定义了音频服务会调用且您必须实现才能使音频硬件正常运行的标准接口。音频 HAL 接口位于 hardware/libhardware/include/hardware 中。详情可参阅 audio.h。对于不同的平台可能具体代码路径不一样,这里rk3588Android12平台hal层相关处理代码在 /hardware/rockchip/audio目录
8.内核声卡驱动程序
音频驱动程序用于同您的硬件和 HAL 实现进行交互。可以使用高级 Linux 声音架构 (ALSA)、开放声音系统 (OSS) 或自定义驱动程序(HAL 与驱动程序无关)。
对于驱动具体的详细不在这里说,驱动涉及了codec和i2s或者pdm等的适配,及相关寄存器,snd_control操作
9.开源的调试用例
使用的是 ALSA,建议将 external/tinyalsa 用于驱动程序的用户部分,因为它具有兼容的许可(标准的用户模式库已获得 GPL 许可)。通常sdk里面都自带了tinyalsa相关测试源码,
二、介绍里面相关功能的具体是西安及相关修改
1.查看原理图,
1)我们需要驱动es8388这颗芯片做模拟输入和模拟输出使用。
2)hdmiout接口自带音频输出,需要进行配置
3)hdmiin接口,需要配置音频输入(这里涉及到rk自己的驱动)
4)uvc 需要配置相关uac驱动,usb相关驱动内核已有支持
rk3588自带的hdmi in、out,以及usb具体配置不细说了。有文档可以参考文档,这里简单说一下es8388相关处理
查看原理图,知道具体使用哪路i2s,adc检测,模拟输出走哪一路,模拟输入走哪一路。因为这里没有做耳机检测,我们需要去掉es8388官方驱动里面相关的中断触发以及extcon状态上报
添加adc接口读取电压值,检测mic插入。因为耳机需要一直保持输出且输入也是固定一个通路,只需要设置extcon状态一直为1即可,然后配置LINE1 通路寄存器使能
相关初始化寄存器配置
matchine驱动对于相关拔插检测和exton注册都可以去掉
codec相关配置
驱动编译成功,正常跑起来如果看到如下,说明声卡已经创建成功1:
此时我们可以编译tinyalsa进行测试驱动是否可行。tinyalsa路径: /external
相关使用方法
1.录制:
tinycap /sdcard/xxx.wav -D X -d 0 -r 48000 (-D是选择声卡,录制的数据保存到xx.wav中,采样率使用48000)
tinyplay /sdcard/xxx.wav -D X -d 0 -r 48000(播放,其他同理)
tinymix 主要配置驱动相关接口控制,比如音频通道,模拟音量,Tinymix 可以得到音频通路相关的各项配置参数。也可以通过添加参数修改
其中的配置。如下:
Tinypcminfo 查看 pcm 通道的相关信息 比如查看声卡0如下:
2.音频hal层相关修改
确定声卡注册成功后,开机加载 hal 层音频模块的时候,会根据声卡的名字找到声卡对应的codec 通道配置文件,我们可以通过抓取logcat log 确定声卡对应的通道配置文件。
具体可以修改如下代码,打开相关log,然后查看log进行相关codec配置以及声卡通路的选择
我的修改如下:
为了快速调试,我们可以直接编译hal层相关代码,到目录下mm即可。编译完会生成一个audio.primary.rk30board.so,我们用adb直接push到
system/vendor/lib64/hw/目录覆盖掉,重启即可生效。查看log
我们可以知道使用哪个config,在config_list.h中定义(Android平台都是此文件名)
这个时候我们就需要针对不同的场景配置不同的config,参考tinymix打印,比如配置播音
相关配置完成后,我们要查看具体选择声卡实现的代码 audio_hw.c 关注这两个接口
加上打印,进行调试,比如采样率,声卡,type等,比如同时出声需要在这里强制设置。同时打开两个声卡
3.进行策略选择的调试
Andorid相关测略的选择,具体实现内容复杂,涉及到进程间通信,我们这里直接看影响到选择哪个输入输出设备的地方
文件路径:
frameworks/av/services/audiopolicy/enginedefault/src/Engine.cpp
输入策略相关接口
sp<DeviceDescriptor> Engine::getDeviceForInputSource(audio_source_t inputSource) const
我们可以打开debug进行调试,最终我们是uvc hdmi mic切换修改如下:
最好对于apk也要进行相关设置,主要是通过设置属性,来选择通道。
如下:
大致就是这些,具体一些没说清楚的可以讨论