蓝牙(三)a2dp连接

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/pashanhu6402/article/details/79930133

以下内容都是基于android6.0的基础上讲的,相对于android4.4架构有了很大改动。

先借用一下图用一下。

这里写图片描述 
上图描述的是蓝牙协议栈,通过该图,查看A2dp的代码在协议栈的调用流程。其分层架构如下: 
这里写图片描述 
1.蓝牙的系统服务service通过JNI与bluedroid协议栈进行通信。协议栈分为两层,Bluetooth Embedded System(BTE)和Bluetooth Application Layer(BTA)。这两层和framework层应用进行通信。 
2.蓝牙服务通过Binder IPC通信与应用程序交互。 
3.系统服务给开发者提供了获取各种profile的接口。

一、接下来将深入Framework层讲解蓝牙的连接

    1)那就从connectInt()开始

synchronized void connectInt(LocalBluetoothProfile profile) {
        if (!ensurePaired()) {
            return;
        }
        if (profile.connect(mDevice)) {
            if (Utils.D) {
                Log.d(TAG, "Command sent successfully:CONNECT " + describe(profile));
            }
            return;
        }
        Log.i(TAG, "Failed to connect " + profile.toString() + " to " + mName);
    }

2)若profile为a2dpprofile,则A2dpProfile.connect()

public boolean connect(BluetoothDevice device) {
        if (mService == null) return false;
        List<BluetoothDevice> sinks = getConnectedDevices();
        if (sinks != null) {
            for (BluetoothDevice sink : sinks) {
                mService.disconnect(sink);
            }
        }
        return mService.connect(device);
    }

上面的代码就很好理解了,查询已连接的设备,然后断开。只有先把蓝牙节点给释放掉才能供给其它使用。

3)BluetoothA2dp.connect()

public boolean connect(BluetoothDevice device) {
        if (DBG) log("connect(" + device + ")");
        if (mService != null && isEnabled() &&
            isValidDevice(device)) {
            try {
                return mService.connect(device);
            } catch (RemoteException e) {
                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
                return false;
            }
        }
        if (mService == null) Log.w(TAG, "Proxy not attached to service");
        return false;
    }

BluetoothA2dp类是干什么的呢?它是蓝牙a2dp服务的代理对象,就是上层想要使用就必须用到它了。获取BluetoothA2dp的方法就是BluetoothAdapter.getProfileProxy()

4.A2dpService.connect()

mStateMachine.sendMessage(A2dpStateMachine.CONNECT, device);

发送一个蓝牙连接的消息给A2dpStateMachine进行连接操作。a2dp连接之前肯定处于disconnect状态,所以进行连接时要一步一个脚印。大家注意下面一段代码是mDisconnected里的。

switch(message.what) {
                case CONNECT:
                    BluetoothDevice device = (BluetoothDevice) message.obj;
                    broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTING,
                                   BluetoothProfile.STATE_DISCONNECTED);----(1)

                    if (!connectA2dpNative(getByteAddress(device)) ) {-----(2)
                        broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED,
                                       BluetoothProfile.STATE_CONNECTING);
                        break;
                    }

                    synchronized (A2dpStateMachine.this) {
                        mTargetDevice = device;
                        transitionTo(mPending);---------(3)
                    }
                    // TODO(BT) remove CONNECT_TIMEOUT when the stack
                    //          sends back events consistently
                    sendMessageDelayed(CONNECT_TIMEOUT, 30000);
                    break;

        上面的(1)处是发送一个连接蓝牙状态改变事件。

                         (2)进行a2dp连接,很明显就要进入jni里了

                           (3)状态转换到==》pending==>connected

JNI

5.这里只讲连接,所以下面要分析jni了

static jboolean connectA2dpNative(JNIEnv *env, jobject object, jbyteArray address) {
    jbyte *addr;
    bt_bdaddr_t * btAddr;
    bt_status_t status;

    ALOGI("%s: sBluetoothA2dpInterface: %p", __FUNCTION__, sBluetoothA2dpInterface);
    if (!sBluetoothA2dpInterface) return JNI_FALSE;

    addr = env->GetByteArrayElements(address, NULL);
    btAddr = (bt_bdaddr_t *) addr;
    if (!addr) {
        jniThrowIOException(env, EINVAL);
        return JNI_FALSE;
    }

    if ((status = sBluetoothA2dpInterface->connect((bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
        ALOGE("Failed HF connection, status: %d", status);
    }
    env->ReleaseByteArrayElements(address, addr, 0);
    return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}

那么这个sBluetoothA2dpInterface这个是什么呢?其实这个就相当于java中对外提供的api接口,只是在c中是头文件而已。

既然是蓝牙肯定是在蓝牙的头文件里bt_av.h里

typedef struct {

    /** set to sizeof(btav_interface_t) */
    size_t          size;
    /**
     * Register the BtAv callbacks
     */
    bt_status_t (*init)( btav_callbacks_t* callbacks );

    /** connect to headset */
    bt_status_t (*connect)( bt_bdaddr_t *bd_addr );

    /** dis-connect from headset */
    bt_status_t (*disconnect)( bt_bdaddr_t *bd_addr );

    /** Closes the interface. */
    void  (*cleanup)( void );
} btav_interface_t;

接下来就调用到./btif/src/btif_av.c

static const btav_interface_t bt_av_src_interface = {
    sizeof(btav_interface_t),
    init_src,
    src_connect_sink,
    disconnect,
    cleanup_src,
};

static const btav_interface_t bt_av_sink_interface = {
    sizeof(btav_interface_t),
    init_sink,
    sink_connect_src,
    disconnect,
    cleanup_sink,
};

至于a2dp的断开,流程和连接类似,请大家自行分析。

上面有两个connect到底使用哪一个呢?那就要看你的机器是发送连接还是接收连接了。就到这了,接下来的东西其实我没搞太明白,就不误导大家了。

如果感觉不错,就赞一下。微笑





猜你喜欢

转载自blog.csdn.net/pashanhu6402/article/details/79930133
今日推荐