在车机中 a2dp 通常情况下作为 sink. 本篇来帮助各位 朋友梳理一下,这部分的初始化流程。
我们着重梳理 native 层的逻辑, framework - java 侧一般比较容易看明白, 暂时不做梳理。 如果需要笨叔梳理的可以在博客评论。 出专门的章节来梳理。
本篇的目的只有一个,在 初始化流程中 梳理出 avdtp 在 l2cap 层的回调接口。 这样我们就可以 从 l2cap 层, 的接口回调中,配合具体案例,来分析 avdtp 的所有内容。
蓝牙进程在拉起来的时候, 回去加载 A2dpSinkNativeInterface 类,此时就会触发 对应的 classInitNative 调用。
当 A2dpSinkNativeInterface.java 调用 加载时,会调用 c++ 的 classInitNative,
// android/app/src/com/android/bluetooth/a2dpsink/A2dpSinkNativeInterface.java
public class A2dpSinkNativeInterface {
private static final String TAG = "A2dpSinkNativeInterface";
private static final boolean DBG = A2dpSinkService.DBG;//Log.isLoggable(TAG, Log.DEBUG);
private AdapterService mAdapterService;
@GuardedBy("INSTANCE_LOCK")
private static A2dpSinkNativeInterface sInstance;
private static final Object INSTANCE_LOCK = new Object();
static {
classInitNative();
}
// android/app/jni/com_android_bluetooth_a2dp_sink.cpp
static JNINativeMethod sMethods[] = {
{"classInitNative", "()V", (void*)classInitNative},
{"initNative", "(I)V", (void*)initNative},
{"cleanupNative", "()V", (void*)cleanupNative},
{"connectA2dpNative", "([B)Z", (void*)connectA2dpNative},
{"disconnectA2dpNative", "([B)Z", (void*)disconnectA2dpNative},
{"informAudioFocusStateNative", "(I)V", (void*)informAudioFocusStateNative},
{"informAudioTrackGainNative", "(F)V", (void*)informAudioTrackGainNative},
{"setActiveDeviceNative", "([B)Z", (void*)setActiveDeviceNative},
};
int register_com_android_bluetooth_a2dp_sink(JNIEnv* env) {
return jniRegisterNativeMethods(
env, "com/android/bluetooth/a2dpsink/A2dpSinkNativeInterface", sMethods,
NELEM(sMethods));
}
static void classInitNative(JNIEnv* env, jclass clazz) {
method_onConnectionStateChanged =
env->GetMethodID(clazz, "onConnectionStateChanged", "([BI)V");
method_onAudioStateChanged =
env->GetMethodID(clazz, "onAudioStateChanged", "([BI)V");
method_onAudioConfigChanged =
env->GetMethodID(clazz, "onAudioConfigChanged", "([BII)V");
ALOGI("%s: succeeds", __func__);
}
当A2dpSinkService 启动时, 才真正的触发 调用 a2dpsink 协议栈部分的初始化
// android/app/src/com/android/bluetooth/a2dpsink/A2dpSinkService.java
protected boolean start() {
mAdapterService = Objects.requireNonNull(AdapterService.getAdapterService(),
"AdapterService cannot be null when A2dpSinkService starts");
mDatabaseManager = Objects.requireNonNull(AdapterService.getAdapterService().getDatabase(),
"DatabaseManager cannot be null when A2dpSinkService starts");
mNativeInterface = A2dpSinkNativeInterface.getInstance();
mMaxConnectedAudioDevices = mAdapterService.getMaxConnectedAudioDevices();
mNativeInterface.init(mMaxConnectedAudioDevices); // 这里才真正的触发 调用 a2dpsink 协议栈初始化
synchronized (mStreamHandlerLock) {
mA2dpSinkStreamHandler = new A2dpSinkStreamHandler(this, mNativeInterface);
}
// android/app/src/com/android/bluetooth/a2dpsink/A2dpSinkNativeInterface.java
public void init(int maxConnectedAudioDevices) {
initNative(maxConnectedAudioDevices); // 这个是触发 a2dp sink 协议栈初始化的点。
}
// android/app/jni/com_android_bluetooth_a2dp_sink.cpp
static void initNative(JNIEnv* env, jobject object,
jint maxConnectedAudioDevices) {
...
sBluetoothA2dpInterface =
(btav_sink_interface_t*)btInf->get_profile_interface(
BT_PROFILE_ADVANCED_AUDIO_SINK_ID);
// 这里实际触发到了 btif_av.cc::init_sink
bt_status_t status = sBluetoothA2dpInterface->init(&sBluetoothA2dpCallbacks,
maxConnectedAudioDevices);
...
}
上面已经看清楚了触发时机,那就是 当A2dpSinkService 启动时,触发 调用 a2dpsink 协议栈部分的初始化。
为啥触发到 btif_av.cc::init_sink
// system/btif/src/bluetooth.cc
static const void* get_profile_interface(const char* profile_id) {
...
if (is_profile(profile_id, BT_PROFILE_ADVANCED_AUDIO_SINK_ID))
return btif_av_get_sink_interface();
}
// system/btif/src/btif_av.cc
const btav_sink_interface_t* btif_av_get_sink_interface(void) {
BTIF_TRACE_EVENT("%s", __func__);
return &bt_av_sink_interface;
}
// system/btif/src/btif_av.cc
static const btav_sink_interface_t bt_av_sink_interface = {
sizeof(btav_sink_interface_t),
init_sink, // 这里会触发初始化
sink_connect_src,
sink_disconnect_src,
cleanup_sink,
update_audio_focus_state,
update_audio_track_gain,
sink_set_active_device};
// system/btif/src/btif_av.cc
static BtifAvSink btif_av_sink;
static bt_status_t init_sink(btav_sink_callbacks_t* callbacks,
int max_connected_audio_devices) {
BTIF_TRACE_EVENT("%s", __func__);
return btif_av_sink.Init(callbacks, max_connected_audio_devices);
}
// system/btif/src/btif_av.cc
bt_status_t BtifAvSink::Init(btav_sink_callbacks_t* callbacks,
int max_connected_audio_devices) {
...
btif_enable_service(BTA_A2DP_SINK_SERVICE_ID); // 这里去使能 a2dp_sink
enabled_ = true;
return BT_STATUS_SUCCESS;
}
这里当地插一句, 我们 协议栈侧 的native 服务 ,基本是通过 btif_enable_service 函数来 使能的。
- btif_enable_service(BTA_A2DP_SOURCE_SERVICE_ID)
- btif_enable_service(BTA_A2DP_SINK_SERVICE_ID)
- btif_enable_service(BTA_HIDD_SERVICE_ID)
- btif_enable_service(BTA_HFP_HS_SERVICE_ID)
- btif_enable_service(BTA_HFP_SERVICE_ID)
- btif_enable_service(BTA_HID_SERVICE_ID)
- btif_enable_service(BTA_SDP_SERVICE_ID)
// system/bta/include/bta_api.h
#define BTA_A2DP_SINK_SERVICE_ID 18 /* A2DP Sink */
// system/btif/src/btif_core.cc
void btif_enable_service(tBTA_SERVICE_ID service_id) {
btif_enabled_services |= (1 << service_id); // 记录当前启动的服务
BTIF_TRACE_DEBUG("%s: current services:0x%x", __func__,
btif_enabled_services);
if (btif_is_enabled()) {
btif_dm_enable_service(service_id, true);
}
}
// system/btif/src/btif_dm.cc
/*
* 这个函数的目的是:在底层启用或关闭某个 Bluetooth Profile 服务,并在启用成功后,将本地支持的 UUID 列表更新到上层(Java 层),以便系统知道当前本机支持哪些蓝牙 Profile。
*/
void btif_dm_enable_service(tBTA_SERVICE_ID service_id, bool enable) {
bt_status_t status = btif_in_execute_service_request(service_id, enable); // 调用底层逻辑来开启或关闭实际的蓝牙服务。
if (status == BT_STATUS_SUCCESS) {
// 说明服务已经初始化成功,那么系统现在支持的 Profile 也发生了变化,我们就需要将这个变化通知 Java 层。
bt_property_t property;
Uuid local_uuids[BT_MAX_NUM_UUIDS];
/* Now send the UUID_PROPERTY_CHANGED event to the upper layer */
BTIF_STORAGE_FILL_PROPERTY(&property, BT_PROPERTY_UUIDS,
sizeof(local_uuids), local_uuids);// 这一步只是初始化 `property`,下一步才真正获取 UUID。
btif_storage_get_adapter_property(&property);// 这个函数负责从配置文件(如 `/data/misc/bluedroid/bt_config.conf`)中获取当前注册的 Profile UUID 列表,填充到 local_uuids 数组中。
invoke_adapter_properties_cb(BT_STATUS_SUCCESS, 1, &property);// 调用 Java 层注册的 BluetoothAdapterPropertiesCallback 回调,让 Java 层知道:蓝牙支持的服务列表(UUID)更新了」,可以刷新界面或更新系统状态
}
return;
}
btif_dm_enable_service 函数主要做如下几件事情:
最终 uuid 会上报到:AdapterProperties.mUuids 中
class AdapterProperties {
private volatile ParcelUuid[] mUuids;
ParcelUuid[] getUuids() {
return mUuids;
}
void adapterPropertyChangedCallback(int[] types, byte[][] values) {
Intent intent;
int type;
byte[] val;
for (int i = 0; i < types.length; i++) {
val = values[i];
type = types[i];
infoLog("adapterPropertyChangedCallback with type:" + type + " len:" + val.length);
synchronized (mObject) {
switch (type) {
case AbstractionLayer.BT_PROPERTY_UUIDS:
mUuids = Utils.byteArrayToUuid(val); // 最终 uuid 会上报到这里
break;
}
}
// 当应用层调用 connectAllEnabledProfiles 连接时, 才能去连接对应的服务。
// android/app/src/com/android/bluetooth/btservice/AdapterService.java
public int connectAllEnabledProfiles(BluetoothDevice device) {
ParcelUuid[] localDeviceUuids = mAdapterProperties.getUuids();
if (mA2dpService != null && isSupported(localDeviceUuids, remoteDeviceUuids,
BluetoothProfile.A2DP, device)) {
Log.i(TAG, "connectAllEnabledProfiles: Connecting A2dp");
// Set connection policy also connects the profile with CONNECTION_POLICY_ALLOWED
mA2dpService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
numProfilesConnected++;
}
}
我们接着去分析 btif_in_execute_service_request 看 a2dpsink 是如何启动的。
// system/btif/src/btif_dm.cc
bt_status_t btif_in_execute_service_request(tBTA_SERVICE_ID service_id,
bool b_enable) {
switch (service_id) {
case BTA_A2DP_SINK_SERVICE_ID: {
btif_av_sink_execute_service(b_enable);
} break;
// system/btif/src/btif_av.cc
bt_status_t btif_av_sink_execute_service(bool enable) {
BTIF_TRACE_EVENT("%s: Sink service: %s", __func__,
(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.
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;
if (delay_reporting_enabled()) {
features |= BTA_AV_FEAT_DELAY_RPT;
}
BTA_AvEnable(features, bta_av_sink_callback); // 这个地方会向 bta 层注册处理处理函数。
btif_av_sink.RegisterAllBtaHandles(); // 我们还是着重分析一下 他
return BT_STATUS_SUCCESS;
}
// Disable the service
btif_av_sink.DeregisterAllBtaHandles();
BTA_AvDisable();
return BT_STATUS_SUCCESS;
}
// system/bta/av/bta_av_api.cc
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); // 这样 jni 下来的数据, 就可以通过 bta_sys_sendmsg 下发给 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); // bta av 第一个处理的事件就是 BTA_AV_API_ENABLE_EVT 事件
}
static const tBTA_SYS_REG bta_av_reg = {bta_av_hdl_event, BTA_AvDisable};
// system/bta/av/bta_av_main.cc
bool bta_av_hdl_event(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) {
/*
非状态机事件(如 ENABLE、DISABLE)
不依赖任何状态,比如:
`BTA_AV_API_ENABLE_EVT`:初始化回调、注册模块
`BTA_AV_API_DISABLE_EVT`:反注册模块
*/
APPL_TRACE_VERBOSE("%s: AV nsm event=0x%x(%s)", __func__, 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) {
/*
主状态机事件(如控制流程)
依赖全局状态 `bta_av_cb`
管理连接、注册、发现等控制逻辑
举例事件:
BTA_AV_API_REGISTER_EVT
BTA_AV_API_OPEN_EVT
*/
APPL_TRACE_VERBOSE("%s: AV sm event=0x%x(%s)", __func__, 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 {
/*
子状态机事件(具体媒体流)
针对每一个媒体流连接(SCB)都有一个独立状态机
可同时管理多个音频会话(比如双设备播放)
举例事件:
BTA_AV_STR_OPEN_EVT(Stream open)
BTA_AV_STR_START_EVT(Start playback)
BTA_AV_STR_CLOSE_EVT
*/
APPL_TRACE_VERBOSE("%s: bta_handle=0x%x", __func__, 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;
}
bta_av_hdl_event()
函数,是 A2DP 模块中 统一处理所有 BTA_AV 事件的分发器(dispatcher)。它根据事件的类型,将事件分发给不同的处理逻辑(函数)来处理 —— 本质上是 “职责分离 + 状态感知” 的策略。
事件类型范围 | 处理函数 | 对应状态机/作用 |
---|---|---|
BTA_AV_FIRST_NSM_EVT ~ BTA_AV_LAST_EVT |
bta_av_non_state_machine_event() |
全局事件(非状态相关),如 enable、disable |
BTA_AV_FIRST_SM_EVT ~ BTA_AV_LAST_SM_EVT |
bta_av_sm_execute() |
主状态机(control block),处理如 register、discover、open |
其它事件(不在以上两个范围) | bta_av_ssm_execute() |
每个 stream 实例的状态机,例如一个 A2DP 连接的媒体流生命周期 |
清晰职责分离
类型 | 管理内容 | 状态 |
---|---|---|
Non-State-Machine | 模块初始化、功能开关 | 无状态 |
State-Machine | 控制模块行为 | 注册、发现、连接 |
Sub-State-Machine | 每路媒体流 | 打开、播放、暂停 |
支持多设备连接
提高可维护性 & 扩展性
你可以把这个机制类比为:
问题 | 解答 |
---|---|
为何用不同处理函数? | 事件来源不同,作用域不同:有全局控制的,有媒体流专属的 |
如何区分处理? | 通过 event 范围判断,派发到对应函数 |
好处? | 解耦清晰、可支持多媒体流、模块化强 |
我们继续分析一下 btif_av_sink.RegisterAllBtaHandles()
// system/btif/src/btif_av.cc
void BtifAvSink::RegisterAllBtaHandles() {
for (int peer_id = kPeerIdMin; peer_id < kPeerIdMax; peer_id++) {
BTA_AvRegister(BTA_AV_CHNL_AUDIO, kBtifAvSinkServiceName.c_str(), peer_id,
bta_av_sink_media_callback, UUID_SERVCLASS_AUDIO_SINK);
}
}
// system/bta/av/bta_av_api.cc
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; // 在 bta_av_hdl_event 中处理 BTA_AV_API_REGISTER_EVT 事件
if (p_service_name)
strlcpy(p_buf->p_service_name, p_service_name, BTA_SERVICE_NAME_LEN);
else
p_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);
}
// 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_REGISTER_EVT:
bta_av_api_register(p_data);
break;
// system/bta/av/bta_av_main.cc
static void bta_av_api_register(tBTA_AV_DATA* p_data) {
...
if (bta_av_cb.reg_audio == 0) {
/* the first channel registered. register to AVDTP */
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;
bta_ar_reg_avdt(®, bta_av_conn_cback); // 这里我们终于看到注册 avdt 的地方。
bta_sys_role_chg_register(&bta_av_sys_rs_cback);
...
}
...
}
// system/bta/ar/bta_ar.cc
void bta_ar_reg_avdt(AvdtpRcb* p_reg, tAVDT_CTRL_CBACK* p_cback) {
bta_ar_cb.p_av_conn_cback = p_cback; // 将 bta_av_conn_cback 赋值给 p_av_conn_cback
if (bta_ar_cb.avdt_registered == 0) {
AVDT_Register(p_reg, bta_ar_avdt_cback); // 注册 avdt
} else {
APPL_TRACE_WARNING("%s: doesn't register again (registered:%d)", __func__,
bta_ar_cb.avdt_registered);
}
bta_ar_cb.avdt_registered |= BTA_AR_AV_MASK;
}
// system/stack/avdt/avdt_api.cc
void AVDT_Register(AvdtpRcb* p_reg, tAVDT_CTRL_CBACK* p_cback) {
/* register PSM with L2CAP */
L2CA_Register2(AVDT_PSM, avdt_l2c_appl, true /* enable_snoop */, nullptr,
kAvdtpMtu, 0, BTA_SEC_AUTHENTICATE);
/* initialize AVDTP data structures */
avdt_scb_init(); // 初始化 流控制块
avdt_ccb_init(); // 初始化 通道控制块
avdt_ad_init(); // 初始化 适配层
/* copy registration struct */
avdtp_cb.rcb = *p_reg;
avdtp_cb.p_conn_cback = p_cback; // bta_ar_avdt_cback ; 在 avdt_ccb_ll_opened 函数中会调用 p_conn_cback, 从而触发 bta_ar_avdt_cback 的调用 -> p_av_conn_cback(实际调用的是 bta_av_conn_cback)
}
/* L2CAP callback function structure */
const tL2CAP_APPL_INFO avdt_l2c_appl = {avdt_l2c_connect_ind_cback,
avdt_l2c_connect_cfm_cback,
avdt_l2c_config_ind_cback,
avdt_l2c_config_cfm_cback,
avdt_l2c_disconnect_ind_cback,
NULL,
avdt_l2c_data_ind_cback,
avdt_l2c_congestion_ind_cback,
NULL,
avdt_on_l2cap_error,
NULL,
NULL,
NULL,
NULL};
回调函数名 | 触发时机说明 | 所在连接阶段 | 主要用途/作用描述 |
---|---|---|---|
avdt_l2c_connect_ind_cback |
远端设备(如手机)发起连接请求时触发 | L2CAP 建立阶段 | 接受连接、为新信令通道分配 SCB |
avdt_l2c_connect_cfm_cback |
本地设备作为 发起方主动连接成功时 触发(L2CAP connect response) | L2CAP 建立阶段 | 通知连接成功、准备发送配置请求 |
avdt_l2c_config_ind_cback |
对方发送 L2CAP 配置请求(ConfigReq) 时触发 | L2CAP 配置阶段 | 回应对方的配置请求 |
avdt_l2c_config_cfm_cback |
本地发送的 L2CAP 配置请求收到回应(ConfigRsp) 时触发 | L2CAP 配置阶段 | 标记配置完成、准备发送 AVDTP 信令 |
avdt_l2c_disconnect_ind_cback |
信令通道或媒体通道 被远端断开或异常断开 时触发 | 任意阶段(断链) | 清理资源、通知上层连接已断 |
NULL |
占位字段,无回调 | - | - |
avdt_l2c_data_ind_cback |
收到远端 L2CAP 信道的数据包(AVDTP 信令包或媒体包)时触发 | 正常通信阶段 | 将数据交由 AVDTP 层解析(区分信令/媒体) |
avdt_l2c_congestion_ind_cback |
L2CAP 通道发生 拥塞状态变化(进入/退出拥塞) 时触发 | 正常通信阶段 | 通知上层暂停或恢复数据发送 |
NULL |
占位字段,无回调 | - | - |
avdt_on_l2cap_error |
L2CAP 通信过程出现异常(如参数错误、协商失败)时触发 | 任意阶段(错误) | 异常处理、通知断链 |
其他 NULL |
预留未用字段(如 retransmit, QoS, flush, tx complete 等) | - | - |
看到这里, 我们已经 找到了 avdtp 关于 l2cap 层的回调了。 之后会有专门的篇幅来分析 车机主动连 a2dp, 被动连a2dp. 到时候, 就不用再梳理这块了。 本篇相当于是, 梳理一下整体思路。 方便之后的篇幅里面直接查找函数。
例如如果看到 bta_sys_sendmsg(p_buf):
l2cap 中的回调,我们直接回去找 avdt_l2c_appl 变量中的函数即可。
/* L2CAP callback function structure */
const tL2CAP_APPL_INFO avdt_l2c_appl = {avdt_l2c_connect_ind_cback,
avdt_l2c_connect_cfm_cback,
avdt_l2c_config_ind_cback,
avdt_l2c_config_cfm_cback,
avdt_l2c_disconnect_ind_cback,
NULL,
avdt_l2c_data_ind_cback,
avdt_l2c_congestion_ind_cback,
NULL,
avdt_on_l2cap_error,
NULL,
NULL,
NULL,
NULL};