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个部分:
- btif—a2dp-sink的线程启动btif_sm_init
- btif_sm_init
- 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