【android bluetooth 协议分析 11】【AVDTP详解 2】【avdtp 初始化阶段主要回调关系梳理】

在车机中 a2dp 通常情况下作为 sink. 本篇来帮助各位 朋友梳理一下,这部分的初始化流程。

我们着重梳理 native 层的逻辑, framework - java 侧一般比较容易看明白, 暂时不做梳理。 如果需要笨叔梳理的可以在博客评论。 出专门的章节来梳理。

本篇的目的只有一个,在 初始化流程中 梳理出 avdtp 在 l2cap 层的回调接口。 这样我们就可以 从 l2cap 层, 的接口回调中,配合具体案例,来分析 avdtp 的所有内容。

1. java侧触发a2dpsink协议栈初始化

蓝牙进程在拉起来的时候, 回去加载 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__);
}

  • 在 classInitNative 中我们只是 获取了 几个java 层的回调函数:
    • onConnectionStateChanged
    • onAudioStateChanged
    • onAudioConfigChanged

当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 协议栈部分的初始化。

2. btif 侧初始化

为啥触发到 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);
}
  • btif_av_sink 是一个静态变量,也就是说, 一个蓝牙进程中,只能有一个 BtifAvSink

3. btif_enable_service


// 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 函数来 使能的。

  1. btif_enable_service(BTA_A2DP_SOURCE_SERVICE_ID)
  2. btif_enable_service(BTA_A2DP_SINK_SERVICE_ID)
  3. btif_enable_service(BTA_HIDD_SERVICE_ID)
  4. btif_enable_service(BTA_HFP_HS_SERVICE_ID)
  5. btif_enable_service(BTA_HFP_SERVICE_ID)
  6. btif_enable_service(BTA_HID_SERVICE_ID)
  7. 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 函数主要做如下几件事情:

  1. 调用 btif_in_execute_service_request 开开启底层蓝牙服务
  2. 服务开启成功后, 会调用 invoke_adapter_properties_cb 通知给 java 层。 当前 xxx 服务已经启动。此时 app 层才能发起 对应的连接。例如 此时用户才能去连接 手机的a2dp.

最终 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++;
        }
}

4. btif_in_execute_service_request

我们接着去分析 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;
}

1. BTA_AvEnable

// 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};

2. bta_av_hdl_event

// 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)。它根据事件的类型,将事件分发给不同的处理逻辑(函数)来处理 —— 本质上是 “职责分离 + 状态感知” 的策略。

1. 为什么同一个模块里会有“多个状态机处理函数”?

事件类型范围 处理函数 对应状态机/作用
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 连接的媒体流生命周期

2. 为什么要分这么细?

清晰职责分离

类型 管理内容 状态
Non-State-Machine 模块初始化、功能开关 无状态
State-Machine 控制模块行为 注册、发现、连接
Sub-State-Machine 每路媒体流 打开、播放、暂停
  1. 支持多设备连接

    • 比如同时连接两个 A2DP Source,每路 stream 都有自己的状态,不能混用一个状态机。
  2. 提高可维护性 & 扩展性

    • 模块功能多(如 A2DP Sink、Source、AVRCP Control/Target),事件分派机制让代码层次分明,易于拓展。

你可以把这个机制类比为:

  • 非状态事件:像家电开关按钮,按了就执行动作,不关心状态(比如插座上电)
  • 主状态机事件:像遥控器控制电视的主机:开机、切源、音量设置,主机来执行
  • 子状态机事件:像电视里每个“应用”(比如 YouTube、Netflix)内部自己管理“播放-暂停-退出”
问题 解答
为何用不同处理函数? 事件来源不同,作用域不同:有全局控制的,有媒体流专属的
如何区分处理? 通过 event 范围判断,派发到对应函数
好处? 解耦清晰、可支持多媒体流、模块化强

5. RegisterAllBtaHandles

我们继续分析一下 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);
}

6. BTA_AV_API_REGISTER_EVT 事件处理

  • BTA_AV_API_REGISTER_EVT 命令是一个 非状态机事件 ,所以在 bta_av_hdl_event 中直接就调用 bta_av_non_state_machine_event 处理了。
// 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(&reg, 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;
}

7. AVDT_Register


// 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)
}
  • 通过 L2CA_Register2 向 l2cap 注册 avdtp 相关的 l2cap 的回调。

1. 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};

回调函数名 触发时机说明 所在连接阶段 主要用途/作用描述
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 等) - -

8. 小结

看到这里, 我们已经 找到了 avdtp 关于 l2cap 层的回调了。 之后会有专门的篇幅来分析 车机主动连 a2dp, 被动连a2dp. 到时候, 就不用再梳理这块了。 本篇相当于是, 梳理一下整体思路。 方便之后的篇幅里面直接查找函数。

  1. 例如如果看到 bta_sys_sendmsg(p_buf):

    • 我们会第一时间去找 bta_av_hdl_event
  2. 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};

  1. 在 avdt_ccb_ll_opened 函数中会调用 p_conn_cback, 从而触发 bta_ar_avdt_cback 的调用 -> p_av_conn_cback(实际调用的是 bta_av_conn_cback)
    1. avdt_ccb_ll_opened ->p_conn_cback[bta_ar_avdt_cback]
    2. bta_ar_avdt_cback->p_av_conn_cback[bta_av_conn_cback]

你可能感兴趣的:(android,15,蓝牙协议栈分析,android,bluetooth,bt,avdtp,a2dp,l2cap,aosp13)