A2dp sink 初始化流程源码分析

本文详细分析了Android O系统中A2dp Sink的初始化流程,从service启动开始,逐步深入到C++层的实现,包括sink状态机启动、initNative函数的调用,以及蓝牙接口和状态机的初始化。整个流程涉及到btif_a2dp_sink_startup、btif_sm_init、BTA_AvEnable和BTA_AvRegister等关键步骤,展示了A2dp Sink与A2dp Source的不同之处。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A2dp sink的初始化流程和A2dp 的初始化流程,基本一样,这里做简单分析.这里分析的android的版本是Android O.

我们先从service的启动说起吧.

下面 是启动的时候的log:

D/BluetoothAdapterService( 2029): setProfileServiceState() - Starting service com.android.bluetooth.a2dpsink.A2dpSinkService
01-01 08:00:22.042 D/A2dpSinkService( 2029): Received start request. Starting profile...
01-01 08:00:22.045 D/A2dpSinkService( 2029): start()
01-01 08:00:22.054 I/BluetoothA2dpSinkServiceJni( 2029): classInitNative: succeeds

我们看看 A2dpSinkService.java的start函数的实现:

    protected boolean start() {
        if (DBG) {
            Log.d(TAG, "start()");
        }
        // Start the media browser service.
        Intent startIntent = new Intent(this, A2dpMediaBrowserService.class);
        startService(startIntent);//启动service
        mStateMachine = A2dpSinkStateMachine.make(this, this);//启动状态机
        setA2dpSinkService(this);//设置sA2dpSinkService = this
        return true;
    }

 

这里比较重要的地方就是 sink 状态机的启动,我们进一步看看:

    static A2dpSinkStateMachine make(A2dpSinkService svc, Context context) {
        Log.d("A2dpSinkStateMachine", "make");
        A2dpSinkStateMachine a2dpSm = new A2dpSinkStateMachine(svc, context);//新建状态机
        a2dpSm.start();
        return a2dpSm;
    }

 我们看看这个类的构造函数实现:

    static {
        classInitNative();
    }
    private A2dpSinkStateMachine(A2dpSinkService svc, Context context) {
        super("A2dpSinkStateMachine");
        mService = svc;
        mContext = context;
        mAdapter = BluetoothAdapter.getDefaultAdapter();

        initNative();//初始化

        mDisconnected = new Disconnected();
        mPending = new Pending();
        mConnected = new Connected();

        addState(mDisconnected);
        addState(mPending);
        addState(mConnected);

        setInitialState(mDisconnected);

        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);

        mIntentBroadcastHandler = new IntentBroadcastHandler();
    }

 

上面  主要做了初始化,然后 新建三个状态,然后设置初始状态.这里主要分析一下初始化相关的流程: classInitNative()和initNative()

我们先看前者:

 private native static void classInitNative();

 

这是本地实现的函数,在com_android_bluetooth_a2dp_sink.cpp中:

static void classInitNative(JNIEnv* env, jclass clazz) {
  method_onConnectionStateChanged =
      env->GetMethodID(clazz, "onConnectionStateChanged", "(I[B)V");

  method_onAudioStateChanged =
      env->GetMethodID(clazz, "onAudioStateChanged", "(I[B)V");

  method_onAudioConfigChanged =
      env->GetMethodID(clazz, "onAudioConfigChanged", "([BII)V");

  ALOGI("%s: succeeds", __func__);
}

 

主要就是 从上层 索取了一些函数调用的"句柄",我们继续看initNative:

static void initNative(JNIEnv* env, jobject object) {
  const bt_interface_t* btInf = getBluetoothInterface();
  if (btInf == NULL) {
    ALOGE("Bluetooth module is not loaded");
    return;
  }

  if (sBluetoothA2dpInterface != NULL) {
    ALOGW("Cleaning up A2DP Interface before initializing...");
    sBluetoothA2dpInterface->cleanup();
    sBluetoothA2dpInterface = NULL;
  }

  if (mCallbacksObj != NULL) {
    ALOGW("Cleaning up A2DP callback object");
    env->DeleteGlobalRef(mCallbacksObj);
    mCallbacksObj = NULL;
  }

  sBluetoothA2dpInterface =
      (btav_sink_interface_t*)btInf->get_profile_interface(
          BT_PROFILE_ADVANCED_AUDIO_SINK_ID);
  if (sBluetoothA2dpInterface == NULL) {
    ALOGE("Failed to get Bluetooth A2DP Sink Interface");
    return;
  }

  bt_status_t status = sBluetoothA2dpInterface->init(&sBluetoothA2dpCallbacks);
  if (status != BT_STATUS_SUCCESS) {
    ALOGE("Failed to initialize Bluetooth A2DP Sink, status: %d", status);
    sBluetoothA2dpInterface = NULL;
    return;
  }

  mCallbacksObj = env->NewGlobalRef(object);
}

 

上面的逻辑 就是先获取蓝牙的接口,再获取sink 的接口,然后对sink 接口进行初始化.我们主要看初始化的过程:

实现是在btif_av.cc中:

 

static const btav_sink_interface_t bt_av_sink_interface = {
    sizeof(btav_sink_interface_t),
    init_sink,
    sink_connect_src,
    disconnect,
    cleanup_sink,
    update_audio_focus_state,
    update_audio_track_gain,
}

 

这里的init 对应的接口就是init_sink,我们继续看:

/*******************************************************************************
 *
 * Function         init_sink
 *
 * Description      Initializes the AV interface for sink mode
 *
 * Returns          bt_status_t
 *
 ******************************************************************************/

static bt_status_t init_sink(btav_sink_callbacks_t* callbacks) {
  BTIF_TRACE_EVENT("%s()", __func__);

  bt_status_t status = btif_av_init(BTA_A2DP_SINK_SERVICE_ID);
  if (status == BT_STATUS_SUCCESS) bt_av_sink_callbacks = callbacks;

  return status;
}

 

这里的核心是btif_av_init,这里和之前src的初始化很相似,由于Android版本的演化,这里的btif_av_init 接口已经有了参数,:

/*******************************************************************************
 *
 * Function         btif_av_init
 *
 * Description      Initializes btif AV if not already done
 *
 * Returns          bt_status_t
 *
 ******************************************************************************/

bt_status_t btif_av_init(int service_id) {
  if (btif_av_cb.sm_handle == NULL) {
    alarm_free(av_open_on_rc_timer);
    av_open_on_rc_timer = alarm_new("btif_av.av_open_on_rc_timer");

    switch (service_id) {
      case BTA_A2DP_SOURCE_SERVICE_ID:
        if (!btif_a2dp_source_startup())
          return BT_STATUS_FAIL;  // Already running
        break;
      case BTA_A2DP_SINK_SERVICE_ID:
        if (!btif_a2dp_sink_startup())
          return BT_STATUS_FAIL;  // Already running
        break;
    }

    /* Also initialize the AV state machine */
    btif_av_cb.sm_handle = btif_sm_init(
        (const btif_sm_handler_t*)btif_av_state_handlers, BTIF_AV_STATE_IDLE);//初始化 av 状态机

    btif_enable_service(service_id);//enable 某个service

  }

  return BT_STATUS_SUCCESS;
}

 

从上面的代码结构可以看出,此接口是sink 和src 共享的.

上面的代码的执行任务分为3个部分:

  1. btif—a2dp-sink的线程启动btif_sm_init
  2. btif_sm_init
  3. btif_enable_service(sink)

我们发现根据传入的参数不同,如果是src,那么执行btif_a2dp_source_startup,如果是sink 执行:btif_a2dp_sink_startup,看了下两者的实现也是大致相同,都是先设置相应的状态,然后新建线程,然后绑定线程队列,然后调用thread_post 去执行 剩下的流程:

bool btif_a2dp_sink_startup(void) {
  if (btif_a2dp_sink_state != BTIF_A2DP_SINK_STATE_OFF) {
    APPL_TRACE_ERROR("%s: A2DP Sink media task already running
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值