当前位置: 首页 > java >正文

【Bluedroid】btif_av_sink_execute_service之服务器启用源码流程解析

本文围绕 Bluedroid 蓝牙协议栈中 A2DP Sink(音频接收端)服务的启用流程展开,深入解析从 BTIF 层触发到 BTA 层初始化、协议栈集成、SDP 服务发现记录创建及 AVRCP 控制连接建立的全链路流程。重点分析功能特性配置、事件驱动机制、资源管理(如流控制块 SCB)及多模块协作逻辑,揭示蓝牙音频接收端服务生命周期管理的核心实现。

一、概述

A2DP(Advanced Audio Distribution Profile)是蓝牙音频传输的核心协议,负责将音频流从源设备(如手机)传输到接收端设备(如耳机)。A2DP Sink 服务的启用是设备作为音频接收端的基础,涉及 BTIF(蓝牙接口层)、BTA(蓝牙应用层)、AVDT(音频 / 视频分发传输协议)、AVCT(音频 / 视频控制传输协议)及 SDP(服务发现协议)等多模块协作。

流程核心可分为以下阶段:

  1. BTIF 层触发与配置:通过btif_av_sink_execute_service函数,根据系统属性(如延迟报告、源 / 接收端共存)配置 BTA AV 功能特性,并调用BTA_AvEnable触发 BTA 层服务初始化。

  2. BTA 层服务初始化:BTA 层通过消息机制(bta_sys_sendmsg)将启用请求传递至主线程,经事件分发(bta_sys_eventbta_av_hdl_event)调用bta_av_api_enable完成控制块初始化、状态校验及回调通知。

  3. 流控制与协议集成:通过bta_av_api_register分配流控制块(SCB),注册 AVDT/AVCT 协议栈,创建 SDP 记录并填充 A2DP 服务属性(如服务类 UUID、支持特性),确保远程设备可发现并连接本地服务。

  4. AVRCP 控制连接建立:调用bta_av_rc_create创建 AVRCP(音频 / 视频远程控制协议)连接,管理音频流的远程控制(如播放、暂停)。

二、源码解析

btif_av_sink_execute_service

packages/modules/Bluetooth/system/btif/src/btif_av.cc
bt_status_t btif_av_sink_execute_service(bool enable) {log::verbose("Sink service: {}", (enable) ? "enable" : "disable");if (enable) {// Added BTA_AV_FEAT_NO_SCO_SSPD - this ensures that the BTA does not// auto-suspend AV streaming on AG events (SCO or Call). The suspend shall// be initiated by the app/audioflinger layers.// 1. 配置BTA AV功能特性tBTA_AV_FEAT features = BTA_AV_FEAT_NO_SCO_SSPD | BTA_AV_FEAT_RCCT |BTA_AV_FEAT_METADATA | BTA_AV_FEAT_VENDOR |BTA_AV_FEAT_ADV_CTRL | BTA_AV_FEAT_RCTG |BTA_AV_FEAT_BROWSE | BTA_AV_FEAT_COVER_ARTWORK;// 2. 根据系统属性决定是否启用延迟报告if (delay_reporting_enabled()) {features |= BTA_AV_FEAT_DELAY_RPT;}// 3. 根据源/接收端共存属性选择回调函数if (btif_av_src_sink_coexist_enabled())BTA_AvEnable(features, bta_av_event_callback);elseBTA_AvEnable(features, bta_av_sink_callback);// 4. 启用BTA AV服务并注册句柄btif_av_sink.RegisterAllBtaHandles(); return BT_STATUS_SUCCESS;}// Disable the service// 1. 注销所有BTA句柄btif_av_sink.DeregisterAllBtaHandles(); // 2. 禁用BTA AV服务BTA_AvDisable();return BT_STATUS_SUCCESS;
}typedef uint16_t tBTA_AV_FEAT;/* Internal features */
#define BTA_AV_FEAT_NO_SCO_SSPD \0x8000 /* Do not suspend av streaming as to AG events(SCO or Call) */
#define BTA_AV_FEAT_RCCT 0x0002    /* remote control controller */
#define BTA_AV_FEAT_METADATA \0x0040 /* remote control Metadata Transfer command/response */
#define BTA_AV_FEAT_VENDOR                                                    \0x0008                          /* remote control vendor dependent commands \*/
#define BTA_AV_FEAT_ADV_CTRL \0x0200 /* remote control Advanced Control command/response */
#define BTA_AV_FEAT_RCTG 0x0001    /* remote control target */
#define BTA_AV_FEAT_BROWSE 0x0010 /* use browsing channel */
#define BTA_AV_FEAT_COVER_ARTWORK 0x1000 /* use cover art feature */
#define BTA_AV_FEAT_DELAY_RPT 0x0400 /* allow delay reporting */bool delay_reporting_enabled() {return !osi_property_get_bool("persist.bluetooth.disabledelayreports", false);
}bool btif_av_src_sink_coexist_enabled(void) {return GET_SYSPROP(A2dp, src_sink_coexist, false);
}packages/modules/Bluetooth/sysprop/a2dp.sysprop
// 应用层或系统配置可通过修改bluetooth.a2dp.src_sink_coexist.enabled属性(true/false)
// 动态控制是否允许设备同时作为 A2DP 发送端和接收端
prop {api_name: "src_sink_coexist"type: Booleanscope: Internalaccess: Readonlyprop_name: "bluetooth.a2dp.src_sink_coexist.enabled"
}

执行 A2DP Sink服务的启用或禁用。通过组合蓝牙协议栈的功能特性(如禁止自动暂停、元数据传输),并结合系统属性(延迟报告、源 / 接收端共存)动态配置 A2DP Sink 服务的行为,最终通过BTA_AvEnable/BTA_AvDisable接口与蓝牙协议栈交互,实现服务的生命周期管理(启用 / 禁用)。确保设备能正确处理音频流传输和远程控制指令。

typedef uint16_t tBTA_AV_FEAT定义了蓝牙 AV 模块的功能特性掩码,通过位运算组合不同功能。以下是关键特性的作用:

宏定义二进制位(十六进制)功能说明
BTA_AV_FEAT_NO_SCO_SSPD0x8000禁止因 AG(音频网关)事件(如 SCO 连接或通话)自动暂停音频流(由上层控制暂停)
BTA_AV_FEAT_RCCT0x0002支持远程控制(Remote Control)的 “控制器” 角色(发送控制指令)
BTA_AV_FEAT_METADATA0x0040支持元数据(如歌曲名、艺术家)的传输
BTA_AV_FEAT_VENDOR0x0008支持厂商自定义的远程控制命令
BTA_AV_FEAT_ADV_CTRL0x0200支持高级控制命令(如播放速率调整)
BTA_AV_FEAT_RCTG0x0001支持远程控制的 “目标” 角色(接收控制指令)
BTA_AV_FEAT_BROWSE0x0010支持浏览通道(如访问设备媒体库)
BTA_AV_FEAT_COVER_ARTWORK0x1000支持封面艺术(专辑封面)传输
BTA_AV_FEAT_DELAY_RPT0x0400支持延迟报告(如音频传输延迟反馈)

本文主要分析启动服务流程图,服务禁用流程分析见后面的文章

BTA_AvEnable

packages/modules/Bluetooth/system/bta/av/bta_av_api.cc
static const tBTA_SYS_REG bta_av_reg = {bta_av_hdl_event, BTA_AvDisable};/********************************************************************************* Function         BTA_AvEnable** Description      Enable the advanced audio/video service. When the enable*                  operation is complete the callback function will be*                  called with a BTA_AV_ENABLE_EVT. This function must*                  be called before other function in the AV API are*                  called.** Returns          void*******************************************************************************/
void BTA_AvEnable(tBTA_AV_FEAT features, tBTA_AV_CBACK* p_cback) {tBTA_AV_API_ENABLE* p_buf =(tBTA_AV_API_ENABLE*)osi_malloc(sizeof(tBTA_AV_API_ENABLE));/* register with BTA system manager */bta_sys_register(BTA_ID_AV, &bta_av_reg);p_buf->hdr.event = BTA_AV_API_ENABLE_EVT;p_buf->p_cback = p_cback;p_buf->features = features;bta_sys_sendmsg(p_buf);
}
  • 启用高级音频 / 视频服务(如 A2DP、AVRCP 等配置文件)。

  • 启用完成后,通过传入的回调函数 p_cback 通知上层 BTA_AV_ENABLE_EVT 事件(表示启用操作完成)。

  • 是其他 AV 接口(如 BTA_AvConnectBTA_AvStart)的前置调用条件(必须先启用服务)。

bta_sys_register(&bta_av_reg)

packages/modules/Bluetooth/system/bta/sys/bta_sys_main.cc
/* system manager control block definition */
tBTA_SYS_CB bta_sys_cb;/********************************************************************************* Function         bta_sys_register** Description      Called by other BTA subsystems to register their event*                  handler.*** Returns          void*******************************************************************************/
void bta_sys_register(uint8_t id, const tBTA_SYS_REG* p_reg) {// 将子系统的注册信息(如事件处理函数、资源释放函数等)保存到系统管理器的控制块中,便于后续调度bta_sys_cb.reg[id] = (tBTA_SYS_REG*)p_reg;// 标记子系统已注册bta_sys_cb.is_reg[id] = true;
}
  • 供其他 BTA 子系统(如 AV、AG、HF 等模块)调用,向 BTA 系统管理器注册自身的事件处理逻辑。

  • 是 BTA 子系统与系统管理器建立联系的 “注册入口”,确保系统管理器能统一调度各子系统的事件。

bta_sys_sendmsg(BTA_AV_API_ENABLE_EVT)
/packages/modules/Bluetooth/system/bta/sys/bta_sys_main.xcc
/********************************************************************************* Function         bta_sys_sendmsg** Description      Send a GKI message to BTA.  This function is designed to*                  optimize sending of messages to BTA.  It is called by BTA*                  API functions and call-in functions.**                  TODO (apanicke): Add location object as parameter for easier*                  future debugging when doing alarm refactor*** Returns          void*******************************************************************************/
void bta_sys_sendmsg(void* p_msg) {if (do_in_main_thread(FROM_HERE,base::BindOnce(&bta_sys_event, static_cast<BT_HDR_RIGID*>(p_msg))) !=BT_STATUS_SUCCESS) {log::error("do_in_main_thread failed");}
}

BTA 系统的 “消息总线”,其核心价值在于:

  • 线程安全:通过主线程串行处理消息,避免多线程并发问题。

  • 模块化协作:为所有 BTA 子系统提供统一的消息发送接口,实现模块间的松耦合通信。

  • 向 BTA 系统发送 GKI(Generic Kernel Interface,通用内核接口)消息,优化消息传递流程。

  • 供 BTA 的 API 函数(如 BTA_AvEnable)和回调函数(如设备连接回调)调用,是模块间通信的核心通道。

这是Bluedroid蓝牙协议中事件驱动模型的一部分,用于在不同组件和子系统之间传递信息和执行回调。

bta_sys_event
packages/modules/Bluetooth/system/bta/sys/bta_sys_main.cc
/********************************************************************************* Function         bta_sys_event** Description      BTA event handler; called from task event handler.*** Returns          void*******************************************************************************/
static void bta_sys_event(BT_HDR_RIGID* p_msg) {bool freebuf = true;log::verbose("Event 0x{:x}", p_msg->event);/* get subsystem id from event */uint8_t id = (uint8_t)(p_msg->event >> 8); // 获取子系统ID,事件类型的高8位表示子系统ID/* verify id and call subsystem event handler */if ((id < BTA_ID_MAX) && (bta_sys_cb.reg[id] != NULL)) {freebuf = (*bta_sys_cb.reg[id]->evt_hdlr)(p_msg);} else {log::info("Ignoring receipt of unregistered event id:{}[{}]",BtaIdSysText(static_cast<tBTA_SYS_ID>(id)), id);}if (freebuf) {osi_free(p_msg);}
}

BTA系统管理器的核心事件分发函数,主要负责将接收到的消息路由到对应的 BTA 子系统(如 AV、AG、HF 模块)处理,是 BTA 系统 “事件驱动” 架构的核心枢纽。

bta_sys_event 的作用是:

  • 事件分发:根据消息中的子系统 ID,将事件分发给已注册的子系统事件处理函数。

  • 内存管理:根据子系统处理结果,决定是否释放消息缓冲区内存。

  • 是 BTA 系统消息处理流程的 “总调度中心”,所有通过 bta_sys_sendmsg 发送的消息最终都由它处理。

这是Bluedriod蓝牙协议栈中事件驱动模型的关键组件,确保了事件能够正确地被处理并传递给相应的子系统。

以 AV 子系统的 “启用服务” 消息(BTA_AV_API_ENABLE_EVT)为例:

  1. 消息发送BTA_AvEnable 函数调用 bta_sys_sendmsg,将封装好的消息(事件类型为 0x0201,其中 0x02 是 AV 子系统 ID,0x01 是启用事件)发送到主线程。

  2. 事件分发bta_sys_event 提取子系统 ID 0x02,检查 bta_sys_cb.reg[0x02] 非空(AV 子系统已注册),调用 AV 的事件处理函数 bta_av_hdl_event

  3. 子系统处理:bta_av_hdl_event 处理 0x0201 事件(启用 AV 服务),完成后返回 true(表示消息处理完毕)。

  4. 内存释放bta_sys_event 执行 osi_free(p_msg),释放消息缓冲区。

bta_av_hdl_event
packages/modules/Bluetooth/system/bta/av/bta_av_main.cc
/********************************************************************************* Function         bta_av_hdl_event** Description      Advanced audio/video main event handling function.*** Returns          bool*******************************************************************************/
bool bta_av_hdl_event(const BT_HDR_RIGID* p_msg) {if (p_msg->event > BTA_AV_LAST_EVT) { // 无效事件过滤return true; /* to free p_msg */}if (p_msg->event >= BTA_AV_FIRST_NSM_EVT) { // 非状态机事件log::verbose("AV nsm event=0x{:x}({})", p_msg->event,bta_av_evt_code(p_msg->event));bta_av_non_state_machine_event(p_msg->event, (tBTA_AV_DATA*)p_msg);} else if (p_msg->event >= BTA_AV_FIRST_SM_EVT &&p_msg->event <= BTA_AV_LAST_SM_EVT) { // 状态机事件log::verbose("AV sm event=0x{:x}({})", p_msg->event,bta_av_evt_code(p_msg->event));/* state machine events */bta_av_sm_execute(&bta_av_cb, p_msg->event, (tBTA_AV_DATA*)p_msg);} else { // 流状态机事件log::verbose("bta_handle=0x{:x}", p_msg->layer_specific);/* stream state machine events */bta_av_ssm_execute(bta_av_hndl_to_scb(p_msg->layer_specific), p_msg->event,(tBTA_AV_DATA*)p_msg);}return true;
}

负责根据事件类型路由到不同的处理逻辑(状态机事件、非状态机事件、流状态机事件),是 AV 子系统 “事件驱动” 架构的核心枢纽。主要作用是

  • 事件分类处理:根据事件类型(状态机事件、非状态机事件、流状态机事件)调用对应的处理函数。

  • 消息生命周期管理:返回 true 表示消息已处理完毕,触发 bta_sys_event 释放消息缓冲区(避免内存泄漏)。

  • 是 AV 子系统与 BTA 系统管理器交互的 “事件入口”,所有发送到 AV 子系统的事件最终由它处理。

BTA_AV_API_ENABLE_EVT事件属于非状态机事件范围(即大于等于BTA_AV_FIRST_NSM_EVT),则调用bta_av_non_state_machine_event函数来处理该事件。

bta_av_non_state_machine_event
packages/modules/Bluetooth/system/bta/av/bta_av_main.cc
static void bta_av_non_state_machine_event(uint16_t event,tBTA_AV_DATA* p_data) {switch (event) {case BTA_AV_API_ENABLE_EVT:bta_av_api_enable(p_data);break;...      }

对于BTA_AV_API_ENABLE_EVT 事件,直接调用 bta_av_api_enable 函数。

bta_av_api_enable
packages/modules/Bluetooth/system/bta/av/bta_av_main.cc
constexpr uint8_t kEnablingAttemptsCountMaximum = 5;/********************************************************************************* Function         bta_av_api_enable** Description      Handle an API enable event.*** Returns          void*******************************************************************************/
static void bta_av_api_enable(tBTA_AV_DATA* p_data) {// 1. 处理共存场景:交换源/接收端特性并通知回调if (btif_av_src_sink_coexist_enabled() && bta_av_cb.features != 0) { // 非首次启用tBTA_AV_ENABLE enable;tBTA_AV bta_av_data;// 保存接收端特性bta_av_cb.sink_features = p_data->api_enable.features;enable.features = p_data->api_enable.features;bta_av_data.enable = enable;// 通知启用完成(*bta_av_cb.p_cback)(BTA_AV_ENABLE_EVT, &bta_av_data);// 交换源 / 接收端特性(避免冲突)/* if this is source feature, then exchange them */if (p_data->api_enable.features & BTA_AV_FEAT_SRC) {tBTA_AV_FEAT tmp_feature = bta_av_cb.features;bta_av_cb.features = bta_av_cb.sink_features;bta_av_cb.sink_features = tmp_feature;}return;}// 2. A/V模块正在禁用中if (bta_av_cb.disabling) { log::warn("previous (reg_audio={:#x}) is still disabling (attempts={})",bta_av_cb.reg_audio, bta_av_cb.enabling_attempts);if (++bta_av_cb.enabling_attempts <= kEnablingAttemptsCountMaximum) {// 重新封装启用请求消息tBTA_AV_API_ENABLE* p_buf =(tBTA_AV_API_ENABLE*)osi_malloc(sizeof(tBTA_AV_API_ENABLE));memcpy(p_buf, &p_data->api_enable, sizeof(tBTA_AV_API_ENABLE));bta_sys_sendmsg_delayed(p_buf, std::chrono::milliseconds(kEnablingAttemptsIntervalMs)); // 重新发送启用请求return;}// 若超过最大重试次数,清理资源(删除 SDP 记录、注销 AVDT/AVCT 模块),确保模块状态一致if (bta_av_cb.sdp_a2dp_handle) {get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord(bta_av_cb.sdp_a2dp_handle);bta_sys_remove_uuid(UUID_SERVCLASS_AUDIO_SOURCE);}if (bta_av_cb.sdp_a2dp_snk_handle) {get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord(bta_av_cb.sdp_a2dp_snk_handle);bta_sys_remove_uuid(UUID_SERVCLASS_AUDIO_SINK);}// deregister from AVDTbta_ar_dereg_avdt();// deregister from AVCTbta_ar_dereg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL);bta_ar_dereg_avrc(UUID_SERVCLASS_AV_REM_CTRL_TARGET);bta_ar_dereg_avct();}// 3. 初始化 AV 控制块/* initialize control block */memset(&bta_av_cb, 0, sizeof(tBTA_AV_CB)); //重置A/V控制块(bta_av_cb)为初始状态for (int i = 0; i < BTA_AV_NUM_RCB; i++)bta_av_cb.rcb[i].handle = BTA_AV_RC_HANDLE_NONE; //初始化所有远程控制块(RCB)的句柄为无效句柄bta_av_cb.rc_acp_handle = BTA_AV_RC_HANDLE_NONE;// 4. 存储配置参数/* store parameters */bta_av_cb.p_cback = p_data->api_enable.p_cback; // 保存上层传入的回调函数bta_av_cb.features = p_data->api_enable.features; // 保存启用的功能特性(如元数据、远程控制等)bta_av_cb.offload_start_pending_hndl = BTA_AV_INVALID_HANDLE;bta_av_cb.offload_started_hndl = BTA_AV_INVALID_HANDLE;tBTA_AV_ENABLE enable;enable.features = bta_av_cb.features;// 5. 注册 SCO 变更回调/* Register for SCO change event */bta_sys_sco_register(bta_av_sco_chg_cback); // 注册SCO变更回调函数,以便在SCO连接状态变化时接收通知// 6. 通知上层启用完成/* call callback with enable event */tBTA_AV bta_av_data;bta_av_data.enable = enable;(*bta_av_cb.p_cback)(BTA_AV_ENABLE_EVT, &bta_av_data); //使用存储的回调指针和启用事件调用回调
}

完成 AV 服务的初始化、状态管理及资源配置,是 AV 服务从 “启用请求” 到 “启用完成” 的关键执行逻辑。AV 服务启用流程的 “最后一公里” 函数,其核心作用是:

  • 处理启用请求:当上层调用 BTA_AvEnable 接口启用 AV 服务时,系统管理器通过消息机制将请求传递至此函数。

  • 状态校验:处理源 / 接收端共存、模块禁用中的重试等边界场景。

  • 资源初始化:重置控制块、配置功能特性,确保模块从干净状态启动。

  • 依赖注册:注册 SCO 变更回调,确保与语音通话等功能的协作。

  • 完成通知:通过回调向上层反馈启用结果,驱动后续业务逻辑。

bta_av_sink_callback
packages/modules/Bluetooth/system/btif/src/btif_av.cc
static void bta_av_sink_callback(tBTA_AV_EVT event, tBTA_AV* p_data) {// 封装了从蓝牙A/V模块接收到的事件和数据BtifAvEvent btif_av_event(event, p_data, sizeof(tBTA_AV)); do_in_main_thread(FROM_HERE, base::BindOnce(&btif_av_handle_bta_av_event,AVDT_TSEP_SRC /* peer_sep */, btif_av_event));
}

A2DP Sink的回调函数。将 BTA 层的 AV(高级音频 / 视频)事件传递到 BTIF 层处理,是蓝牙协议栈从底层到上层的 “事件桥梁”。核心作用是:

  • 接收 BTA 层的 AV 事件:当 BTA 层(如 AV 模块)发生状态变化(如音频流连接、断开)时,通过此回调通知 BTIF 层。

  • 事件跨层传递:将 BTA 层的原始事件(tBTA_AV_EVT)和数据(tBTA_AV*)封装为 BTIF 层可处理的事件对象,并提交到主线程处理。

  • 是 BTIF 层与 BTA 层解耦的关键接口(BTA 层不直接调用上层逻辑,而是通过回调传递事件)。

AVDT_TSEP_SRC:表示对等 SEP(Stream Endpoint,流终结点)的类型为 “源端”(Source),用于标识音频流的方向(如手机作为源端向耳机发送音频)。

btif_av_handle_bta_av_event(BTA_AV_ENABLE_EVT)
packages/modules/Bluetooth/system/btif/src/btif_av.cc
/*** Process BTA AV or BTA AVRCP events. The processing is done on the JNI* thread.** @param peer_sep the corresponding peer's SEP: AVDT_TSEP_SRC if the peer* is A2DP Source, or AVDT_TSEP_SNK if the peer is A2DP Sink.* @param btif_av_event the corresponding event*/
static void btif_av_handle_bta_av_event(uint8_t peer_sep,const BtifAvEvent& btif_av_event) {RawAddress peer_address = RawAddress::kEmpty;tBTA_AV_HNDL bta_handle = kBtaHandleUnknown;tBTA_AV_EVT event = btif_av_event.Event();tBTA_AV* p_data = (tBTA_AV*)btif_av_event.Data();std::string msg;log::debug("jni_thread: Handle BTA AV or AVRCP event {}: peer_sep={} event={}",peer_stream_endpoint_text(peer_sep), peer_sep, btif_av_event.ToString());switch (event) {case BTA_AV_ENABLE_EVT: {const tBTA_AV_ENABLE& enable = p_data->enable;log::debug("Enable features=0x{:x}", enable.features);return;  // Nothing to do}...if (!msg.empty()) {BTM_LogHistory(kBtmLogHistoryTag, peer_address, msg,btif_av_event.ToString());}btif_av_handle_event(peer_sep, peer_address, bta_handle, btif_av_event);
}

BTA_AV_ENABLE_EVT事件中,记录了启用的功能,但并未执行其他操作。

注册:btif_av_sink.RegisterAllBtaHandles

packages/modules/Bluetooth/system/btif/src/btif_av.cc
void BtifAvSink::RegisterAllBtaHandles() {//遍历对等设备 ID 范围for (int peer_id = kPeerIdMin; peer_id < kPeerIdMax; peer_id++) {// 为每个peer_id注册服务BTA_AvRegister(BTA_AV_CHNL_AUDIO,                // 通道类型:音频通道kBtifAvSinkServiceName.c_str(),   // 服务名称(用于SDP记录)peer_id,                         // 对等设备IDbta_av_sink_media_callback,       // 媒体事件回调函数UUID_SERVCLASS_AUDIO_SINK         // 服务类UUID(标识音频接收端));}
}

向 BTA注册音频接收端(Sink)的媒体通道句柄,确保 BTA 层能正确识别并处理来自多个蓝牙设备的音频流事件。

其核心作用是:

  • 多设备支持:通过遍历设备 ID 范围,为每个设备注册独立的服务句柄。

  • 服务发现:通过标准 UUID 和服务名称,确保远程设备能正确发现音频接收端服务。

  • 事件路由:绑定设备 ID 与回调函数,实现不同设备事件的隔离处理。

  • 是 AV 接收端服务初始化流程的关键步骤(在btif_av_sink_execute_service启用服务时调用)。

是蓝牙协议栈 “多设备并发能力” 的关键实现,确保了音频接收端在复杂连接场景下的稳定性和可靠性。

实际应用场景

当手机作为蓝牙音频接收端(Sink)时,需要支持连接多个音频源设备(如笔记本电脑、平板):

  1. 服务注册RegisterAllBtaHandles 为每个peer_id(如 0、1、2)调用BTA_AvRegister,在协议栈中注册 8 个(假设kPeerIdMax=8)音频接收端服务实例。

  2. 设备连接:当设备 1(peer_id=0)发起音频连接时,BTA 层根据peer_id=0的注册信息,调用对应的bta_av_sink_media_callback处理连接事件。

  3. 事件处理:设备 1 的播放事件(如开始传输音频流)通过peer_id=0的回调通知 BTIF 层,BTIF 层根据peer_id定位到设备 1 的上下文,执行相应操作(如播放音频)。

BTA_AvRegister
packages/modules/Bluetooth/system/bta/av/bta_av_api.cc
/********************************************************************************* Function         BTA_AvRegister** Description      Register the audio or video service to stack. When the*                  operation is complete the callback function will be*                  called with a BTA_AV_REGISTER_EVT. This function must*                  be called before AVDT stream is open.*** Returns          void*******************************************************************************/
void BTA_AvRegister(tBTA_AV_CHNL chnl, const char* p_service_name,uint8_t app_id, tBTA_AV_SINK_DATA_CBACK* p_sink_data_cback,uint16_t service_uuid) {tBTA_AV_API_REG* p_buf =(tBTA_AV_API_REG*)osi_malloc(sizeof(tBTA_AV_API_REG));p_buf->hdr.layer_specific = chnl;p_buf->hdr.event = BTA_AV_API_REGISTER_EVT;if (p_service_name)strlcpy(p_buf->p_service_name, p_service_name, BTA_SERVICE_NAME_LEN);elsep_buf->p_service_name[0] = 0;p_buf->app_id = app_id;p_buf->p_app_sink_data_cback = p_sink_data_cback;p_buf->service_uuid = service_uuid;bta_sys_sendmsg(p_buf); //  发送消息到 BTA 系统
}

向上层应用提供注册音频 / 视频服务的接口,是 AV 服务从 “应用请求注册” 到 “协议栈处理注册” 的关键入口函数。其核心作用是:

  • 接口抽象:向上层应用提供简单的注册接口,隐藏底层复杂逻辑。

  • 消息封装:将注册请求参数封装为 BTA 层可识别的消息,确保跨线程传递的可靠性。

  • 流程启动:触发 BTA 层的注册流程(bta_av_api_register),最终实现服务的协议栈注册、SDP 记录创建及资源分配。

体现了蓝牙协议栈 “接口简洁性” 和 “底层复杂性封装” 的设计思想,是上层应用与 BTA 层高效协作的关键纽带。

函数参数解析:

参数类型说明
chnltBTA_AV_CHNL音频 / 视频通道类型(如 BTA_AV_CHNL_AUDIO 表示音频通道)
p_service_nameconst char*服务名称(用于 SDP 记录,远程设备可通过此名称发现服务)
app_iduint8_t应用 ID(标识发起注册的上层应用,用于隔离多应用的服务)
p_sink_data_cbacktBTA_AV_SINK_DATA_CBACK*接收端数据回调函数(当音频接收端收到媒体数据时,BTA 层通过此函数通知应用)
service_uuiduint16_t服务类 UUID(如 UUID_SERVCLASS_AUDIO_SOURCE 表示音频源服务)

在注册操作完成后,对应的回调函数会以 BTA_AV_REGISTER_EVT 事件被调用,此函数必须在 AVDT(蓝牙音频 / 视频传输相关协议)流打开之前调用,以确保服务注册及后续相关流程能按正确顺序执行,整体实现了收集服务注册相关信息、封装成消息结构体后发送给系统,从而触发服务注册流程的功能。

bta_sys_sendmsg(BTA_AV_API_REGISTER_EVT)

BTA 系统的消息发送函数(前文分析过),将消息提交到 BTA 主线程处理。 BTA 主线程收到消息后,通过 bta_sys_event 分发到 AV 子系统的事件处理函数 bta_av_hdl_event,最终调用 bta_av_api_register 执行具体的注册逻辑(如分配流控制块 SCB、创建 SDP 记录、注册协议栈)。

bta_av_api_register
/packages/modules/Bluetooth/system/bta/av/bta_av_main.cc
// total attempts are half seconds
constexpr uint32_t kEnablingAttemptsIntervalMs = 100;/********************************************************************************* Function         bta_av_api_register** Description      allocate stream control block,*                  register the service to stack*                  create SDP record** Returns          void*******************************************************************************/
static void bta_av_api_register(tBTA_AV_DATA* p_data) {tBTA_AV_REGISTER reg_data;tBTA_AV_SCB* p_scb; /* stream control block */AvdtpRcb reg;AvdtpStreamConfig avdtp_stream_config;char* p_service_name;tBTA_UTL_COD cod;uint8_t local_role = 0;// 1. AV 模块处于禁用中或功能未启用if (bta_av_cb.disabling || (bta_av_cb.features == 0)) {log::warn("AV instance (features={:#x}, reg_audio={:#x}) is not ready for app_id ""{}",bta_av_cb.features, bta_av_cb.reg_audio, p_data->api_reg.app_id);// 延迟重新发送注册请求tBTA_AV_API_REG* p_buf =(tBTA_AV_API_REG*)osi_malloc(sizeof(tBTA_AV_API_REG));memcpy(p_buf, &p_data->api_reg, sizeof(tBTA_AV_API_REG));bta_sys_sendmsg_delayed(p_buf, std::chrono::milliseconds(kEnablingAttemptsIntervalMs));return;}avdtp_stream_config.Reset(); // 重置AVDTP流配置// 2. 本地角色确定(源 / 接收端共存场景)if (btif_av_src_sink_coexist_enabled()) {// 根据注册的服务UUID,确定本地设备是作为音频源还是音频接收器local_role = (p_data->api_reg.service_uuid == UUID_SERVCLASS_AUDIO_SINK)? AVDT_TSEP_SNK: AVDT_TSEP_SRC;}//初始化一个 reg_data 结构体,用于存储注册操作的结果和相关信息reg_data.status = BTA_AV_FAIL_RESOURCES;reg_data.app_id = p_data->api_reg.app_id;reg_data.chnl = (tBTA_AV_CHNL)p_data->hdr.layer_specific;//通过读取系统属性,函数获取AVRCP的版本信息char avrcp_version[PROPERTY_VALUE_MAX] = {0};osi_property_get(AVRCP_VERSION_PROPERTY, avrcp_version,AVRCP_DEFAULT_VERSION);log::info("AVRCP version used for sdp: \"{}\"", avrcp_version);//根据服务UUID和AVRCP版本,函数选择合适的配置uint16_t profile_initialized = p_data->api_reg.service_uuid;if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK) {p_bta_av_cfg = get_bta_avk_cfg();} else if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE) {p_bta_av_cfg = &bta_av_cfg;if (!strncmp(AVRCP_1_3_STRING, avrcp_version, sizeof(AVRCP_1_3_STRING))) {log::info("AVRCP 1.3 capabilites used");p_bta_av_cfg = &bta_av_cfg_compatibility;}}log::verbose("profile: 0x{:x}", profile_initialized);if (p_bta_av_cfg == NULL) {log::error("AV configuration is null!");return;}do {p_scb = nullptr;if (btif_av_src_sink_coexist_enabled()) {// 3. 流控制块(SCB)分配与初始化p_scb = bta_av_find_scb(reg_data.chnl, reg_data.app_id);}if (p_scb == nullptr) {p_scb = bta_av_alloc_scb(reg_data.chnl); // 尝试分配一个新的SCB}if (p_scb == NULL) {log::error("failed to alloc SCB");break;}reg_data.hndl = p_scb->hndl;p_scb->app_id = reg_data.app_id;/* initialize the stream control block */reg_data.status = BTA_AV_SUCCESS; // 注册状态被设置为成功,表示到目前为止,注册过程已经顺利if ((btif_av_src_sink_coexist_enabled() &&!(bta_av_cb.reg_role & (1 << local_role))) ||(!btif_av_src_sink_coexist_enabled() && bta_av_cb.reg_audio == 0)) {/* the first channel registered. register to AVDTP *///设置AVDTP注册参数,并调用bta_ar_reg_avdt函数进行注册reg.ctrl_mtu = 672;reg.ret_tout = BTA_AV_RET_TOUT;reg.sig_tout = BTA_AV_SIG_TOUT;reg.idle_tout = BTA_AV_IDLE_TOUT;reg.scb_index = p_scb->hdi;// 4. 协议栈注册(AVDTP/AVCT)bta_ar_reg_avdt(&reg, bta_av_conn_cback);bta_sys_role_chg_register(&bta_av_sys_rs_cback); // 注册了一个系统角色更改回调/* create remote control TG service if required */if (bta_av_cb.features & (BTA_AV_FEAT_RCTG)) { //确定是否支持远程控制目标服务/* register with no authorization; let AVDTP use authorization instead*/bta_ar_reg_avct(); // 注册AVCT服务,但不使用授权,让AVDTP处理授权/* For the Audio Sink role we support additional TG to support* absolute volume.*/if (is_new_avrcp_enabled()) { //检查是否启用了新的AVRCP版本//如果启用了新版本,则不创建SDP记录,因为新版本会管理自己的SDP记录。如果未启用新版本,则继续创建SDP记录log::verbose("newavrcp is the owner of the AVRCP Target SDP record. Don't ""create the SDP record");} else {log::verbose("newavrcp is not enabled. Create SDP record");// 设置AVRCP的版本号uint16_t profile_version = AVRC_REV_1_0; if (!strncmp(AVRCP_1_6_STRING, avrcp_version,sizeof(AVRCP_1_6_STRING))) {profile_version = AVRC_REV_1_6;} else if (!strncmp(AVRCP_1_5_STRING, avrcp_version,sizeof(AVRCP_1_5_STRING))) {profile_version = AVRC_REV_1_5;} else if (!strncmp(AVRCP_1_3_STRING, avrcp_version,sizeof(AVRCP_1_3_STRING))) {profile_version = AVRC_REV_1_3;} else {profile_version = AVRC_REV_1_4;}//根据是否启用了共存,调用不同的函数来注册AVRC服务if (btif_av_src_sink_coexist_enabled()) {bta_ar_reg_avrc_for_src_sink_coexist(UUID_SERVCLASS_AV_REM_CTRL_TARGET, "AV Remote Control Target",NULL, p_bta_av_cfg->avrc_tg_cat,static_cast<tBTA_SYS_ID>(BTA_ID_AV + local_role),(bta_av_cb.features & BTA_AV_FEAT_BROWSE), profile_version);} else {bta_ar_reg_avrc(UUID_SERVCLASS_AV_REM_CTRL_TARGET, "AV Remote Control Target",NULL, p_bta_av_cfg->avrc_tg_cat,(bta_av_cb.features & BTA_AV_FEAT_BROWSE), profile_version);}}}/* Set the Capturing service class bit *///设置设备的COD服务位。然后,调用utl_set_device_class函数应用这些更改if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE)cod.service = BTM_COD_SERVICE_CAPTURING;else if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK)cod.service = BTM_COD_SERVICE_RENDERING;utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS);} /* if 1st channel *//* get stream configuration and create stream */// 6. 流参数配置与编解码器支持avdtp_stream_config.cfg.num_codec = 1; // 支持的编解码器数量avdtp_stream_config.nsc_mask = AvdtpStreamConfig::AVDT_NSC_RECONFIG; // 支持重新配置// 如果未启用保护特性,则添加安全标志到nsc_maskif (!(bta_av_cb.features & BTA_AV_FEAT_PROTECT)) {avdtp_stream_config.nsc_mask |= AvdtpStreamConfig::AVDT_NSC_SECURITY;}log::verbose("nsc_mask: 0x{:x}", avdtp_stream_config.nsc_mask);// 根据注册数据中提供的服务名称设置p_service_nameif (p_data->api_reg.p_service_name[0] == 0) {p_service_name = NULL;} else {p_service_name = p_data->api_reg.p_service_name;}//设置流控制块(SCB)的暂停支持和重新配置支持标志p_scb->suspend_sup = true;p_scb->recfg_sup = true;//设置AVDTP流配置的SCB索引和控制回调,以便在流事件发生时进行处理avdtp_stream_config.scb_index = p_scb->hdi;avdtp_stream_config.p_avdt_ctrl_cback = &bta_av_proc_stream_evt;/* set up the audio stream control block */p_scb->p_cos = &bta_av_a2dp_cos; // 将A2DP的编码配置集(COS)的指针赋给SCBp_scb->media_type = AVDT_MEDIA_TYPE_AUDIO; // 设置媒体类型为音频//配置AVDTP流参数avdtp_stream_config.cfg.psc_mask = AVDT_PSC_TRANS;avdtp_stream_config.media_type = AVDT_MEDIA_TYPE_AUDIO;avdtp_stream_config.mtu = MAX_3MBPS_AVDTP_MTU;btav_a2dp_codec_index_t codec_index_min = BTAV_A2DP_CODEC_INDEX_SOURCE_MIN;btav_a2dp_codec_index_t codec_index_max = BTAV_A2DP_CODEC_INDEX_SOURCE_MAX;// 如果支持报告功能(BTA_AV_FEAT_REPORT),则配置相应的回调和标志if (bta_av_cb.features & BTA_AV_FEAT_REPORT) {avdtp_stream_config.cfg.psc_mask |= AVDT_PSC_REPORT;avdtp_stream_config.p_report_cback = bta_av_a2dp_report_cback;}// 如果支持延迟报告(BTA_AV_FEAT_DELAY_RPT),则设置相应的标志if (bta_av_cb.features & BTA_AV_FEAT_DELAY_RPT)avdtp_stream_config.cfg.psc_mask |= AVDT_PSC_DELAY_RPT;// 根据初始化的UUID设置传输端点(TSEP)和相应的回调if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE) { avdtp_stream_config.tsep = AVDT_TSEP_SRC;codec_index_min = BTAV_A2DP_CODEC_INDEX_SOURCE_MIN;codec_index_max = BTAV_A2DP_CODEC_INDEX_SOURCE_MAX;} else if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK) {avdtp_stream_config.tsep = AVDT_TSEP_SNK;avdtp_stream_config.p_sink_data_cback = bta_av_sink_data_cback;codec_index_min = BTAV_A2DP_CODEC_INDEX_SINK_MIN;codec_index_max = BTAV_A2DP_CODEC_INDEX_SINK_MAX;}// 初始化SEPs(同步端点)if (btif_av_src_sink_coexist_enabled()) {for (int xx = codec_index_min; xx < codec_index_max; xx++) {p_scb->seps[xx].av_handle = 0;}} else {for (int xx = 0; xx < BTAV_A2DP_CODEC_INDEX_MAX; xx++) {p_scb->seps[xx].av_handle = 0;}}/* keep the configuration in the stream control block *///保存配置并创建AVDTP流p_scb->cfg = avdtp_stream_config.cfg; // 将配置保存到SCB中for (int i = codec_index_min; i < codec_index_max; i++) {// 遍历支持的编解码器,初始化编解码器配置集(COS)btav_a2dp_codec_index_t codec_index =static_cast<btav_a2dp_codec_index_t>(i);if (!bta_av_co_is_supported_codec(codec_index)) {continue;}if (!(*bta_av_a2dp_cos.init)(codec_index, &avdtp_stream_config.cfg)) {continue;}// 创建AVDTP流if (AVDT_CreateStream(p_scb->app_id, &p_scb->seps[codec_index].av_handle,avdtp_stream_config) != AVDT_SUCCESS) {log::warn("bta_handle=0x{:x} (app_id {}) failed to alloc an SEP index:{}",p_scb->hndl, p_scb->app_id, codec_index);continue;} //如果创建成功,保存编解码器信息和传输端点/* Save a copy of the codec */memcpy(p_scb->seps[codec_index].codec_info,avdtp_stream_config.cfg.codec_info, AVDT_CODEC_SIZE);p_scb->seps[codec_index].tsep = avdtp_stream_config.tsep;if (avdtp_stream_config.tsep == AVDT_TSEP_SNK) {p_scb->seps[codec_index].p_app_sink_data_cback =p_data->api_reg.p_app_sink_data_cback;} else {/* In case of A2DP SOURCE we don't need a callback to* handle media packets.*/p_scb->seps[codec_index].p_app_sink_data_cback = NULL;}}// 根据角色和共存设置创建SDP记录if ((btif_av_src_sink_coexist_enabled() &&!(bta_av_cb.reg_role & (1 << local_role))) ||(!btif_av_src_sink_coexist_enabled() && !bta_av_cb.reg_audio)) {// 如果不支持源和接收器共存,或者注册的角色不匹配,则清除SDP句柄bta_av_cb.sdp_a2dp_handle = 0;bta_av_cb.sdp_a2dp_snk_handle = 0;// 5. SDP 记录创建与服务发现//根据初始化的UUID(源或接收器)创建SDP记录,并添加A2DP记录if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE) {/* create the SDP records on the 1st audio channel */bta_av_cb.sdp_a2dp_handle =get_legacy_stack_sdp_api()->handle.SDP_CreateRecord();A2DP_AddRecord(UUID_SERVCLASS_AUDIO_SOURCE, p_service_name, NULL,A2DP_SUPF_PLAYER, bta_av_cb.sdp_a2dp_handle);bta_sys_add_uuid(UUID_SERVCLASS_AUDIO_SOURCE);} else if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK) {bta_av_cb.sdp_a2dp_snk_handle =get_legacy_stack_sdp_api()->handle.SDP_CreateRecord();A2DP_AddRecord(UUID_SERVCLASS_AUDIO_SINK, p_service_name, NULL,A2DP_SUPF_PLAYER, bta_av_cb.sdp_a2dp_snk_handle);bta_sys_add_uuid(UUID_SERVCLASS_AUDIO_SINK);}/* start listening when A2DP is registered */// 如果支持远程控制目标(RCTG)功能,则创建AVRC实例if (bta_av_cb.features & BTA_AV_FEAT_RCTG)bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1);/* if the AV and AVK are both supported, it cannot support the CT role*/// 根据是否支持远程控制控制器(RCCT)和RCTG功能,注册AVCT并创建AVRC实例if (bta_av_cb.features & (BTA_AV_FEAT_RCCT)) {/* if TG is not supported, we need to register to AVCT now */if ((bta_av_cb.features & (BTA_AV_FEAT_RCTG)) == 0) {bta_ar_reg_avct();bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1);}/* create an SDP record as AVRC CT. We create 1.3 for SOURCE* because we rely on feature bits being scanned by external* devices more than the profile version itself.** We create 1.4 for SINK since we support browsing.*/// 根据共存设置和角色,为源和接收器注册不同版本的AVRCif (btif_av_src_sink_coexist_enabled()) {if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE) {bta_ar_reg_avrc_for_src_sink_coexist(UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL, NULL,p_bta_av_cfg->avrc_ct_cat, BTA_ID_AV,(bta_av_cb.features & BTA_AV_FEAT_BROWSE), AVRC_REV_1_5);} else if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK)bta_ar_reg_avrc_for_src_sink_coexist(UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL, NULL,p_bta_av_cfg->avrc_ct_cat, BTA_ID_AVK,(bta_av_cb.features & BTA_AV_FEAT_BROWSE), AVRC_REV_1_5);} else {if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE &&!is_new_avrcp_enabled()) {bta_ar_reg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL, NULL,p_bta_av_cfg->avrc_ct_cat,(bta_av_cb.features & BTA_AV_FEAT_BROWSE),AVRC_REV_1_3);} else if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK)bta_ar_reg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL, NULL,p_bta_av_cfg->avrc_ct_cat,(bta_av_cb.features & BTA_AV_FEAT_BROWSE),AVRC_REV_1_6);}}}bta_av_cb.reg_audio |= BTA_AV_HNDL_TO_MSK(p_scb->hdi); // 表示已注册的音频句柄log::verbose("reg_audio: 0x{:x}", bta_av_cb.reg_audio);} while (0);if (btif_av_src_sink_coexist_enabled()) {bta_av_cb.reg_role |= (1 << local_role); // 将当前设备的角色(源或接收器)注册到bta_av_cb的reg_role成员中// 设置对等端SEP(Streaming Endpoint)reg_data.peer_sep = (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE)? AVDT_TSEP_SNK: AVDT_TSEP_SRC;/* there are too much check depend on it's only source */if ((profile_initialized == UUID_SERVCLASS_AUDIO_SINK) &&(bta_av_cb.reg_role & (1 << AVDT_TSEP_SRC))) {p_bta_av_cfg = &bta_av_cfg; // 获取一个指向配置结构的指针if (!strncmp(AVRCP_1_3_STRING, avrcp_version,sizeof(AVRCP_1_3_STRING))) {  // ver if needlog::verbose("AVRCP 1.3 capabilites used");p_bta_av_cfg = &bta_av_cfg_compatibility; // 使用兼容性配置}}}// 7. 状态通知与收尾/* call callback with register event */tBTA_AV bta_av_data;bta_av_data.reg = reg_data;// 通过bta_av_cb.p_cback回调函数指针调用BTA_AV_REGISTER_EVT事件,通知上层应用或管理模块注册结果或状态(*bta_av_cb.p_cback)(BTA_AV_REGISTER_EVT, &bta_av_data); // 
}

完成 AV 服务的资源分配、协议栈注册、SDP(服务发现协议)记录创建及状态通知,是 AV 服务从 “注册请求” 到 “服务可用” 的关键执行逻辑。核心目标是:

  1. 资源分配:通过 SCB 管理音频流的生命周期,确保多流并发时的隔离与控制。

  2. 协议集成:注册 AVDTP/AVCT 协议栈,实现音频流传输与远程控制的底层支持。

  3. 服务发现:创建 SDP 记录,使远程设备能发现并连接本地音频服务。

  4. 兼容性保障:通过版本检测、多角色配置,确保与不同蓝牙设备的互操作性。

体现了蓝牙协议栈 “资源管理严谨性”“多角色支持灵活性” 和 “版本兼容性” 的设计原则,是 AV 服务稳定运行的关键基础设施。 其整体流程可概括为: 状态校验 → 资源分配(SCB)→ 协议栈注册(AVDTP/AVCT)→ SDP 记录创建 → 流参数配置 → 状态通知。

bta_av_alloc_scb
packages/modules/Bluetooth/system/bta/av/bta_av_main.cc
#define BTA_AV_CHNL_AUDIO 0x40 /* audio channel *//* maximum number of streams created */
#ifndef BTA_AV_NUM_STRS
#define BTA_AV_NUM_STRS 6
#endif/* initialization value for AVRC handle */
#define BTA_AV_RC_HANDLE_NONE 0xFF/********************************************************************************* Function         bta_av_alloc_scb** Description      allocate stream control block,*                  register the service to stack*                  create SDP record** Returns          void*******************************************************************************/
static tBTA_AV_SCB* bta_av_alloc_scb(tBTA_AV_CHNL chnl) {if (chnl != BTA_AV_CHNL_AUDIO) { // 只处理音频通道类型(BTA_AV_CHNL_AUDIO)的分配请求log::error("bad channel: {}", chnl);return nullptr;}// 遍历 SCB 数组寻找空闲位置for (int xx = 0; xx < BTA_AV_NUM_STRS; xx++) {if (bta_av_cb.p_scb[xx] != nullptr) continue;// Found an empty spot// TODO: After tBTA_AV_SCB is changed to a proper class, the entry// here should be allocated by C++ 'new' statement.//  分配并初始化 SCBtBTA_AV_SCB* p_ret = (tBTA_AV_SCB*)osi_calloc(sizeof(tBTA_AV_SCB));p_ret->rc_handle = BTA_AV_RC_HANDLE_NONE;p_ret->chnl = chnl;p_ret->hndl = (tBTA_AV_HNDL)((xx + 1) | chnl);p_ret->hdi = xx; // 记录SCB在数组中的索引(用于快速访问)p_ret->a2dp_list = list_new(nullptr);p_ret->avrc_ct_timer = alarm_new("bta_av.avrc_ct_timer");bta_av_cb.p_scb[xx] = p_ret; // 将SCB存入数组return p_ret;}return nullptr;
}

分配一个流控制块(stream control block),从预定义的 SCB 数组(bta_av_cb.p_scb)中找到空闲位置,分配并初始化一个新的 SCB 结构体,用于管理音频流的状态(如流句柄、通道类型、回调列表等)。它是 AV 子系统实现 “多音频流并发管理” 的基础函数。其核心作用是:

  • 资源池管理:通过预定义数组实现 SCB 的池化分配,限制最大并发流数量。

  • 初始化保障:为 SCB 分配内存并初始化关键字段,确保流管理的基础状态正确。

  • 唯一性标识:生成全局唯一的流句柄,为后续流操作(如控制、数据传输)提供标识依据。

体现了蓝牙协议栈 “资源高效管理” 和 “状态严谨性” 的设计原则。

AVDT_CreateStream
packages/modules/Bluetooth/system/stack/avdt/avdt_api.cc
/********************************************************************************* Function         AVDT_CreateStream** Description      Create a stream endpoint.  After a stream endpoint is*                  created an application can initiate a connection between*                  this endpoint and an endpoint on a peer device.  In*                  addition, a peer device can discover, get the capabilities,*                  and connect to this endpoint.*** Returns          AVDT_SUCCESS if successful, otherwise error.*******************************************************************************/
uint16_t AVDT_CreateStream(uint8_t peer_id, uint8_t* p_handle,const AvdtpStreamConfig& avdtp_stream_config) {tAVDT_RESULT result = AVDT_SUCCESS;AvdtpScb* p_scb;// 1. 参数合法性校验/* Verify parameters; if invalid, return failure */if (((avdtp_stream_config.cfg.psc_mask & (~AVDT_PSC)) != 0) ||(avdtp_stream_config.p_avdt_ctrl_cback == NULL)) {result = AVDT_BAD_PARAMS;log::error("Invalid AVDT stream endpoint parameters peer_id={} scb_index={}",peer_id, avdtp_stream_config.scb_index);}/* Allocate scb; if no scbs, return failure */else {// 2. 尝试为新的流端点分配一个SCB。SCB是用于管理流状态和控制信息的内部数据结构p_scb = avdt_scb_alloc(peer_id, avdtp_stream_config);if (p_scb == NULL) {log::error("Unable to create AVDT stream endpoint peer_id={} scb_index={}",peer_id, avdtp_stream_config.scb_index);result = AVDT_NO_RESOURCES;} else {// 3. 将SCB转换为句柄,并将该句柄存储在p_handle指向的位置*p_handle = avdt_scb_to_hdl(p_scb); log::debug("Created stream endpoint peer_id={} handle={}", peer_id,*p_handle);}}return static_cast<uint16_t>(result);
}

创建一个流端点(stream endpoint),创建成功后,应用程序能够基于此端点与对等设备(peer device)上的端点发起连接,同时对等设备也可以发现该端点、获取其功能特性并与之建立连接。其核心作用是:

  • 参数校验:确保流配置合法,避免非法参数影响协议栈稳定性。

  • 资源分配:通过 SCB 资源池管理流状态,支持多流并发。

  • 句柄生成:为新流生成唯一标识,供上层模块后续操作使用。

AVDT_CreateStream 是 BTA 层与 AVDT 层协作的关键接口,其典型调用场景(如 BTA_AV 注册音频流)流程如下:

  1. BTA 层发起请求:BTA_AV 模块在 bta_av_api_register 中调用 AVDT_CreateStream,传入流配置(如音频媒体类型、A2DP 编解码器、控制回调 bta_av_proc_stream_evt)。

  2. AVDT 层分配资源:AVDT 层校验参数后,分配 SCB 并初始化,生成流句柄返回给 BTA 层。

  3. BTA 层管理流:BTA 层将流句柄存储在 SCB 的 seps(流端点)数组中,后续通过句柄发起流连接或处理流事件(如数据到达)。

SDP_CreateRecord
packages/modules/Bluetooth/system/stack/sdp/sdp_db.cc
/* The maximum number of SDP records the server can support. */
#ifndef SDP_MAX_RECORDS
#define SDP_MAX_RECORDS 30
#endif/********************************************************************************* Function         SDP_CreateRecord** Description      This function is called to create a record in the database.*                  This would be through the SDP database maintenance API. The*                  record is created empty, teh application should then call*                  "add_attribute" to add the record's attributes.** Returns          Record handle if OK, else 0.*******************************************************************************/
uint32_t SDP_CreateRecord(void) {uint32_t handle;uint8_t buf[4];tSDP_DB* p_db = &sdp_cb.server_db;// 1. 记录数量限制校验/* First, check if there is a free record */if (p_db->num_records < SDP_MAX_RECORDS) {// 2. 初始化新记录结构体memset(&p_db->record[p_db->num_records], 0, sizeof(tSDP_RECORD));// 3. 分配唯一记录句柄/* We will use a handle of the first unreserved handle plus last record** number + 1 */if (p_db->num_records)handle = p_db->record[p_db->num_records - 1].record_handle + 1;elsehandle = 0x10000;p_db->record[p_db->num_records].record_handle = handle;// 4. 更新数据库记录数p_db->num_records++;log::verbose("SDP_CreateRecord ok, num_records:{}", p_db->num_records);/* Add the first attribute (the handle) automatically */// 5. 添加第一个属性:SDP记录必须至少有一个属性,即服务记录句柄属性(ATTR_ID_SERVICE_RECORD_HDL)UINT32_TO_BE_FIELD(buf, handle); //将32位无符号整数转换为大端格式的字节序列SDP_AddAttribute(handle, ATTR_ID_SERVICE_RECORD_HDL, UINT_DESC_TYPE, 4,buf); // 将服务记录句柄属性添加到新记录中return (p_db->record[p_db->num_records - 1].record_handle);} elselog::error("SDP_CreateRecord fail, exceed maximum records:{}",SDP_MAX_RECORDS);return (0);
}

在 SDP 服务器数据库中创建一个空的服务记录,分配唯一的记录句柄,并自动添加 SDP 规范要求的 “服务记录句柄属性”(ATTR_ID_SERVICE_RECORD_HDL,为后续通过 SDP_AddAttribute 添加其他服务属性(如服务类 UUID、协议描述)奠定基础。它是蓝牙设备 “服务发布” 流程的起点。其核心作用是:

  • 资源管理:通过最大记录数限制,保障 SDP 数据库的稳定性。

  • 句柄分配:生成唯一的记录句柄,作为后续操作的标识。

  • 规范符合性:自动添加 SDP 协议要求的 “服务记录句柄” 属性,确保记录合法性。

体现了蓝牙协议栈 “协议规范符合性” 和 “资源高效管理” 的设计原则,是设备间服务发现的关键基础设施。

SDP_CreateRecord 是蓝牙设备 “服务发布” 流程的关键步骤,其典型调用场景(如 BTA_AV 注册音频服务)流程如下:

  1. BTA 层发起创建请求:BTA_AV 模块在 bta_av_api_register 中调用 SDP_CreateRecord,创建一个空的 SDP 记录。

  2. 分配句柄并初始化属性SDP_CreateRecord 分配句柄(如 0x10000),并自动添加 “服务记录句柄” 属性。

  3. 添加其他服务属性:BTA 层通过 SDP_AddAttribute 为新记录添加其他属性(如服务类 UUID UUID_SERVCLASS_AUDIO_SOURCE、协议描述(A2DP)等)。

  4. 服务发现:远程设备通过 SDP 查询(SDP_ServiceSearchAttributeRequest)获取该记录,发现本地支持的音频服务并建立连接。

A2DP_AddRecord
packages/modules/Bluetooth/system/stack/a2dp/a2dp_api.cc
/******************************************************************************** Function         A2DP_AddRecord** Description      This function is called by a server application to add*                  SRC or SNK information to an SDP record.  Prior to*                  calling this function the application must call*                  SDP_CreateRecord() to create an SDP record.**                  Input Parameters:*                      service_uuid:  Indicates SRC or SNK.**                      p_service_name:  Pointer to a null-terminated character*                      string containing the service name.**                      p_provider_name:  Pointer to a null-terminated character*                      string containing the provider name.**                      features:  Profile supported features.**                      sdp_handle:  SDP handle returned by SDP_CreateRecord().**                  Output Parameters:*                      None.** Returns          A2DP_SUCCESS if function execution succeeded,*                  A2DP_INVALID_PARAMS if bad parameters are given.*                  A2DP_FAIL if function execution failed.******************************************************************************/
tA2DP_STATUS A2DP_AddRecord(uint16_t service_uuid, char* p_service_name,char* p_provider_name, uint16_t features,uint32_t sdp_handle) {uint16_t browse_list[1];bool result = true;uint8_t temp[8];uint8_t* p;tSDP_PROTOCOL_ELEM proto_list[A2DP_NUM_PROTO_ELEMS];log::verbose("uuid: 0x{:x}", service_uuid);// 1. 参数合法性校验if ((sdp_handle == 0) || (service_uuid != UUID_SERVCLASS_AUDIO_SOURCE &&service_uuid != UUID_SERVCLASS_AUDIO_SINK))return A2DP_INVALID_PARAMS;/* add service class id list */// 2. 添加服务类 ID 列表, 明确服务类型(源或接收端)result &= get_legacy_stack_sdp_api()->handle.SDP_AddServiceClassIdList(sdp_handle, 1, &service_uuid);// 3. 添加协议描述符列表// A2DP 基于 L2CAP(逻辑链路控制与适配协议)和 AVDTP(音频 / 视频分发传输协议)memset((void*)proto_list, 0,A2DP_NUM_PROTO_ELEMS * sizeof(tSDP_PROTOCOL_ELEM));/* add protocol descriptor list   */// 设置L2CAP和AVDTP协议及其参数proto_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;proto_list[0].num_params = 1;proto_list[0].params[0] = AVDT_PSM; // L2CAP的PSM(协议服务多路复用器)proto_list[1].protocol_uuid = UUID_PROTOCOL_AVDTP;proto_list[1].num_params = 1;proto_list[1].params[0] = a2dp_cb.avdt_sdp_ver;result &= get_legacy_stack_sdp_api()->handle.SDP_AddProtocolList(sdp_handle, A2DP_NUM_PROTO_ELEMS, proto_list);/* add profile descriptor list   */// 4. 添加轮廓描述符列表, 声明该服务符合 A2DP 配置文件的规范result &= get_legacy_stack_sdp_api()->handle.SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_ADV_AUDIO_DISTRIBUTION, A2DP_VERSION);// 5. 添加支持的特性/* add supported feature */if (features != 0) {p = temp;UINT16_TO_BE_STREAM(p, features); // 转换为大端格式的字节序列result &= get_legacy_stack_sdp_api()->handle.SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE, (uint32_t)2,(uint8_t*)temp);}// 6. 添加可选文本属性(服务名称、提供者名称),提升用户体验/* add provider name */if (p_provider_name != NULL) {result &= get_legacy_stack_sdp_api()->handle.SDP_AddAttribute(sdp_handle, ATTR_ID_PROVIDER_NAME, TEXT_STR_DESC_TYPE,(uint32_t)(strlen(p_provider_name) + 1), (uint8_t*)p_provider_name);}/* add service name */// 添加服务名称(可选)if (p_service_name != NULL) {result &= get_legacy_stack_sdp_api()->handle.SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,(uint32_t)(strlen(p_service_name) + 1), (uint8_t*)p_service_name);}/* add browse group list */// 7. 添加浏览组列表// 将服务加入 “公共浏览组”,远程设备可通过浏览组快速发现此类服务(如 “音频 / 视频设备” 组)browse_list[0] = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;result &= get_legacy_stack_sdp_api()->handle.SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, browse_list);return (result ? A2DP_SUCCESS : A2DP_FAIL);
}

将 A2DP 源(Source)或接收端(Sink)的关键信息(如服务类型、支持的协议、特性)填充到 SDP 记录中,是蓝牙设备间通过 SDP 发现并建立 A2DP 连接的关键步骤。

其核心作用是:

  • 规范填充:在已创建的 SDP 记录(通过 SDP_CreateRecord)中,填充 A2DP 服务的标准化属性(如服务类 ID、协议描述、支持特性),使远程设备通过 SDP 查询时,能识别本地设备支持的 A2DP 服务类型(源 / 接收端)、通信协议及功能特性,最终建立符合 A2DP 规范的音频流连接。

  • 功能声明:通过 “支持的特性” 属性告知远程设备本地支持的 A2DP 功能,为后续连接参数协商奠定基础。

  • 服务发现:通过浏览组和服务名称属性,提升服务的可发现性和用户友好性。

A2DP_AddRecord 是 SDP 记录创建的 “填充阶段”,其典型调用流程如下:

  1. 创建 SDP 记录:上层模块(如 BTA_AV)调用 SDP_CreateRecord 创建空记录,获取句柄(sdp_handle)。

  2. 填充 A2DP 信息:调用 A2DP_AddRecord,传入句柄和 A2DP 参数(服务类型、特性等),填充标准化属性。

  3. 完成服务发布:SDP 记录填充完成后,远程设备通过 SDP 查询(如 SDP_ServiceSearchAttributeRequest)获取记录,解析其中的属性(服务类型、协议、特性),最终建立 A2DP 连接。

bta_av_rc_create
packages/modules/Bluetooth/system/bta/av/bta_av_act.cc
/********************************************************************************* Function         bta_av_rc_create** Description      alloc RCB and call AVRC_Open** Returns          the created rc handle*******************************************************************************/
uint8_t bta_av_rc_create(tBTA_AV_CB* p_cb, uint8_t role, uint8_t shdl,uint8_t lidx) {// 1. 配置校验:跳过旧版 AVRCP 连接(可选逻辑)if ((!btif_av_src_sink_coexist_enabled() ||(btif_av_src_sink_coexist_enabled() && !btif_av_is_sink_enabled() &&btif_av_is_source_enabled())) &&is_new_avrcp_enabled()) {log::info("Skipping RC creation for the old AVRCP profile");return BTA_AV_RC_HANDLE_NONE;}tAVRC_CONN_CB ccb;RawAddress bda = RawAddress::kAny;uint8_t status = BTA_AV_RC_ROLE_ACP;int i;uint8_t rc_handle;tBTA_AV_RCB* p_rcb;// 2. 角色分支:内部角色(AVCT_INT)处理if (role == AVCT_INT) {// Can't grab a stream control block that doesn't have a valid handleif (!shdl) {log::error("Can't grab stream control block for shdl = {} -> index = {}",shdl, shdl - 1);return BTA_AV_RC_HANDLE_NONE;}//尝试获取流控制块(SCB),设置设备地址和遥控角色,并更新设备IoT配置tBTA_AV_SCB* p_scb = p_cb->p_scb[shdl - 1];bda = p_scb->PeerAddress();status = BTA_AV_RC_ROLE_INT;DEVICE_IOT_CONFIG_ADDR_INT_ADD_ONE(p_scb->PeerAddress(),IOT_CONF_KEY_AVRCP_CONN_COUNT);} // 3. 角色分支:非内部角色处理(如控制者 / 目标)else {// 尝试获取现有的遥控块(RCB)。如果找到了,则更新其lidx并返回其句柄p_rcb = bta_av_get_rcb_by_shdl(shdl);if (p_rcb != NULL) {log::error("ACP handle exist for shdl:{}", shdl);p_rcb->lidx = lidx;return p_rcb->handle;}}// 4. 配置 AVRCP 连接控制块(ccb)ccb.ctrl_cback = base::Bind(bta_av_rc_ctrl_cback);  // 控制事件回调(如连接状态变化)ccb.msg_cback = base::Bind(bta_av_rc_msg_cback); // 消息事件回调(如控制命令接收)ccb.company_id = p_bta_av_cfg->company_id; // 本地设备的公司ID(用于标识厂商)ccb.conn = role;/* note: BTA_AV_FEAT_RCTG = AVRC_CT_TARGET, BTA_AV_FEAT_RCCT = AVRC_CT_CONTROL*/// 支持的控制功能(目标、控制、元数据等)ccb.control = p_cb->features & (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_RCCT |BTA_AV_FEAT_METADATA | AVRC_CT_PASSIVE);// 5. 打开AVRCP连接:调用AVRC_Open尝试建立AVRCP连接。如果失败,则更新IoT配置中的失败计数if (AVRC_Open(&rc_handle, &ccb, bda) != AVRC_SUCCESS) {DEVICE_IOT_CONFIG_ADDR_INT_ADD_ONE(bda, IOT_CONF_KEY_AVRCP_CONN_FAIL_COUNT);return BTA_AV_RC_HANDLE_NONE;}// 6. 初始化 RCB 并记录连接状态i = rc_handle;p_rcb = &p_cb->rcb[i];if (p_rcb->handle != BTA_AV_RC_HANDLE_NONE) {log::error("found duplicated handle:{}", rc_handle);}//更新遥控块:如果连接成功,更新遥控块(RCB)的句柄、状态、流句柄、链接索引等信息p_rcb->handle = rc_handle;p_rcb->status = status;p_rcb->shdl = shdl;p_rcb->lidx = lidx;p_rcb->peer_features = 0;p_rcb->peer_ct_features = 0;p_rcb->peer_tg_features = 0;p_rcb->cover_art_psm = 0;// 7. 特殊处理:ACP 连接记录if (lidx == (BTA_AV_NUM_LINKS + 1)) { /* this LIDX is reserved fo/home/yanlongli/code/android/packages/modules/Bluetooth/system/bta/av/bta_av_act.ccr the AVRCP ACP connection */p_cb->rc_acp_handle = p_rcb->handle;p_cb->rc_acp_idx = (i + 1);log::verbose("rc_acp_handle:{} idx:{}", p_cb->rc_acp_handle,p_cb->rc_acp_idx);}log::verbose("create {}, role: {}, shdl:{}, rc_handle:{}, lidx:{}, status:0x{:x}", i,role, shdl, p_rcb->handle, lidx, p_rcb->status);return rc_handle;
}

管理 AVRCP 连接的生命周期,确保蓝牙设备间能通过 AVRCP 协议实现音频 / 视频的远程控制(如播放、暂停、音量调节)。核心职责是:

  1. 连接前校验:根据配置(如是否启用新旧 AVRCP 兼容、源 / 接收端共存)决定是否跳过旧版 AVRCP 连接创建。

  2. 资源复用:检查是否已有同流句柄(shdl)的 RCB,避免重复创建连接。

  3. 连接建立:配置 AVRCP 连接参数(回调、功能集),调用底层 AVRC_Open 建立物理连接。

  4. 状态管理:初始化 RCB(存储连接状态、句柄、对端信息),并记录特殊连接(如 ACP 连接)的句柄。

函数参数与关键变量:

参数 / 变量类型说明
p_cbtBTA_AV_CB*BTA AV 模块的全局控制块(存储 SCB、RCB 等核心数据结构)
roleuint8_t连接角色(AVCT_INT:内部角色;其他:如控制者(CT)或目标(TG))
shdluint8_t流句柄(关联音频流的 SCB,用于绑定 AVRCP 连接与音频流)
lidxuint8_t链接索引(标识蓝牙控制器中的物理链路)
rc_handleuint8_t输出参数:AVRCP 连接句柄(由 AVRC_Open 生成,用于后续操作)
p_rcbtBTA_AV_RCB*AVRCP 连接控制块指针(存储连接状态、对端特性、句柄等信息)

ACP(Audio/Video Control Point):AVRCP 的控制端点,用于发送控制命令(如播放、停止)。

bta_av_rc_create 是 BTA 层管理 AVRCP 连接的关键入口,其典型调用场景(如音频流建立时的控制连接)流程如下:

  1. 音频流关联:BTA_AV 模块在创建音频流(SCB)后,调用 bta_av_rc_create 为该流创建关联的 AVRCP 连接(内部角色)。

  2. 连接建立:通过 AVRC_Open 与对端设备建立 AVRCP 连接,生成句柄。

  3. 状态同步:RCB 记录连接状态,后续控制命令(如播放)通过该句柄发送到对端。

  4. 连接释放:当音频流断开时,BTA 层调用 bta_av_rc_close 释放 RCB 并关闭 AVRCP 连接。

AVRC_Open分析见后面文章。

三、流程图


Bluedroid 中 A2DP Sink 服务的启用是多模块协作的典型案例,其设计体现以下特点:

  • 事件驱动:通过bta_sys_sendmsgbta_sys_event的消息总线机制,实现跨线程事件分发与处理,确保模块间松耦合。

  • 资源管理:通过流控制块(SCB)池化分配、SDP 记录数限制等机制,保障多流并发场景下的资源高效利用与稳定性。

  • 多设备支持:通过遍历设备 ID(peer_id)注册多实例服务、SCB 隔离管理等设计,支持同时连接多个音频源设备。

  • 协议兼容性:通过版本检测(如 AVRCP 1.3/1.6)、特性位配置(如BTA_AV_FEAT_DELAY_RPT),确保与不同蓝牙设备的互操作性。


http://www.xdnf.cn/news/15763.html

相关文章:

  • 一动一静皆消耗——IC设计之低功耗技术(Low Power Design)
  • install_arm_docker.sh
  • Redis性能测试全攻略:工具实操与性能优化指南
  • 安装单机版本Redis
  • 2025第15届上海国际生物发酵展:聚焦合成生物与绿色制造,共启生物经济新时代
  • 在 .NET Core 中创建 Web Socket API
  • Spring AI 1.0版本 + 千问大模型之文本对话
  • FPGA自学——二选一多路选择器
  • 南洋理工空中导航零样本迁移与泛化!VLFly:基于开放词汇目标理解的无人机视觉语言导航
  • 1. Spring AI概述
  • 论文略读:Are Large Language Models In-Context Graph Learners?
  • 100条常用SQL语句
  • javaweb的几大常见漏洞
  • YOLOv11改进 | DWRSeg扩张式残差助力小目标检测
  • 3.条件判断:让程序学会做选择
  • gitlab+jenkins
  • 【数据结构】栈(stack)
  • Uniapp之自定义图片预览
  • Linux --进程信号
  • 初识C++——开启新旅途
  • 【51单片机学习】LED、独立按键
  • ENSP路由综合实验 + 思科(cisco)/华为(ensp)链路聚合实验
  • C++中的vector(2)
  • 基于Python的口腔正畸健康教育聊天机器人开发与评估研究
  • PyCharm + AI 辅助编程
  • 深度学习图像分类数据集—六十种植物病害分类
  • 基于单片机宠物喂食器/智能宠物窝/智能饲养
  • Typecho博客Ajax评论功能实现全攻略
  • 车载诊断架构 --- OEM对于DTC相关参数得定义
  • FastAPI遇上GraphQL:异步解析器如何让API性能飙升?