除了使用HIDL来区分蓝牙的公共stack和vendor lib,Oreo对蓝牙A2DP的支持也更加全面。除了A2DP profile强制支持的SBC,Oreo新增了对AAC、APTX、LDAC的编码定义。具体是否支持,还得看实现。这里简单说明Oreo是如何做到支持多种编码,并选择合适的编码方式的。

Java world的声明

codec的支持是A2DP profile的声明的。在Bluetooth.apk中,编码的支持包含在A2dpStateMachine当中。它在自己的构造函数中对编码的支持进行了初始化:

    private A2dpStateMachine(A2dpService svc, Context context) {//......mCodecConfigPriorities = assignCodecConfigPriorities();initNative(mCodecConfigPriorities);//......}

assignCodecConfigPriorities的作用是,首先加载各个codec的priority,再将每个支持的codec参数初始化。codec的priority保存在配置文件values/config.xml中。就目前的设置来看,它支持五种编码:

    <!-- Configuring priorities of A2DP source codecs. Larger value meanshigher priority. Value -1 means the codec is disabled.Value 0 is reserved and should not be used here. Enabled codecsshould have priorities in the interval [1, 999999], and each priorityvalue should be unique. --><integer name="a2dp_source_codec_priority_sbc">1001</integer><integer name="a2dp_source_codec_priority_aac">2001</integer><integer name="a2dp_source_codec_priority_aptx">3001</integer><integer name="a2dp_source_codec_priority_aptx_hd">4001</integer><integer name="a2dp_source_codec_priority_ldac">5001</integer>

priority本身没有什么意义,它们的相对值决定应该选择使用哪种编码。在以上所有五种编码都已经实现了的情况下,Android会选择使用LDAC作为A2DP(source)的codec。这是它自己的偏好,还是说LDAC是更好的编码方式呢?除了priority,assignCodecConfigPriorities还会初始化各个codec的参数。由于实际使用的参数是有source和sink协商决定的,而encode和decode这种需要较高time efficiency的操作都是方法C++实现的native world中的,这里的初始化并没有什么意义。

BT stack的codec初始化

到了native world,BT stack会对所有codec进行初始化。BT stack在对a2dp初始化是就会完成这个动作,调用A2dpCodecConfig::createCodec创建A2dpCodecConfig对象。各个codec会有自己的codec config构造函数:

A2dpCodecConfig* A2dpCodecConfig::createCodec(btav_a2dp_codec_index_t codec_index,btav_a2dp_codec_priority_t codec_priority) {LOG_DEBUG(LOG_TAG, "%s: codec %s", __func__, A2DP_CodecIndexStr(codec_index));A2dpCodecConfig* codec_config = nullptr;switch (codec_index) {case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC:codec_config = new A2dpCodecConfigSbc(codec_priority);break;case BTAV_A2DP_CODEC_INDEX_SINK_SBC:codec_config = new A2dpCodecConfigSbcSink(codec_priority);break;case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:codec_config = new A2dpCodecConfigAac(codec_priority);break;case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX:codec_config = new A2dpCodecConfigAptx(codec_priority);break;case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD:codec_config = new A2dpCodecConfigAptxHd(codec_priority);break;case BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC:codec_config = new A2dpCodecConfigLdac(codec_priority);break;// Add a switch statement for each vendor-specific codeccase BTAV_A2DP_CODEC_INDEX_MAX:break;}if (codec_config != nullptr) {if (!codec_config->init()) {delete codec_config;codec_config = nullptr;}}return codec_config;
}

首先可以注意到的是,对于sink而言,Oreo仍然只支持SBC编码;所有新增的codec都用于source。其次,每个codec有自己的codec_config构造,但即使创建成功,init失败了也会无法使用此codec。这里简单提一下BT stack对各个编码的支持。对于SBC和AAC,BT stack使用静态连接,因此无需再去单独加载它们的库文件。对于剩下的APTX、APTX_HD和LDAC,它们分别需要加载“libaptX_encoder.so”、“libaptXHD_encoder.so”和“libldacBT_enc.so”。对于前两者,它们目前属于qcom,因此你只能在使用qcom BT的平台上支持它们。而Oreo的代码中似乎有libladcBT_enc.so这个文件,因此理论上它也是可以默认支持的。

选择合适的codec

使用蓝牙音箱来播放音乐时,该如何选择“最适合”的音频编码呢?首先,选择的codec一定要是source和sink双方都支持的。这里的支持不仅仅是说,双方都支持某一个编码方式,它们对这个特定编码方式的支持能力也要是匹配的。举一反例来说,如果source支持仅支持bitpool为2~35的SBC编码,而sink支持40~53,这样SBC也是无法使用的。其次,BT stack要考虑priorities,在所有available的codec中选择priority最高的。具体的实现是在函数bta_av_co_audio_set_codec中:

//
// Select the current codec configuration based on peer codec support.
// Furthermore, the local state for the remaining non-selected codecs is
// updated to reflect whether the codec is selectable.
// Return a pointer to the corresponding |tBTA_AV_CO_SINK| sink entry
// on success, otherwise NULL.
//
static tBTA_AV_CO_SINK* bta_av_co_audio_set_codec(tBTA_AV_CO_PEER* p_peer) {tBTA_AV_CO_SINK* p_sink = NULL;// Update all selectable codecs.// This is needed to update the selectable parameters for each codec.// NOTE: The selectable codec info is used only for informational purpose.for (const auto& iter : bta_av_co_cb.codecs->orderedSourceCodecs()) {APPL_TRACE_DEBUG("%s: updating selectable codec %s", __func__,iter->name().c_str());bta_av_co_audio_update_selectable_codec(*iter, p_peer);}// Select the codecfor (const auto& iter : bta_av_co_cb.codecs->orderedSourceCodecs()) {APPL_TRACE_DEBUG("%s: trying codec %s", __func__, iter->name().c_str());p_sink = bta_av_co_audio_codec_selected(*iter, p_peer);if (p_sink != NULL) {APPL_TRACE_DEBUG("%s: selected codec %s", __func__, iter->name().c_str());break;}APPL_TRACE_DEBUG("%s: cannot use codec %s", __func__, iter->name().c_str());}// NOTE: Unconditionally dispatch the event to make sure a callback with// the most recent codec info is generated.btif_dispatch_sm_event(BTIF_AV_SOURCE_CONFIG_UPDATED_EVT, NULL, 0);return p_sink;
}

首先,基于双方的能力,在bta_av_co_audio_update_selectable_codec中更新每个codec的参数。bta_av_co_audio_codec_selected会决定最终的codec。显然,这里是按照priority由高至低一个一个去check是否支持。

More

如何添加vendor specific编码呢?Java和C++代码都需要修改,而stack中的代码似乎不少,需要按照模板去实现codec的相应方法。

Source的codec已经支持的不错了,不晓得今后会不会提高对sink的支持。

Oreo对A2DP codec的支持相关推荐

  1. CentOS + Asterisk + FreePBX ——支持蓝牙,AMR-NB audio codec

    CentOS + Asterisk + FreePBX --支持蓝牙,AMR-NB audio codec 配置前的软件包列表以及下载(或者到我个人的百度云网盘下载也可) 网盘地址:http://pa ...

  2. 【经典蓝牙】蓝牙 A2DP协议分析

    A2DP 介绍 A2DP(Advanced Audio Distribution Profile)是蓝牙高音质音频传输协议, 用于传输单声道, 双声道音乐(一般在 A2DP 中用于 stereo 双声 ...

  3. Android Bluetooth A2DP

    本篇blog继续以结合日志的形式来分析A2DP,以手机连接上耳机后,播放音乐为例,来分析A2DP的过程, 后续还有blog,通过耳机控制音乐播放的暂停.播放来分析AVRCP的过程,可以阅读https: ...

  4. A2DP Hardware Offload

    关于A2DP硬件卸载功能,描述可以看https://source.android.com/docs/core/connect/bluetooth/hci_requirements#a2dp-hardw ...

  5. 蓝牙音频双剑客(二)--高质量音频分布协议(A2DP) SBC编解码算法

    零. 概述 主要介绍下蓝牙协议栈(bluetooth stack)传统蓝牙音频协议之高质量音频分布协议(A2DP) SBC编解码算法 Codec Specific Infomation Element ...

  6. PyTorch Mobile已支持Android!

    点上方蓝字计算机视觉联盟获取更多干货 在右上方 ··· 设为星标 ★,与你不见不散 仅作学术分享,不代表本公众号立场,侵权联系删除 转载于:作者:David Reiss 编译:ronghuaiyang ...

  7. Python silk 库 支持微信语音

    GitHub 项目地址 python silk codec binding 支持微信语音编解码 pilk python silk codec binding 支持微信语音编解码 pilk: pytho ...

  8. SRS开始支持SRT

    为什么我要开始着手SRT 为什么我觉得SRT有趣?我们知道RTMP是公共互联网上直播视频的事实标准:但RTMP已经存在了很长一段时间,其标准在2012年最后一次更新过后就被放弃了.新的Codec标准诸 ...

  9. HDA codec相关(2) - verbtable相关

    Verb结构 function group和widgets都通过verbs来访问parameters和controls.Parameters为function group或widget的能力或配置选项 ...

最新文章

  1. java web与android互通的aes算法
  2. (44)FPGA面试技能提升篇(VCS仿真工具)
  3. Python内置函数sorted()和列表方法sort()的排序原理
  4. css样式(二)(伪类 | 伪元素 | 导航 | 图像拼合 | 属性选择器 )
  5. 2010年一月份兑换公告
  6. ArcGIS操作小技巧(一)之属性表中显示出小数点前面的 0
  7. VS2010 VB.net安装包生成过程
  8. 二分排序(java)
  9. Centos7使用docke搭建openV
  10. etal斜体吗 参考文献_论文参考文献格式要求
  11. windows10安装虚拟机virtualbox详细步骤
  12. 作为过来人的我是如何学技术的?
  13. 信息学奥赛一本通 1362:家庭问题(family)
  14. 小姜的perl学习笔记
  15. JS 中 TDZ 的理解
  16. 如何使用FonePaw Video Converter Ultimate将 2D 电影转换为 3D
  17. 在无处落脚的大海,你就是我的岛屿
  18. 用网站怎么赚钱?具体点!聊聊用网站赚钱的方法
  19. 优惠券系统:优惠券分发微服务功能编码实现
  20. 全加器高进位和低进位的理解

热门文章

  1. 垃圾分类里有哪些淘金机会?​
  2. Java基础--继承案例(二)
  3. 怎么在线给图片转换格式?分享一款图片转格式神器
  4. Git概念:什么是分支
  5. dsp正弦波信号发生器c语言编程实例,毕业设计基于DSP的正弦波信号发生器的设计与实现整理版V3.1...
  6. 生物电镜常见问题及解答
  7. R语言主成分分析PCA谱分解、奇异值分解预测分析运动员表现数据和降维可视化
  8. 3小时快速入门html5+css(2022)
  9. serverless入门介绍
  10. mysql columns表_mysql8 参考手册-INFORMATION_SCHEMA COLUMNS表