随着电子产品的普及,越来越多的年轻人热衷于使用蓝牙技术来播放歌曲(相当多的手机品牌取消了耳机插孔 [狗头]),本篇文章就和大家聊聊蓝牙音乐SRC端在安卓系统中的实现原理。
安卓系统参考版本:Android-9
这些音频输出设备通过HAL框架以一个个单独的模块存在于安卓系统中,音频系统服务层 audioserver 在初始化过程中通过HAL技术加载配置文件支持的模块。这里以蓝牙a2dp为例具体分析下加载模块的时序图:
蓝牙提供的音频系统的动态链接库为:audio.a2dp.default.so
源码路径:/system/bt/audio_a2dp_hw/
音频系统初始化阶段只会加载打开 audio.a2dp.default.so 获取到a2dp模块接口,至于打开输出流只有在A2DP协议连接成功后才会执行。
从以上时序图可以看到 audio.a2dp.default.so 运行在音频服务的进程中,那其又如何与蓝牙服务进程 com.android.bluetooth 交互呢?
跨进程通信有多种方式,audioserver 和 com.android.bluetooth 在蓝牙音乐数据传输场景下通过 socket 完成跨进程通信。
蓝牙协议栈创建如下两种socket与audioserver进行通信:
Bluedroid通过数据socket接收到audio发送过来的音频数据后,根据A2DP连接时双方协商确定的编码方式对数据进行编码操作,最终将编码后的数据通过l2cap链路发送到SNK端。具体时序图如下:
对音频数据进行编码的具体操作则在各编码方式对应的处理函数中完成,源码路径参考:system/bt/stack/a2dp/a2dp_xxx_encoder.cc/a2dp_xxx_encode_frames(),xxx对应A2DP连接使用的编码方式(SBC、AAC、aptX、LDAC等)。
数据最终在bta层 bta_av_data_path() 处理函数中通过 p_scb-p_cos-data() 回调从 btif_a2dp_source_cb.tx_audio_queue 队列中取出,数据随后经过进一步封装发送给SNK端,SNK再反向解码出音频流播放。