Android13 BluetoothA2dp connect流程分析

BluetoothA2dp的connect用于连接蓝牙耳机,代码如下:

//packages/modules/Bluetooth/framework/java/android/bluetooth/BluetoothA2dp.java
public final class BluetoothA2dp implements BluetoothProfile {
    public boolean connect(BluetoothDevice device) {
        if (DBG) log("connect(" + device + ")");
        final IBluetoothA2dp service = getService();
        final boolean defaultValue = false;
        if (service == null) {
            Log.w(TAG, "Proxy not attached to service");
            if (DBG) log(Log.getStackTraceString(new Throwable()));
        } else if (isEnabled() && isValidDevice(device)) {
            try {
                final SynchronousResultReceiver<Boolean> recv = SynchronousResultReceiver.get();
                service.connectWithAttribution(device, mAttributionSource, recv);
                return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
            } catch (RemoteException | TimeoutException e) {
                Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
            }
        }
        return defaultValue;
    }
}

A2dpService connectWithAttribution

调用IBluetoothA2dp的connectWithAttribution方法,IBluetoothA2dp是一个接口,由A2dpService的内部类BluetoothA2dpBinder 实现:

//packages/modules/Bluetooth/abdriid/app/src/com/android/bluetooth/a2dp/A2dpService.java
public class A2dpService extends ProfileService {
    static class BluetoothA2dpBinder extends IBluetoothA2dp.Stub
            implements IProfileServiceBinder {
        public void connectWithAttribution(BluetoothDevice device, AttributionSource source,
                SynchronousResultReceiver receiver) {
            try {
                A2dpService service = getService(source);
                boolean result = false;
                if (service != null) {
                    result = service.connect(device);
                }
                receiver.send(result);
            } catch (RuntimeException e) {
                receiver.propagateException(e);
            }
        }
    }
}

调用A2dpService的connect方法:

//packages/modules/Bluetooth/abdriid/app/src/com/android/bluetooth/a2dp/A2dpService.java
public class A2dpService extends ProfileService {
    public boolean connect(BluetoothDevice device) {
        if (DBG) {
            Log.d(TAG, "connect(): " + device);
        }


        if (getConnectionPolicy(device) == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN) {
            Log.e(TAG, "Cannot connect to " + device + " : CONNECTION_POLICY_FORBIDDEN");
            return false;
        }
        if (!Utils.arrayContains(mAdapterService.getRemoteUuids(device),
                                         BluetoothUuid.A2DP_SINK)) {
            Log.e(TAG, "Cannot connect to " + device + " : Remote does not have A2DP Sink UUID");
            return false;
        }


        synchronized (mStateMachines) {
            if (!connectionAllowedCheckMaxDevices(device)) {
                // when mMaxConnectedAudioDevices is one, disconnect current device first.
                if (mMaxConnectedAudioDevices == 1) {
                    List<BluetoothDevice> sinks = getDevicesMatchingConnectionStates(
                            new int[] {BluetoothProfile.STATE_CONNECTED,
                                    BluetoothProfile.STATE_CONNECTING,
                                    BluetoothProfile.STATE_DISCONNECTING});
                    for (BluetoothDevice sink : sinks) {
                        if (sink.equals(device)) {
                            Log.w(TAG, "Connecting to device " + device + " : disconnect skipped");
                            continue;
                        }
                        disconnect(sink);
                    }
                } else {
                    Log.e(TAG, "Cannot connect to " + device + " : too many connected devices");
                    return false;
                }
            }
            A2dpStateMachine smConnect = getOrCreateStateMachine(device); //取得或创建状态机
            if (smConnect == null) {
                Log.e(TAG, "Cannot connect to " + device + " : no state machine");
                return false;
            }
            smConnect.sendMessage(A2dpStateMachine.CONNECT); //向状态机发送CONNECT命令
            return true;
        }
    }
}

向状态机发送CONNECT命令,在A2dpStateMachine的状态类Disconnected的processMessage方法中处理:

//packages/modules/Bluetooth/abdriid/app/src/com/android/bluetooth/a2dp/A2dpStateMachine.java
final class A2dpStateMachine extends StateMachine {
    class Disconnected extends State {
         public boolean processMessage(Message message) {
            switch (message.what) {
                case CONNECT:
                    if (DBG) Log.d(TAG, "Connect");
                    transitionTo(mConnecting); //迁移到Connecting状态
                    return true;
            }
            return false;
        }
   }
}

迁移到Connecting状态,会调用Connecting状态类的enter方法:

//packages/modules/Bluetooth/abdriid/app/src/com/android/bluetooth/a2dp/A2dpStateMachine.java
final class A2dpStateMachine extends StateMachine {
    protected final A2dpSinkNativeInterface mNativeInterface;
    class Connecting extends State {
        public void enter() {
            if (DBG) Log.d(TAG, "Enter Connecting");
            onConnectionStateChanged(BluetoothProfile.STATE_CONNECTING); 调用onConnectionStateChanged方法,发送A2DP连接中广播
            sendMessageDelayed(CONNECT_TIMEOUT, CONNECT_TIMEOUT_MS); //启动超时定时器


            if (!mIncomingConnection) {
                mNativeInterface.connectA2dpSink(mDevice); //调用A2dpSinkNativeInterface的connectA2dpSink方法
            }


            super.enter();
        }
   }
}

A2dpSinkNativeInterface connectA2dpSink

调用A2dpSinkNativeInterface的connectA2dpSink方法:

//packages/modules/Bluetooth/abdriid/app/src/com/android/bluetooth/a2dpsink/A2dpSinkNativeInterface.java
public class A2dpSinkNativeInterface {
    public boolean connectA2dpSink(BluetoothDevice device) {
        return connectA2dpNative(getByteAddress(device));
    }
}

调用connectA2dpNative方法,connectA2dpNative是一个Native方法,实现代码如下:

//packages/modules/Bluetooth/android/app/jni/com_android_bluetooth_a2dp.cpp
static const btav_source_interface_t* sBluetoothA2dpInterface = nullptr;
static jboolean connectA2dpNative(JNIEnv* env, jobject object,
                                  jbyteArray address) {
  ALOGI("%s: sBluetoothA2dpInterface: %p", __func__, sBluetoothA2dpInterface);
  std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
  if (!sBluetoothA2dpInterface) {
    ALOGE("%s: Failed to get the Bluetooth A2DP Interface", __func__);
    return JNI_FALSE;
  }


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


  RawAddress bd_addr;
  bd_addr.FromOctets(reinterpret_cast<const uint8_t*>(addr));
  bt_status_t status = sBluetoothA2dpInterface->connect(bd_addr);
  if (status != BT_STATUS_SUCCESS) {
    ALOGE("%s: Failed A2DP connection, status: %d", __func__, status);
  }
  env->ReleaseByteArrayElements(address, addr, 0);
  return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}

调用btav_source_interface_t的connect方法,btav_source_interface_t是一个结构体,在bt_av.h中定义,a2dp_source.cc中实现:

//packages/modules/Bluetooth/system/service/a2dp_source.cc
bool A2dpSource::Connect(const std::string& device_address) {
  RawAddress addr = PARSE_ADDR(device_address);
  LockGuard lock(mutex_);
  TRY_RET_FUNC(
      hal::BluetoothAvInterface::Get()->GetA2dpSourceHALInterface()->connect(
          addr) == BT_STATUS_SUCCESS);
}

在之后就是蓝牙协议栈相关内容,在这里就不再分析了。

A2dpNativeInterface onConnectionStateChanged

当蓝牙协议栈(BT Stack)处理完相关请求后,会调用A2dpNativeInterface的onConnectionStateChanged方法:

//packages/modules/Bluetooth/abdriid/app/src/com/android/bluetooth/a2dp/A2dpSinkNativeInterface.java
public class A2dpNativeInterface {
    private void onConnectionStateChanged(byte[] address, int state) {
        A2dpStackEvent event =
                new A2dpStackEvent(A2dpStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
        event.device = getDevice(address);
        event.valueInt = state;


        if (DBG) {
            Log.d(TAG, "onConnectionStateChanged: " + event);
        }
        sendMessageToService(event);
    }
}

发送EVENT_TYPE_CONNECTION_STATE_CHANGED消息,发送的消息在A2dpService 的messageFromNative方法中处理:

//packages/modules/Bluetooth/abdriid/app/src/com/android/bluetooth/a2dp/A2dpService.java
public class A2dpService extends ProfileService {
    void messageFromNative(A2dpStackEvent stackEvent) {
        Objects.requireNonNull(stackEvent.device,
                               "Device should never be null, event: " + stackEvent);
        synchronized (mStateMachines) {
            BluetoothDevice device = stackEvent.device;
            A2dpStateMachine sm = mStateMachines.get(device);
            if (sm == null) {
                if (stackEvent.type == A2dpStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED) {
                    switch (stackEvent.valueInt) {
                        case A2dpStackEvent.CONNECTION_STATE_CONNECTED:
                        case A2dpStackEvent.CONNECTION_STATE_CONNECTING:
                            // Create a new state machine only when connecting to a device
                            if (!connectionAllowedCheckMaxDevices(device)) {
                                Log.e(TAG, "Cannot connect to " + device
                                        + " : too many connected devices");
                                return;
                            }
                            sm = getOrCreateStateMachine(device);
                            break;
                        default:
                            break;
                    }
                }
            }
            if (sm == null) {
                Log.e(TAG, "Cannot process stack event: no state machine: " + stackEvent);
                return;
            }
            sm.sendMessage(A2dpStateMachine.STACK_EVENT, stackEvent);
        }
    }
}

发送STACK_EVENT消息,发送的消息在A2dpStateMachine 的内部状态类Connecting的processMessage中处理:

//packages/modules/Bluetooth/abdriid/app/src/com/android/bluetooth/a2dp/A2dpStateMachine .java
final class A2dpStateMachine extends StateMachine {
    class Connecting extends State {
        public boolean processMessage(Message message) {
            log("Connecting process message(" + mDevice + "): "
                    + messageWhatToString(message.what));


            switch (message.what) {
                case STACK_EVENT:
                    A2dpStackEvent event = (A2dpStackEvent) message.obj;
                    log("Connecting: stack event: " + event);
                    if (!mDevice.equals(event.device)) {
                        Log.wtf(TAG, "Device(" + mDevice + "): event mismatch: " + event);
                    }
                    switch (event.type) {
                        case A2dpStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED:
                            processConnectionEvent(event.valueInt);
                            break;
                        default:
                            Log.e(TAG, "Connecting: ignoring stack event: " + event);
                            break;
                    }
                    break;
                default:
                    return NOT_HANDLED;
            }
            return HANDLED;
        }
    }
}

调用processConnectionEvent方法:

//packages/modules/Bluetooth/abdriid/app/src/com/android/bluetooth/a2dp/A2dpStateMachine .java
final class A2dpStateMachine extends StateMachine {
    class Connecting extends State {
        private void processConnectionEvent(int event) {
            switch (event) {
                case A2dpStackEvent.CONNECTION_STATE_DISCONNECTED:
                    Log.w(TAG, "Connecting device disconnected: " + mDevice);
                    transitionTo(mDisconnected);
                    break;
                case A2dpStackEvent.CONNECTION_STATE_CONNECTED:
                    transitionTo(mConnected); //迁移到Connected状态
                    break;
                case A2dpStackEvent.CONNECTION_STATE_CONNECTING:
                    // Ignored - probably an event that the outgoing connection was initiated
                    break;
                case A2dpStackEvent.CONNECTION_STATE_DISCONNECTING:
                    Log.w(TAG, "Connecting interrupted: device is disconnecting: " + mDevice);
                    transitionTo(mDisconnecting);
                    break;
                default:
                    Log.e(TAG, "Incorrect event: " + event);
                    break;
            }
        }
    }
}

迁移到Connected状态,会调用Connected 的enter方法:

//packages/modules/Bluetooth/abdriid/app/src/com/android/bluetooth/a2dp/A2dpStateMachine .java
final class A2dpStateMachine extends StateMachine {
    class Connected extends State {
        public void enter() {
            Message currentMessage = getCurrentMessage();
            Log.i(TAG, "Enter Connected(" + mDevice + "): " + (currentMessage == null ? "null"
                    : messageWhatToString(currentMessage.what)));
            mConnectionState = BluetoothProfile.STATE_CONNECTED;


            removeDeferredMessages(CONNECT);


    //每次设备连接时,我们都要重新检查它是否支持可选的编解码器(也许它有固件更新等),如果它与我们之前保存的状态不同,请保存该状态。
            // Each time a device connects, we want to re-check if it supports optional
            // codecs (perhaps it's had a firmware update, etc.) and save that state if
            // it differs from what we had saved before.
            mA2dpService.updateOptionalCodecsSupport(mDevice); //更新并启动可选的编解码器状态更改为本机。
            broadcastConnectionState(mConnectionState, mLastConnectionState); //发送Connection状态变更广播
            // Upon connected, the audio starts out as stopped
            broadcastAudioState(BluetoothA2dp.STATE_NOT_PLAYING,
                                BluetoothA2dp.STATE_PLAYING); //发送Audio状态变化广播
        }
    }
}

A2dpService updateOptionalCodecsSupport

调用A2dpService的updateOptionalCodecsSupport方法:

//packages/modules/Bluetooth/abdriid/app/src/com/android/bluetooth/a2dp/A2dpService.java
public class A2dpService extends ProfileService {
    public void updateOptionalCodecsSupport(BluetoothDevice device) {
        int previousSupport = getSupportsOptionalCodecs(device);
        boolean supportsOptional = false;
        boolean hasMandatoryCodec = false;


        synchronized (mStateMachines) {
            A2dpStateMachine sm = mStateMachines.get(device);
            if (sm == null) {
                return;
            }
            BluetoothCodecStatus codecStatus = sm.getCodecStatus(); //获取BluetoothCodecStatus 状态
            if (codecStatus != null) {
                for (BluetoothCodecConfig config : codecStatus.getCodecsSelectableCapabilities()) {
                    if (config.isMandatoryCodec()) {
                        hasMandatoryCodec = true;
                    } else {
                        supportsOptional = true;
                    }
                }
            }
        }
        if (!hasMandatoryCodec) {
            // Mandatory codec(SBC) is not selectable. It could be caused by the remote device
            // select codec before native finish get codec capabilities. Stop use this codec
            // status as the reference to support/enable optional codecs.
            Log.i(TAG, "updateOptionalCodecsSupport: Mandatory codec is not selectable.");
            return;
        }


        if (previousSupport == BluetoothA2dp.OPTIONAL_CODECS_SUPPORT_UNKNOWN
                || supportsOptional != (previousSupport
                                    == BluetoothA2dp.OPTIONAL_CODECS_SUPPORTED)) {
            setSupportsOptionalCodecs(device, supportsOptional);
        }
        if (supportsOptional) {
            int enabled = getOptionalCodecsEnabled(device);
            switch (enabled) {
                case BluetoothA2dp.OPTIONAL_CODECS_PREF_UNKNOWN:
                    // Enable optional codec by default.
                    setOptionalCodecsEnabled(device, BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED);
                    // Fall through intended
                case BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED:
                    enableOptionalCodecs(device);
                    break;
                case BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED:
                    disableOptionalCodecs(device);
                    break;
            }
        }
    }
}

这部分为可选解码器相关,我们可以先不关注,到这里BluetoothA2dp的disconnet流程就分析完了。

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
蓝牙A2DP(Advanced Audio Distribution Profile)是一项用于通过蓝牙传输音频数据的标准协议。它允许音频设备(例如手机、音箱、耳机)直接进行无线音频数据传输。 在Android系统中,可以通过BluetoothA2dp类来连接和管理A2DP音频设备。其连接过程可分为以下几个步骤: 1. 扫描设备:首先,需要在Android系统中开启蓝牙功能,并调用BluetoothAdapter类中的startDiscovery()方法扫描周围的蓝牙设备。 2. 配对设备:在扫描到需要连接的A2DP设备之后,需要进行配对操作。配对可以在Android系统中的蓝牙设置中手动进行,也可以使用BluetoothDevice类的createBond()方法进行自动配对。 3. 连接设备:进行配对后,需要使用BluetoothA2dp类的connect()方法来连接设备。在连接成功后,会回调BluetoothA2dp中的onServiceConnected()方法,表示已经与A2DP设备建立起了连接。 4. 播放音频:连接成功后,可以使用BluetoothA2dp类的getDevicesMatchingConnectionStates()方法获取已连接的A2DP设备,就可以进行音频数据的传输和播放了。 需要注意的是,以上流程是基于源设备(例如手机)与目标设备(例如音箱)之间的连接流程。对于目标设备作为音频源的情景,连接过程会有所不同。 总之,蓝牙A2DP协议通过一系列的连接和数据传输操作,让我们可以实现无线音频的传输和播放。在Android系统中,只需要调用相应的API方法就可以轻松地实现与A2DP设备的连接和操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值