必威体育Betway必威体育官网
当前位置:首页 > IT技术

蓝牙(三)a2dp连接

时间:2019-08-14 21:43:22来源:IT技术作者:seo实验室小编阅读:90次「手机版」
 

a2dp

以下内容都是基于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到底使用哪一个呢?那就要看你的机器是发送连接还是接收连接了。就到这了,接下来的东西其实我没搞太明白,就不误导大家了。

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

相关阅读

入耳式/耳塞式/蓝牙耳机的正确佩戴方法介绍

带上耳机听听音乐看看视频已成为现代生活中的之中时尚潮流。不同的耳机有着不同的佩戴方法,若是佩戴不当容易造成听力损伤,接下来的

蓝牙工具IVT Bluesoleil破解流程

工具1、最新版本IVT_BlueSoleil_10.0.492.12、破解软件Bluesoleil 8.XXX Patch Tool链接:http://pan.baidu.com/s/1jGvXPhc 密

Galaxy Buds耳机值不值得买 三星真无线蓝牙耳机Galaxy

Galaxy Buds耳机怎么样?值不值得买?下面小编带来三星真无线蓝牙耳机Galaxy Buds上手体验,希望对大家有所帮助。三星真无线蓝牙耳机Ga

笔记本如何链接蓝牙

具体的步骤流程: 1   控制面板——>网络和Internet——>网络共享中心——>更改适配器——>Bluetooth网络链接右键点击属性——>

蓝牙协议--HFP协议--转

HFP协议目前HFP的使用场景有车载蓝牙,耳机和PDA,定义了AG和HFP两种角色。     AG(Audio Gate)音频网关—音频设备输入输出网关 

分享到:

栏目导航

推荐阅读

热门阅读