Android13 BluetoothAvrcp disconnect流程

BluetoothAvrcpController,没有提供协议连接断开的接口,A2DP断开成功后,BT协议栈(BT Stack)会主动发起AVRCP的断开,具体可以查看android部分源码。

蓝牙协议栈(BT Stack)相关我们不再这里分析,我们从JNI开始分析:

//packages/modules/Bluetooth/android/app/jni/com_android_bluetooth_avrcp_controller.cpp
static void btavrcp_connection_state_callback(bool rc_connect, bool br_connect,
                                              const RawAddress& bd_addr) {
  ALOGI("%s: conn state: rc: %d br: %d", __func__, rc_connect, br_connect);
  std::shared_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;
  if (!sCallbacksObj) {
    ALOGE("%s: sCallbacksObj is null", __func__);
    return;
  }


  ScopedLocalRef<jbyteArray> addr(
      sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
  if (!addr.get()) {
    ALOGE("%s: Failed to allocate a new byte array", __func__);
    return;
  }


  sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                   (jbyte*)bd_addr.address); //设置字节数组区域
  sCallbackEnv->CallVoidMethod(sCallbacksObj, method_onConnectionStateChanged,
                               (jboolean)rc_connect, (jboolean)br_connect,
                               addr.get());  //调用 void 方法
}

通过sCallbackEnv->CallVoidMethod调用method_onConnectionStateChanged方法,通过classInitNative对应的JAVA方法:

//packages/modules/Bluetooth/android/app/jni/com_android_bluetooth_avrcp_controller.cpp
static void classInitNative(JNIEnv* env, jclass clazz) {
  method_onConnectionStateChanged =
      env->GetMethodID(clazz, "onConnectionStateChanged", "(ZZ[B)V");
}

AvrcpControllerService onConnectionStateChanged

调用AvrcpControllerService的onConnectionStateChanged方法:

//packages/modules/Bluetooth/abdriid/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerService.java
public class AvrcpControllerService extends ProfileService {
    // Called by JNI when a device has connected or disconnected.
    private synchronized void onConnectionStateChanged(boolean remoteControlConnected,
            boolean browsingConnected, byte[] address) {
        BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address);
        if (DBG) {
            Log.d(TAG, "onConnectionStateChanged " + remoteControlConnected + " "
                    + browsingConnected + device);
        }
        if (device == null) {
            Log.e(TAG, "onConnectionStateChanged Device is null");
            return;
        }


        StackEvent event =
                StackEvent.connectionStateChanged(remoteControlConnected, browsingConnected);
        AvrcpControllerStateMachine stateMachine = getOrCreateStateMachine(device);
        if (remoteControlConnected || browsingConnected) {
            stateMachine.connect(event);
            // The first device to connect gets to be the active device
            if (getActiveDevice() == null) {
                setActiveDevice(device);
            }
        } else {
            stateMachine.disconnect();
            if (device.equals(getActiveDevice())) {
                setActiveDevice(null);
            }
        }
    }
}

上面方法的处理处理如下:

1、调用AvrcpControllerStateMachine的disconnect方法,进行状态迁移处理

2、调用AvrcpControllerService的setActiveDevice方法,用于设置活动设备

下面分别进行分析:

AvrcpControllerStateMachine disconnect

调用StackEvent的connectionStateChanged方法,创建EVENT_TYPE_CONNECTION_STATE_CHANGED的StackEvent:

//packages/modules/Bluetooth/abdriid/app/src/com/android/bluetooth/avrcpcontroller/StackEvent.java
final class StackEvent {
    static StackEvent connectionStateChanged(boolean remoteControlConnected,
            boolean browsingConnected) {
        StackEvent event = new StackEvent(EVENT_TYPE_CONNECTION_STATE_CHANGED);
        event.mRemoteControlConnected = remoteControlConnected;
        event.mBrowsingConnected = browsingConnected;
        return event;
    }
}

调用AvrcpControllerStateMachine的disconnect方法:

//packages/modules/Bluetooth/abdriid/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java
class AvrcpControllerStateMachine extends StateMachine {
    public void disconnect() {
        sendMessage(DISCONNECT);
    }
}

发送DISCONNECT消息,在AvrcpControllerStateMachine的内部状态类connected的processMessage方法中处理:

//packages/modules/Bluetooth/abdriid/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java
class AvrcpControllerStateMachine extends StateMachine {
    class Connected extends State {
        private static final String STATE_TAG = "Avrcp.ConnectedAvrcpController";
        private int mCurrentlyHeldKey = 0;
        @Override
        public boolean processMessage(Message msg) {
            logD(STATE_TAG + " processMessage " + msg.what);
            switch (msg.what) {
                case DISCONNECT:
                    transitionTo(mDisconnecting); //迁移到Disconnecting状态
                    return true;
            }
        }
    }
}

迁移到Disconnecting状态,会运行Disconnecting的enter方法:

//packages/modules/Bluetooth/abdriid/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java
class AvrcpControllerStateMachine extends StateMachine {
    protected final AvrcpControllerService mService;
    protected class Disconnecting extends State {
        @Override
        public void enter() {
            disconnectCoverArt();
            onBrowsingDisconnected();
            if (mService.sBrowseTree != null) {
                mService.sBrowseTree.mRootNode.removeChild(mBrowseTree.mRootNode); //删除媒体浏览树的所有子节点
                BluetoothMediaBrowserService.notifyChanged(mService.sBrowseTree.mRootNode); //通过
            }
            broadcastConnectionStateChanged(BluetoothProfile.STATE_DISCONNECTING); //发送Avrcp变化为STATE_DISCONNECTING状态的广播
            transitionTo(mDisconnected); //迁移到Disconnected状态
        }
}

上面方法主要处理如下:

调用disconnectCoverArt方法,断开艺术封面的连接

调用onBrowsingDisconnected方法,用于处理Avrcp浏览断开连接

调用BluetoothMediaBrowserService的notifyChanged方法,通知MediaSession播放队列变化

迁移到Disconnected状态

下面分别进行分析:

AvrcpControllerStateMachine disconnectCoverArt

调用AvrcpControllerStateMachine的disconnectCoverArt方法:

//packages/modules/Bluetooth/abdriid/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java
class AvrcpControllerStateMachine extends StateMachine {
    protected final AvrcpCoverArtManager mCoverArtManager;
    synchronized void disconnectCoverArt() {
        // Safe to call even if we're not connected
        if (mCoverArtManager != null) {
            logD("Disconnect BIP cover artwork");
            mCoverArtManager.disconnect(mDevice);
        }
    }
}

调用AvrcpCoverArtManager的disconnect方法:

//packages/modules/Bluetooth/abdriid/app/src/com/android/bluetooth/avrcpcontroller/AvrcpCoverArtManager.java
public class AvrcpCoverArtManager {
    protected final Map<BluetoothDevice, AvrcpBipClient> mClients = new ConcurrentHashMap<>(1);
    private Map<BluetoothDevice, AvrcpBipSession> mBipSessions = new ConcurrentHashMap<>(1);
    private final AvrcpCoverArtStorage mCoverArtStorage;
    public synchronized boolean disconnect(BluetoothDevice device) {
        debug("Disconnect " + device.getAddress());
        AvrcpBipClient client = getClient(device);
        if (client == null) {
            warn("No client for " + device.getAddress());
            return false;
        }
        client.shutdown();
        mClients.remove(device);
        mBipSessions.remove(device);
        mCoverArtStorage.removeImagesForDevice(device);
        return true;
    }
}

调用AvrcpCoverArtStorage的removeImagesForDevice方法:

//packages/modules/Bluetooth/abdriid/app/src/com/android/bluetooth/avrcpcontroller/AvrcpCoverArtStorage.java
public class AvrcpCoverArtStorage {
    private final Map<BluetoothDevice, Map<String, Bitmap>> mDeviceImages =
            new ConcurrentHashMap<>(1);
    public void removeImagesForDevice(BluetoothDevice device) {
        if (device == null) return;
        debug("Remove cover art for device " + device.getAddress());
        mDeviceImages.remove(device);
    }
}

AvrcpControllerStateMachine onBrowsingDisconnected

调用AvrcpControllerStateMachine的onBrowsingDisconnected方法:

//packages/modules/Bluetooth/abdriid/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java
class AvrcpControllerStateMachine extends StateMachine {
    private AvrcpPlayer mAddressedPlayer;
    final BrowseTree mBrowseTree;
    synchronized void onBrowsingDisconnected() {
        if (!mBrowsingConnected) return;
        mAddressedPlayer.setPlayStatus(PlaybackStateCompat.STATE_ERROR);
        AvrcpItem previousTrack = mAddressedPlayer.getCurrentTrack();
        String previousTrackUuid = previousTrack != null ? previousTrack.getCoverArtUuid() : null;
        mAddressedPlayer.updateCurrentTrack(null);
        mBrowseTree.mNowPlayingNode.setCached(false);
        mBrowseTree.mRootNode.setCached(false);
        if (isActive()) {
            BluetoothMediaBrowserService.notifyChanged(mBrowseTree.mNowPlayingNode);
            BluetoothMediaBrowserService.notifyChanged(mBrowseTree.mRootNode);
        }
        removeUnusedArtwork(previousTrackUuid);
        removeUnusedArtworkFromBrowseTree();
        mBrowsingConnected = false;
    }
}

BluetoothMediaBrowserService notifyChanged

调用BluetoothMediaBrowserService的notifyChanged方法:

//packages/modules/Bluetooth/abdriid/app/src/com/android/bluetooth/avrcpcontroller/BluetoothMediaBrowserService.java
public class BluetoothMediaBrowserService extends MediaBrowserServiceCompat {
    private static BluetoothMediaBrowserService sBluetoothMediaBrowserService;
    static synchronized void notifyChanged(BrowseTree.BrowseNode node) {
        if (sBluetoothMediaBrowserService != null) {
            if (node.getScope() == AvrcpControllerService.BROWSE_SCOPE_NOW_PLAYING) {
                sBluetoothMediaBrowserService.updateNowPlayingQueue(node); //更新当前播放队列
            } else {
                sBluetoothMediaBrowserService.notifyChildrenChanged(node.getID()); //
            }
        }
    }
}

调用BluetoothMediaBrowserService的updateNowPlayingQueue方法:

//packages/modules/Bluetooth/abdriid/app/src/com/android/bluetooth/avrcpcontroller/BluetoothMediaBrowserService.java
public class BluetoothMediaBrowserService extends MediaBrowserServiceCompat {
    private MediaSessionCompat mSession;
    private List<MediaSessionCompat.QueueItem> mMediaQueue = new ArrayList<>();
    private void updateNowPlayingQueue(BrowseTree.BrowseNode node) {
        List<MediaItem> songList = node.getContents();
        mMediaQueue.clear();
        if (songList != null && songList.size() > 0) {
            for (MediaItem song : songList) {
                mMediaQueue.add(new MediaSessionCompat.QueueItem(
                        song.getDescription(),
                        mMediaQueue.size()));
            }
            mSession.setQueue(mMediaQueue);
        } else {
            mSession.setQueue(null);
        }
    }
}

调用MediaSession的setQueue方法, 设置播放队列,这部分属于Media相关内容:

待更新

AvrcpControllerService setActiveDevice

调用AvrcpControllerService setActiveDevice方法:

//packages/modules/Bluetooth/abdriid/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerService.java
public class AvrcpControllerService extends ProfileService {
    private boolean setActiveDevice(BluetoothDevice device) {
        A2dpSinkService a2dpSinkService = A2dpSinkService.getA2dpSinkService();
        if (a2dpSinkService == null) {
            return false;
        }


        BluetoothDevice currentActiveDevice = getActiveDevice();
        if ((device == null && currentActiveDevice == null)  //由于是disconnect,传入的device 为null,因此直接返回true
                || (device != null && device.equals(currentActiveDevice))) {
            return true;
        }


        // Try and update the active device
        synchronized (mActiveDeviceLock) {
            if (a2dpSinkService.setActiveDevice(device)) { 
                mActiveDevice = device;


                // Pause the old active device
                if (currentActiveDevice != null) {
                    AvrcpControllerStateMachine oldStateMachine =
                            getStateMachine(currentActiveDevice); 
                    if (oldStateMachine != null) {
                        oldStateMachine.setDeviceState(DEVICE_STATE_INACTIVE); 
                    }
                }


                AvrcpControllerStateMachine stateMachine = getStateMachine(device); 
                if (stateMachine != null) {
                    stateMachine.setDeviceState(DEVICE_STATE_ACTIVE);
                } else {
                    BluetoothMediaBrowserService.reset();
                }
                return true;
            }
        }
        return false;
    }
}

到这里BluetoothAvrcp disconnect流程就介绍完了。

Android中的AVRCP(Audio/Video Remote Control Profile)是一种用于远程控制音频和视频设备的蓝牙配置文件。它允许Android设备通过蓝牙连接到其他支持AVRCP的设备,并控制其播放、暂停、下一曲、上一曲等操作。 要在Android应用程序中开发AVRCP功能,你可以按照以下步骤进行: 1. 添加蓝牙权限:在AndroidManifest.xml文件中,添加以下权限: ```xml <uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/> ``` 2. 设置蓝牙适配器:在你的Activity或Service中,获取蓝牙适配器并启用蓝牙功能。 ```java BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (bluetoothAdapter == null) { // 设备不支持蓝牙 return; } if (!bluetoothAdapter.isEnabled()) { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); } ``` 3. 监听蓝牙连接状态:注册一个BroadcastReceiver来监听蓝牙连接状态的改变。 ```java private final BroadcastReceiver btReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) { int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR); if (state == BluetoothAdapter.STATE_CONNECTED) { // 设备已连接 } else if (state == BluetoothAdapter.STATE_DISCONNECTED) { // 设备已断开连接 } } } }; IntentFilter btIntentFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED); registerReceiver(btReceiver, btIntentFilter); ``` 4. 实现AVRCP功能:使用BluetoothA2dp和BluetoothAvrcp类来实现AVRCP功能。以下是一些常见的AVRCP操作示例: - 播放/暂停操作: ```java BluetoothAvrcpController avrcpController = new BluetoothAvrcpController(); avrcpController.play(); avrcpController.pause(); ``` - 下一曲/上一曲操作: ```java BluetoothAvrcpController avrcpController = new BluetoothAvrcpController(); avrcpController.skipToNext(); avrcpController.skipToPrevious(); ``` 请注意,这只是一个简单的示例,实际开发中可能需要处理更多的错误和异常情况。 希望这些信息可以帮助你开始在Android应用程序中开发AVRCP功能。如果你有其他问题,请随时提问!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值