Loading android/app/src/com/android/bluetooth/bass_client/BassClientService.java +9 −4 Original line number Diff line number Diff line Loading @@ -1338,12 +1338,17 @@ public class BassClientService extends ProfileService { return false; } boolean isRoomAvailable = false; for (BluetoothLeBroadcastReceiveState recvState : stateMachine.getAllSources()) { List<BluetoothLeBroadcastReceiveState> sources = stateMachine.getAllSources(); if (sources.size() < stateMachine.getMaximumSourceCapacity()) { isRoomAvailable = true; } else { for (BluetoothLeBroadcastReceiveState recvState : sources) { if (isEmptyBluetoothDevice(recvState.getSourceDevice())) { isRoomAvailable = true; break; } } } log("isRoomAvailable: " + isRoomAvailable); return isRoomAvailable; } Loading android/app/src/com/android/bluetooth/bass_client/BassClientStateMachine.java +251 −6 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static android.Manifest.permission.BLUETOOTH_CONNECT; import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; import static com.android.bluetooth.flags.Flags.leaudioBigDependsOnAudioState; import static com.android.bluetooth.flags.Flags.leaudioBroadcastReceiveStateProcessingRefactor; import static com.android.bluetooth.flags.Flags.leaudioBroadcastResyncHelper; import android.annotation.Nullable; Loading Loading @@ -155,6 +156,7 @@ class BassClientStateMachine extends StateMachine { private final Map<Integer, Boolean> mFirstTimeBisDiscoveryMap; private int mPASyncRetryCounter = 0; @VisibleForTesting int mNumOfBroadcastReceiverStates = 0; int mNumOfReadyBroadcastReceiverStates = 0; @VisibleForTesting int mPendingOperation = -1; @VisibleForTesting byte mPendingSourceId = -1; @VisibleForTesting BluetoothLeBroadcastMetadata mPendingMetadata = null; Loading Loading @@ -975,10 +977,15 @@ class BassClientStateMachine extends StateMachine { } private boolean isSourceAbsent(BluetoothLeBroadcastReceiveState recvState) { return recvState.getSourceDevice() == null return recvState == null || recvState.getSourceDevice() == null || recvState.getSourceDevice().getAddress().equals("00:00:00:00:00:00"); } private boolean isSourcePresent(BluetoothLeBroadcastReceiveState recvState) { return !isSourceAbsent(recvState); } private void checkAndUpdateBroadcastCode(BluetoothLeBroadcastReceiveState recvState) { log("checkAndUpdateBroadcastCode"); // Whenever receive state indicated code requested, assistant should set the broadcast code Loading @@ -999,7 +1006,8 @@ class BassClientStateMachine extends StateMachine { } } private BluetoothLeBroadcastReceiveState parseBroadcastReceiverState(byte[] receiverState) { private BluetoothLeBroadcastReceiveState parseBroadcastReceiverStateObsolete( byte[] receiverState) { byte sourceId = 0; if (receiverState.length > 0) { sourceId = receiverState[BassConstants.BCAST_RCVR_STATE_SRC_ID_IDX]; Loading Loading @@ -1140,10 +1148,11 @@ class BassClientStateMachine extends StateMachine { return recvState; } private void processBroadcastReceiverState( private void processBroadcastReceiverStateObsolete( byte[] receiverState, BluetoothGattCharacteristic characteristic) { log("processBroadcastReceiverState: characteristic:" + characteristic); BluetoothLeBroadcastReceiveState recvState = parseBroadcastReceiverState(receiverState); BluetoothLeBroadcastReceiveState recvState = parseBroadcastReceiverStateObsolete(receiverState); if (recvState == null) { log("processBroadcastReceiverState: Null recvState"); return; Loading Loading @@ -1249,6 +1258,226 @@ class BassClientStateMachine extends StateMachine { broadcastReceiverState(recvState, sourceId); } private BluetoothLeBroadcastReceiveState parseBroadcastReceiverState( byte[] receiverState, int previousSourceId) { log("parseBroadcastReceiverState: receiverState length: " + receiverState.length); BluetoothLeBroadcastReceiveState recvState = null; if (receiverState.length == 0) { byte[] emptyBluetoothDeviceAddress = Utils.getBytesFromAddress("00:00:00:00:00:00"); if (previousSourceId != BassConstants.INVALID_SOURCE_ID) { recvState = new BluetoothLeBroadcastReceiveState( previousSourceId, BluetoothDevice.ADDRESS_TYPE_PUBLIC, // sourceAddressType mAdapterService.getDeviceFromByte( emptyBluetoothDeviceAddress), // sourceDev 0, // sourceAdvertisingSid 0, // broadcastId BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE, // paSyncState // bigEncryptionState BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, null, // badCode 0, // numSubgroups Arrays.asList(new Long[0]), // bisSyncState Arrays.asList( new BluetoothLeAudioContentMetadata[0]) // subgroupMetadata ); } else { log("parseBroadcastReceiverState: unknown sourceId"); } } else { byte sourceId = receiverState[BassConstants.BCAST_RCVR_STATE_SRC_ID_IDX]; byte paSyncState = receiverState[BassConstants.BCAST_RCVR_STATE_PA_SYNC_IDX]; byte bigEncryptionStatus = receiverState[BassConstants.BCAST_RCVR_STATE_ENC_STATUS_IDX]; byte[] badBroadcastCode = null; int badBroadcastCodeLen = 0; if (bigEncryptionStatus == BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_BAD_CODE) { badBroadcastCode = new byte[BassConstants.BCAST_RCVR_STATE_BADCODE_SIZE]; System.arraycopy( receiverState, BassConstants.BCAST_RCVR_STATE_BADCODE_START_IDX, badBroadcastCode, 0, BassConstants.BCAST_RCVR_STATE_BADCODE_SIZE); badBroadcastCodeLen = BassConstants.BCAST_RCVR_STATE_BADCODE_SIZE; } byte numSubGroups = receiverState[ BassConstants.BCAST_RCVR_STATE_BADCODE_START_IDX + badBroadcastCodeLen]; int offset = BassConstants.BCAST_RCVR_STATE_BADCODE_START_IDX + badBroadcastCodeLen + 1; ArrayList<BluetoothLeAudioContentMetadata> metadataList = new ArrayList<BluetoothLeAudioContentMetadata>(); ArrayList<Long> bisSyncState = new ArrayList<Long>(); for (int i = 0; i < numSubGroups; i++) { byte[] bisSyncIndex = new byte[Long.BYTES]; System.arraycopy( receiverState, offset, bisSyncIndex, 0, BassConstants.BCAST_RCVR_STATE_BIS_SYNC_SIZE); offset += BassConstants.BCAST_RCVR_STATE_BIS_SYNC_SIZE; bisSyncState.add((long) Utils.byteArrayToLong(bisSyncIndex)); int metaDataLength = receiverState[offset++] & 0xFF; if (metaDataLength > 0) { log("metadata of length: " + metaDataLength + "is available"); byte[] metaData = new byte[metaDataLength]; System.arraycopy(receiverState, offset, metaData, 0, metaDataLength); offset += metaDataLength; metadataList.add(BluetoothLeAudioContentMetadata.fromRawBytes(metaData)); } else { metadataList.add(BluetoothLeAudioContentMetadata.fromRawBytes(new byte[0])); } } byte[] broadcastIdBytes = new byte[mBroadcastSourceIdLength]; System.arraycopy( receiverState, BassConstants.BCAST_RCVR_STATE_SRC_BCAST_ID_START_IDX, broadcastIdBytes, 0, mBroadcastSourceIdLength); int broadcastId = BassUtils.parseBroadcastId(broadcastIdBytes); byte[] sourceAddress = new byte[BassConstants.BCAST_RCVR_STATE_SRC_ADDR_SIZE]; System.arraycopy( receiverState, BassConstants.BCAST_RCVR_STATE_SRC_ADDR_START_IDX, sourceAddress, 0, BassConstants.BCAST_RCVR_STATE_SRC_ADDR_SIZE); byte sourceAddressType = receiverState[BassConstants.BCAST_RCVR_STATE_SRC_ADDR_TYPE_IDX]; BassUtils.reverse(sourceAddress); String address = Utils.getAddressStringFromByte(sourceAddress); BluetoothDevice device = BluetoothAdapter.getDefaultAdapter() .getRemoteLeDevice(address, sourceAddressType); byte sourceAdvSid = receiverState[BassConstants.BCAST_RCVR_STATE_SRC_ADV_SID_IDX]; recvState = new BluetoothLeBroadcastReceiveState( sourceId, (int) sourceAddressType, device, sourceAdvSid, broadcastId, (int) paSyncState, (int) bigEncryptionStatus, badBroadcastCode, numSubGroups, bisSyncState, metadataList); } return recvState; } private void processBroadcastReceiverState( byte[] receiverState, BluetoothGattCharacteristic characteristic) { log( "processBroadcastReceiverState: characteristic:" + characteristic + ", instanceId:" + characteristic.getInstanceId()); BluetoothLeBroadcastReceiveState prevRecvState = mBluetoothLeBroadcastReceiveStates.get(characteristic.getInstanceId()); if (prevRecvState == null && (mBluetoothLeBroadcastReceiveStates.size() == mNumOfBroadcastReceiverStates)) { Log.e(TAG, "processBroadcastReceiverState: reached the Max SourceInfos"); return; } int prevSourceId = BassConstants.INVALID_SOURCE_ID; if (prevRecvState != null) { prevSourceId = prevRecvState.getSourceId(); } BluetoothLeBroadcastReceiveState recvState = parseBroadcastReceiverState(receiverState, prevSourceId); if (recvState == null) { log("processBroadcastReceiverState: Null recvState"); return; } log("processBroadcastReceiverState: Updated receiver state: " + recvState); mBluetoothLeBroadcastReceiveStates.put(characteristic.getInstanceId(), recvState); int sourceId = recvState.getSourceId(); if (isSourceAbsent(prevRecvState) && isSourcePresent(recvState)) { log("processBroadcastReceiverState: Source Addition"); removeMessages(CANCEL_PENDING_SOURCE_OPERATION); if (mPendingMetadata != null) { setCurrentBroadcastMetadata(sourceId, mPendingMetadata); mPendingMetadata = null; } if (mPendingOperation == ADD_BCAST_SOURCE) { mService.getCallbacks() .notifySourceAdded( mDevice, recvState, BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST); } else { mService.getCallbacks() .notifySourceAdded( mDevice, recvState, BluetoothStatusCodes.REASON_REMOTE_REQUEST); } checkAndUpdateBroadcastCode(recvState); processPASyncState(recvState); processSyncStateChangeStats(recvState); } else if (isSourcePresent(prevRecvState) && isSourcePresent(recvState)) { log("processBroadcastReceiverState: Source Update"); removeMessages(CANCEL_PENDING_SOURCE_OPERATION); if (mPendingMetadata != null) { setCurrentBroadcastMetadata(sourceId, mPendingMetadata); mPendingMetadata = null; } mService.getCallbacks() .notifySourceModified( mDevice, sourceId, BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST); checkAndUpdateBroadcastCode(recvState); processPASyncState(recvState); processSyncStateChangeStats(recvState); if (isPendingRemove(sourceId) && !isSyncedToTheSource(sourceId)) { Message message = obtainMessage(REMOVE_BCAST_SOURCE); message.arg1 = sourceId; sendMessage(message); } } else if (isSourcePresent(prevRecvState) && isSourceAbsent(recvState)) { BluetoothDevice removedDevice = prevRecvState.getSourceDevice(); log("processBroadcastReceiverState: Source Removal " + removedDevice); if (!Flags.leaudioBroadcastExtractPeriodicScannerFromStateMachine()) { cancelActiveSync(mService.getSyncHandleForBroadcastId(recvState.getBroadcastId())); } BluetoothLeBroadcastMetadata metaData = getCurrentBroadcastMetadata(sourceId); if (metaData != null) { logBroadcastSyncStatsWithStatus( metaData.getBroadcastId(), BluetoothStatsLog .BROADCAST_AUDIO_SYNC_REPORTED__SYNC_STATUS__SYNC_STATUS_UNKNOWN); } setCurrentBroadcastMetadata(sourceId, null); if (mPendingSourceToSwitch != null) { // Source remove is triggered by switch source request mService.getCallbacks() .notifySourceRemoved( mDevice, sourceId, BluetoothStatusCodes.REASON_LOCAL_STACK_REQUEST); log("processBroadcastReceiverState: Source Switching"); Message message = obtainMessage(ADD_BCAST_SOURCE); message.obj = mPendingSourceToSwitch; sendMessage(message); } else if (mPendingOperation == REMOVE_BCAST_SOURCE) { mService.getCallbacks() .notifySourceRemoved( mDevice, sourceId, BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST); } else { mService.getCallbacks() .notifySourceRemoved( mDevice, sourceId, BluetoothStatusCodes.REASON_REMOTE_REQUEST); } } broadcastReceiverState(recvState, sourceId); } // Implements callback methods for GATT events that the app cares about. // For example, connection change and services discovered. final class GattCallback extends BluetoothGattCallback { Loading Loading @@ -1325,7 +1554,17 @@ class BassClientStateMachine extends StateMachine { characteristic.getValue(), 0, characteristic.getValue().length); if (leaudioBroadcastReceiveStateProcessingRefactor()) { processBroadcastReceiverState(characteristic.getValue(), characteristic); mNumOfReadyBroadcastReceiverStates++; if (mNumOfReadyBroadcastReceiverStates == mNumOfBroadcastReceiverStates) { // Notify service BASS state ready for operations mService.getCallbacks().notifyBassStateReady(mDevice); } } else { processBroadcastReceiverStateObsolete( characteristic.getValue(), characteristic); } } // switch to receiving notifications after initial characteristic read BluetoothGattDescriptor desc = Loading Loading @@ -1376,7 +1615,12 @@ class BassClientStateMachine extends StateMachine { Log.e(TAG, "Remote receiver state is NULL"); return; } if (leaudioBroadcastReceiveStateProcessingRefactor()) { processBroadcastReceiverState(characteristic.getValue(), characteristic); } else { processBroadcastReceiverStateObsolete( characteristic.getValue(), characteristic); } } } Loading Loading @@ -1625,6 +1869,7 @@ class BassClientStateMachine extends StateMachine { mBroadcastScanControlPoint = null; } mNumOfBroadcastReceiverStates = 0; mNumOfReadyBroadcastReceiverStates = 0; if (mBluetoothLeBroadcastReceiveStates != null) { mBluetoothLeBroadcastReceiveStates.clear(); } Loading android/app/tests/unit/src/com/android/bluetooth/bass_client/BassClientServiceTest.java +24 −1 Original line number Diff line number Diff line Loading @@ -140,7 +140,7 @@ public class BassClientServiceTest { // German language code in ISO 639-3 private static final String TEST_LANGUAGE = "deu"; private static final int TEST_SOURCE_ID = 10; private static final int TEST_NUM_SOURCES = 2; private static final int TEST_NUM_SOURCES = 1; private final HashMap<BluetoothDevice, BassClientStateMachine> mStateMachines = new HashMap<>(); private HashMap<BluetoothDevice, LinkedBlockingQueue<Intent>> mIntentQueue; Loading Loading @@ -2176,6 +2176,29 @@ public class BassClientServiceTest { } } @Test public void testSecondAddSourceWithCapacityGreaterThanOne() { prepareConnectedDeviceGroup(); // Set maximum source capacity to 2 for (BassClientStateMachine sm : mStateMachines.values()) { doReturn(2).when(sm).getMaximumSourceCapacity(); } startSearchingForSources(); onScanResult(mSourceDevice, TEST_BROADCAST_ID); onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); verifyAddSourceForGroup(meta); prepareRemoteSourceState(meta, true, true); // Add another new broadcast source onScanResult(mSourceDevice2, TEST_BROADCAST_ID + 1); onSyncEstablished(mSourceDevice2, TEST_SYNC_HANDLE + 1); BluetoothLeBroadcastMetadata newMeta = createBroadcastMetadata(TEST_BROADCAST_ID + 1); verifyAddSourceForGroup(newMeta); } /** * Test that after multiple calls to service.addSource() with a group operation flag set, there * are two call to service.removeSource() needed to clear the flag Loading android/app/tests/unit/src/com/android/bluetooth/bass_client/BassClientStateMachineTest.java +447 −23 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
android/app/src/com/android/bluetooth/bass_client/BassClientService.java +9 −4 Original line number Diff line number Diff line Loading @@ -1338,12 +1338,17 @@ public class BassClientService extends ProfileService { return false; } boolean isRoomAvailable = false; for (BluetoothLeBroadcastReceiveState recvState : stateMachine.getAllSources()) { List<BluetoothLeBroadcastReceiveState> sources = stateMachine.getAllSources(); if (sources.size() < stateMachine.getMaximumSourceCapacity()) { isRoomAvailable = true; } else { for (BluetoothLeBroadcastReceiveState recvState : sources) { if (isEmptyBluetoothDevice(recvState.getSourceDevice())) { isRoomAvailable = true; break; } } } log("isRoomAvailable: " + isRoomAvailable); return isRoomAvailable; } Loading
android/app/src/com/android/bluetooth/bass_client/BassClientStateMachine.java +251 −6 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static android.Manifest.permission.BLUETOOTH_CONNECT; import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; import static com.android.bluetooth.flags.Flags.leaudioBigDependsOnAudioState; import static com.android.bluetooth.flags.Flags.leaudioBroadcastReceiveStateProcessingRefactor; import static com.android.bluetooth.flags.Flags.leaudioBroadcastResyncHelper; import android.annotation.Nullable; Loading Loading @@ -155,6 +156,7 @@ class BassClientStateMachine extends StateMachine { private final Map<Integer, Boolean> mFirstTimeBisDiscoveryMap; private int mPASyncRetryCounter = 0; @VisibleForTesting int mNumOfBroadcastReceiverStates = 0; int mNumOfReadyBroadcastReceiverStates = 0; @VisibleForTesting int mPendingOperation = -1; @VisibleForTesting byte mPendingSourceId = -1; @VisibleForTesting BluetoothLeBroadcastMetadata mPendingMetadata = null; Loading Loading @@ -975,10 +977,15 @@ class BassClientStateMachine extends StateMachine { } private boolean isSourceAbsent(BluetoothLeBroadcastReceiveState recvState) { return recvState.getSourceDevice() == null return recvState == null || recvState.getSourceDevice() == null || recvState.getSourceDevice().getAddress().equals("00:00:00:00:00:00"); } private boolean isSourcePresent(BluetoothLeBroadcastReceiveState recvState) { return !isSourceAbsent(recvState); } private void checkAndUpdateBroadcastCode(BluetoothLeBroadcastReceiveState recvState) { log("checkAndUpdateBroadcastCode"); // Whenever receive state indicated code requested, assistant should set the broadcast code Loading @@ -999,7 +1006,8 @@ class BassClientStateMachine extends StateMachine { } } private BluetoothLeBroadcastReceiveState parseBroadcastReceiverState(byte[] receiverState) { private BluetoothLeBroadcastReceiveState parseBroadcastReceiverStateObsolete( byte[] receiverState) { byte sourceId = 0; if (receiverState.length > 0) { sourceId = receiverState[BassConstants.BCAST_RCVR_STATE_SRC_ID_IDX]; Loading Loading @@ -1140,10 +1148,11 @@ class BassClientStateMachine extends StateMachine { return recvState; } private void processBroadcastReceiverState( private void processBroadcastReceiverStateObsolete( byte[] receiverState, BluetoothGattCharacteristic characteristic) { log("processBroadcastReceiverState: characteristic:" + characteristic); BluetoothLeBroadcastReceiveState recvState = parseBroadcastReceiverState(receiverState); BluetoothLeBroadcastReceiveState recvState = parseBroadcastReceiverStateObsolete(receiverState); if (recvState == null) { log("processBroadcastReceiverState: Null recvState"); return; Loading Loading @@ -1249,6 +1258,226 @@ class BassClientStateMachine extends StateMachine { broadcastReceiverState(recvState, sourceId); } private BluetoothLeBroadcastReceiveState parseBroadcastReceiverState( byte[] receiverState, int previousSourceId) { log("parseBroadcastReceiverState: receiverState length: " + receiverState.length); BluetoothLeBroadcastReceiveState recvState = null; if (receiverState.length == 0) { byte[] emptyBluetoothDeviceAddress = Utils.getBytesFromAddress("00:00:00:00:00:00"); if (previousSourceId != BassConstants.INVALID_SOURCE_ID) { recvState = new BluetoothLeBroadcastReceiveState( previousSourceId, BluetoothDevice.ADDRESS_TYPE_PUBLIC, // sourceAddressType mAdapterService.getDeviceFromByte( emptyBluetoothDeviceAddress), // sourceDev 0, // sourceAdvertisingSid 0, // broadcastId BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE, // paSyncState // bigEncryptionState BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_NOT_ENCRYPTED, null, // badCode 0, // numSubgroups Arrays.asList(new Long[0]), // bisSyncState Arrays.asList( new BluetoothLeAudioContentMetadata[0]) // subgroupMetadata ); } else { log("parseBroadcastReceiverState: unknown sourceId"); } } else { byte sourceId = receiverState[BassConstants.BCAST_RCVR_STATE_SRC_ID_IDX]; byte paSyncState = receiverState[BassConstants.BCAST_RCVR_STATE_PA_SYNC_IDX]; byte bigEncryptionStatus = receiverState[BassConstants.BCAST_RCVR_STATE_ENC_STATUS_IDX]; byte[] badBroadcastCode = null; int badBroadcastCodeLen = 0; if (bigEncryptionStatus == BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_BAD_CODE) { badBroadcastCode = new byte[BassConstants.BCAST_RCVR_STATE_BADCODE_SIZE]; System.arraycopy( receiverState, BassConstants.BCAST_RCVR_STATE_BADCODE_START_IDX, badBroadcastCode, 0, BassConstants.BCAST_RCVR_STATE_BADCODE_SIZE); badBroadcastCodeLen = BassConstants.BCAST_RCVR_STATE_BADCODE_SIZE; } byte numSubGroups = receiverState[ BassConstants.BCAST_RCVR_STATE_BADCODE_START_IDX + badBroadcastCodeLen]; int offset = BassConstants.BCAST_RCVR_STATE_BADCODE_START_IDX + badBroadcastCodeLen + 1; ArrayList<BluetoothLeAudioContentMetadata> metadataList = new ArrayList<BluetoothLeAudioContentMetadata>(); ArrayList<Long> bisSyncState = new ArrayList<Long>(); for (int i = 0; i < numSubGroups; i++) { byte[] bisSyncIndex = new byte[Long.BYTES]; System.arraycopy( receiverState, offset, bisSyncIndex, 0, BassConstants.BCAST_RCVR_STATE_BIS_SYNC_SIZE); offset += BassConstants.BCAST_RCVR_STATE_BIS_SYNC_SIZE; bisSyncState.add((long) Utils.byteArrayToLong(bisSyncIndex)); int metaDataLength = receiverState[offset++] & 0xFF; if (metaDataLength > 0) { log("metadata of length: " + metaDataLength + "is available"); byte[] metaData = new byte[metaDataLength]; System.arraycopy(receiverState, offset, metaData, 0, metaDataLength); offset += metaDataLength; metadataList.add(BluetoothLeAudioContentMetadata.fromRawBytes(metaData)); } else { metadataList.add(BluetoothLeAudioContentMetadata.fromRawBytes(new byte[0])); } } byte[] broadcastIdBytes = new byte[mBroadcastSourceIdLength]; System.arraycopy( receiverState, BassConstants.BCAST_RCVR_STATE_SRC_BCAST_ID_START_IDX, broadcastIdBytes, 0, mBroadcastSourceIdLength); int broadcastId = BassUtils.parseBroadcastId(broadcastIdBytes); byte[] sourceAddress = new byte[BassConstants.BCAST_RCVR_STATE_SRC_ADDR_SIZE]; System.arraycopy( receiverState, BassConstants.BCAST_RCVR_STATE_SRC_ADDR_START_IDX, sourceAddress, 0, BassConstants.BCAST_RCVR_STATE_SRC_ADDR_SIZE); byte sourceAddressType = receiverState[BassConstants.BCAST_RCVR_STATE_SRC_ADDR_TYPE_IDX]; BassUtils.reverse(sourceAddress); String address = Utils.getAddressStringFromByte(sourceAddress); BluetoothDevice device = BluetoothAdapter.getDefaultAdapter() .getRemoteLeDevice(address, sourceAddressType); byte sourceAdvSid = receiverState[BassConstants.BCAST_RCVR_STATE_SRC_ADV_SID_IDX]; recvState = new BluetoothLeBroadcastReceiveState( sourceId, (int) sourceAddressType, device, sourceAdvSid, broadcastId, (int) paSyncState, (int) bigEncryptionStatus, badBroadcastCode, numSubGroups, bisSyncState, metadataList); } return recvState; } private void processBroadcastReceiverState( byte[] receiverState, BluetoothGattCharacteristic characteristic) { log( "processBroadcastReceiverState: characteristic:" + characteristic + ", instanceId:" + characteristic.getInstanceId()); BluetoothLeBroadcastReceiveState prevRecvState = mBluetoothLeBroadcastReceiveStates.get(characteristic.getInstanceId()); if (prevRecvState == null && (mBluetoothLeBroadcastReceiveStates.size() == mNumOfBroadcastReceiverStates)) { Log.e(TAG, "processBroadcastReceiverState: reached the Max SourceInfos"); return; } int prevSourceId = BassConstants.INVALID_SOURCE_ID; if (prevRecvState != null) { prevSourceId = prevRecvState.getSourceId(); } BluetoothLeBroadcastReceiveState recvState = parseBroadcastReceiverState(receiverState, prevSourceId); if (recvState == null) { log("processBroadcastReceiverState: Null recvState"); return; } log("processBroadcastReceiverState: Updated receiver state: " + recvState); mBluetoothLeBroadcastReceiveStates.put(characteristic.getInstanceId(), recvState); int sourceId = recvState.getSourceId(); if (isSourceAbsent(prevRecvState) && isSourcePresent(recvState)) { log("processBroadcastReceiverState: Source Addition"); removeMessages(CANCEL_PENDING_SOURCE_OPERATION); if (mPendingMetadata != null) { setCurrentBroadcastMetadata(sourceId, mPendingMetadata); mPendingMetadata = null; } if (mPendingOperation == ADD_BCAST_SOURCE) { mService.getCallbacks() .notifySourceAdded( mDevice, recvState, BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST); } else { mService.getCallbacks() .notifySourceAdded( mDevice, recvState, BluetoothStatusCodes.REASON_REMOTE_REQUEST); } checkAndUpdateBroadcastCode(recvState); processPASyncState(recvState); processSyncStateChangeStats(recvState); } else if (isSourcePresent(prevRecvState) && isSourcePresent(recvState)) { log("processBroadcastReceiverState: Source Update"); removeMessages(CANCEL_PENDING_SOURCE_OPERATION); if (mPendingMetadata != null) { setCurrentBroadcastMetadata(sourceId, mPendingMetadata); mPendingMetadata = null; } mService.getCallbacks() .notifySourceModified( mDevice, sourceId, BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST); checkAndUpdateBroadcastCode(recvState); processPASyncState(recvState); processSyncStateChangeStats(recvState); if (isPendingRemove(sourceId) && !isSyncedToTheSource(sourceId)) { Message message = obtainMessage(REMOVE_BCAST_SOURCE); message.arg1 = sourceId; sendMessage(message); } } else if (isSourcePresent(prevRecvState) && isSourceAbsent(recvState)) { BluetoothDevice removedDevice = prevRecvState.getSourceDevice(); log("processBroadcastReceiverState: Source Removal " + removedDevice); if (!Flags.leaudioBroadcastExtractPeriodicScannerFromStateMachine()) { cancelActiveSync(mService.getSyncHandleForBroadcastId(recvState.getBroadcastId())); } BluetoothLeBroadcastMetadata metaData = getCurrentBroadcastMetadata(sourceId); if (metaData != null) { logBroadcastSyncStatsWithStatus( metaData.getBroadcastId(), BluetoothStatsLog .BROADCAST_AUDIO_SYNC_REPORTED__SYNC_STATUS__SYNC_STATUS_UNKNOWN); } setCurrentBroadcastMetadata(sourceId, null); if (mPendingSourceToSwitch != null) { // Source remove is triggered by switch source request mService.getCallbacks() .notifySourceRemoved( mDevice, sourceId, BluetoothStatusCodes.REASON_LOCAL_STACK_REQUEST); log("processBroadcastReceiverState: Source Switching"); Message message = obtainMessage(ADD_BCAST_SOURCE); message.obj = mPendingSourceToSwitch; sendMessage(message); } else if (mPendingOperation == REMOVE_BCAST_SOURCE) { mService.getCallbacks() .notifySourceRemoved( mDevice, sourceId, BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST); } else { mService.getCallbacks() .notifySourceRemoved( mDevice, sourceId, BluetoothStatusCodes.REASON_REMOTE_REQUEST); } } broadcastReceiverState(recvState, sourceId); } // Implements callback methods for GATT events that the app cares about. // For example, connection change and services discovered. final class GattCallback extends BluetoothGattCallback { Loading Loading @@ -1325,7 +1554,17 @@ class BassClientStateMachine extends StateMachine { characteristic.getValue(), 0, characteristic.getValue().length); if (leaudioBroadcastReceiveStateProcessingRefactor()) { processBroadcastReceiverState(characteristic.getValue(), characteristic); mNumOfReadyBroadcastReceiverStates++; if (mNumOfReadyBroadcastReceiverStates == mNumOfBroadcastReceiverStates) { // Notify service BASS state ready for operations mService.getCallbacks().notifyBassStateReady(mDevice); } } else { processBroadcastReceiverStateObsolete( characteristic.getValue(), characteristic); } } // switch to receiving notifications after initial characteristic read BluetoothGattDescriptor desc = Loading Loading @@ -1376,7 +1615,12 @@ class BassClientStateMachine extends StateMachine { Log.e(TAG, "Remote receiver state is NULL"); return; } if (leaudioBroadcastReceiveStateProcessingRefactor()) { processBroadcastReceiverState(characteristic.getValue(), characteristic); } else { processBroadcastReceiverStateObsolete( characteristic.getValue(), characteristic); } } } Loading Loading @@ -1625,6 +1869,7 @@ class BassClientStateMachine extends StateMachine { mBroadcastScanControlPoint = null; } mNumOfBroadcastReceiverStates = 0; mNumOfReadyBroadcastReceiverStates = 0; if (mBluetoothLeBroadcastReceiveStates != null) { mBluetoothLeBroadcastReceiveStates.clear(); } Loading
android/app/tests/unit/src/com/android/bluetooth/bass_client/BassClientServiceTest.java +24 −1 Original line number Diff line number Diff line Loading @@ -140,7 +140,7 @@ public class BassClientServiceTest { // German language code in ISO 639-3 private static final String TEST_LANGUAGE = "deu"; private static final int TEST_SOURCE_ID = 10; private static final int TEST_NUM_SOURCES = 2; private static final int TEST_NUM_SOURCES = 1; private final HashMap<BluetoothDevice, BassClientStateMachine> mStateMachines = new HashMap<>(); private HashMap<BluetoothDevice, LinkedBlockingQueue<Intent>> mIntentQueue; Loading Loading @@ -2176,6 +2176,29 @@ public class BassClientServiceTest { } } @Test public void testSecondAddSourceWithCapacityGreaterThanOne() { prepareConnectedDeviceGroup(); // Set maximum source capacity to 2 for (BassClientStateMachine sm : mStateMachines.values()) { doReturn(2).when(sm).getMaximumSourceCapacity(); } startSearchingForSources(); onScanResult(mSourceDevice, TEST_BROADCAST_ID); onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID); verifyAddSourceForGroup(meta); prepareRemoteSourceState(meta, true, true); // Add another new broadcast source onScanResult(mSourceDevice2, TEST_BROADCAST_ID + 1); onSyncEstablished(mSourceDevice2, TEST_SYNC_HANDLE + 1); BluetoothLeBroadcastMetadata newMeta = createBroadcastMetadata(TEST_BROADCAST_ID + 1); verifyAddSourceForGroup(newMeta); } /** * Test that after multiple calls to service.addSource() with a group operation flag set, there * are two call to service.removeSource() needed to clear the flag Loading
android/app/tests/unit/src/com/android/bluetooth/bass_client/BassClientStateMachineTest.java +447 −23 File changed.Preview size limit exceeded, changes collapsed. Show changes