Loading TEST_MAPPING +3 −0 Original line number Diff line number Diff line Loading @@ -326,6 +326,9 @@ { "name": "bluetooth_test_gdx_unit" }, { "name": "CtsStrictJavaPackagesTestCases" }, { "name": "asrc_resampler_test" } Loading android/app/src/com/android/bluetooth/bass_client/BassClientService.java +207 −14 Original line number Diff line number Diff line Loading @@ -60,8 +60,10 @@ import com.android.bluetooth.le_audio.LeAudioService; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.ArrayDeque; import java.util.Arrays; import java.util.Collections; import java.util.Deque; import java.util.HashMap; import java.util.LinkedList; import java.util.List; Loading @@ -79,6 +81,10 @@ public class BassClientService extends ProfileService { private static final int MAX_BASS_CLIENT_STATE_MACHINES = 10; private static final int MAX_ACTIVE_SYNCED_SOURCES_NUM = 4; private static final int STATUS_LOCAL_STREAM_REQUESTED = 0; private static final int STATUS_LOCAL_STREAM_STREAMING = 1; private static final int STATUS_LOCAL_STREAM_SUSPENDED = 2; private static BassClientService sService; private final Map<BluetoothDevice, BassClientStateMachine> mStateMachines = new HashMap<>(); Loading @@ -94,6 +100,7 @@ public class BassClientService extends ProfileService { private final Map<BluetoothDevice, BluetoothLeBroadcastMetadata> mBroadcastMetadataMap = new ConcurrentHashMap<>(); private final LinkedList<BluetoothDevice> mPausedBroadcastSinks = new LinkedList<>(); private final Deque<AddSourceData> mPendingAddSources = new ArrayDeque<>(); private HandlerThread mStateMachinesThread; private HandlerThread mCallbackHandlerThread; Loading @@ -117,6 +124,8 @@ public class BassClientService extends ProfileService { mPeriodicAdvertisementResultMap; private ScanCallback mSearchScanCallback; private Callbacks mCallbacks; private boolean mIsAssistantActive = false; Optional<Integer> mUnicastSourceStreamStatus = Optional.empty(); private static final int LOG_NB_EVENTS = 100; private static final BluetoothEventLogger sEventLogger = Loading @@ -142,6 +151,21 @@ public class BassClientService extends ProfileService { && BluetoothProperties.isProfileBapBroadcastAssistEnabled().orElse(false); } private static class AddSourceData { BluetoothDevice mSink; BluetoothLeBroadcastMetadata mSourceMetadata; boolean mIsGroupOp; AddSourceData( BluetoothDevice sink, BluetoothLeBroadcastMetadata sourceMetadata, boolean isGroupOp) { mSink = sink; mSourceMetadata = sourceMetadata; mIsGroupOp = isGroupOp; } } void updatePeriodicAdvertisementResultMap( BluetoothDevice device, int addressType, Loading Loading @@ -389,6 +413,15 @@ public class BassClientService extends ProfileService { Log.d(TAG, "stop()"); } mUnicastSourceStreamStatus = Optional.empty(); if (mIsAssistantActive) { LeAudioService leAudioService = mServiceFactory.getLeAudioService(); if (leAudioService != null) { leAudioService.activeBroadcastAssistantNotification(false); } } synchronized (mStateMachines) { for (BassClientStateMachine sm : mStateMachines.values()) { BassObjectsFactory.getInstance().destroyStateMachine(sm); Loading Loading @@ -513,6 +546,24 @@ public class BassClientService extends ProfileService { return ret; } private boolean isAnyPendingAddSourceOperation() { for (BluetoothDevice device : getConnectedDevices()) { List<Pair<Integer, Object>> operations = mPendingGroupOp.get(device); if (operations == null) { continue; } boolean isAnyPendingAddSourceOperationForDevice = operations.stream() .anyMatch(e -> e.first.equals(BassClientStateMachine.ADD_BCAST_SOURCE)); if (isAnyPendingAddSourceOperationForDevice) { return true; } } return false; } private void checkForPendingGroupOpRequest(BluetoothDevice sink, int reason, int reqMsg, Object obj) { log("checkForPendingGroupOpRequest device: " + sink + ", reason: " + reason Loading Loading @@ -546,6 +597,17 @@ public class BassClientService extends ProfileService { (m.first.equals(BassClientStateMachine.ADD_BCAST_SOURCE)) && (metadata.getBroadcastId() == ((BluetoothLeBroadcastMetadata) m.second).getBroadcastId())); if (!isAnyPendingAddSourceOperation() && mIsAssistantActive && mPausedBroadcastSinks.isEmpty()) { LeAudioService leAudioService = mServiceFactory.getLeAudioService(); mIsAssistantActive = false; mUnicastSourceStreamStatus = Optional.empty(); if (leAudioService != null) { leAudioService.activeBroadcastAssistantNotification(false); } } } break; case BassClientStateMachine.REMOVE_BCAST_SOURCE: Loading @@ -561,6 +623,33 @@ public class BassClientService extends ProfileService { } } private void localNotifyReceiveStateChanged() { LeAudioService leAudioService = mServiceFactory.getLeAudioService(); if (leAudioService == null) { return; } boolean isAssistantActive = isAnyReceiverReceivingBroadcast(); if (isAssistantActive) { /* Assistant become active */ if (!mIsAssistantActive) { mIsAssistantActive = true; leAudioService.activeBroadcastAssistantNotification(true); return; } } else { /* Assistant become inactive */ if (mIsAssistantActive && mPausedBroadcastSinks.isEmpty()) { mIsAssistantActive = false; mUnicastSourceStreamStatus = Optional.empty(); leAudioService.activeBroadcastAssistantNotification(false); return; } } } private void setSourceGroupManaged(BluetoothDevice sink, int sourceId, boolean isGroupOp) { log("setSourceGroupManaged device: " + sink); if (isGroupOp) { Loading Loading @@ -1231,10 +1320,17 @@ public class BassClientService extends ProfileService { * @param isGroupOp set to true If Application wants to perform this operation for all * coordinated set members, False otherwise */ public void addSource(BluetoothDevice sink, BluetoothLeBroadcastMetadata sourceMetadata, public void addSource( BluetoothDevice sink, BluetoothLeBroadcastMetadata sourceMetadata, boolean isGroupOp) { log("addSource: device: " + sink + " sourceMetadata" + sourceMetadata + " isGroupOp: " + isGroupOp); log( "addSource: device: " + sink + " sourceMetadata" + sourceMetadata + " isGroupOp: " + isGroupOp); List<BluetoothDevice> devices = getTargetDeviceList(sink, isGroupOp); // Don't coordinate it as a group if there's no group or there is one device only Loading @@ -1247,6 +1343,13 @@ public class BassClientService extends ProfileService { return; } if (!isAllowedToAddSource()) { Log.d(TAG, "Add source to pending list"); mPendingAddSources.push(new AddSourceData(sink, sourceMetadata, isGroupOp)); return; } byte[] code = sourceMetadata.getBroadcastCode(); for (BluetoothDevice device : devices) { BassClientStateMachine stateMachine = getOrCreateStateMachine(device); Loading Loading @@ -1592,13 +1695,14 @@ public class BassClientService extends ProfileService { } } private void stopLocalSourceReceivers(int broadcastId, boolean store) { private void stopSourceReceivers(int broadcastId, boolean store) { if (DBG) { Log.d(TAG, "stopLocalSourceReceivers()"); Log.d(TAG, "stopSourceReceivers(), broadcastId: " + broadcastId + ", store: " + store); } if (store && !mPausedBroadcastSinks.isEmpty()) { Log.w(TAG, "stopLocalSourceReceivers(), paused broadcast sinks are replaced"); Log.w(TAG, "stopSourceReceivers(), paused broadcast sinks are replaced"); sEventLogger.logd(DBG, TAG, "Clear broadcast sinks paused cache"); mPausedBroadcastSinks.clear(); } Loading @@ -1606,44 +1710,130 @@ public class BassClientService extends ProfileService { for (BluetoothDevice device : getConnectedDevices()) { for (BluetoothLeBroadcastReceiveState receiveState : getAllSources(device)) { /* Check if local/last broadcast is the synced one */ if (receiveState.getBroadcastId() != broadcastId) continue; /* Check if local/last broadcast is the synced one. Invalid broadcast ID means * that all receivers should be considered. */ if ((broadcastId != BassConstants.INVALID_BROADCAST_ID) && (receiveState.getBroadcastId() != broadcastId)) { continue; } if (store && !mPausedBroadcastSinks.contains(device)) { sEventLogger.logd(DBG, TAG, "Add broadcast sink to paused cache: " + device); mPausedBroadcastSinks.add(device); } sourcesToRemove.put(device, receiveState.getSourceId()); } } for (Map.Entry<BluetoothDevice, Integer> entry : sourcesToRemove.entrySet()) { removeSource(entry.getKey(), entry.getValue()); } } private boolean isAllowedToAddSource() { if (mFeatureFlags.leaudioBroadcastAudioHandoverPolicies()) { /* Check if should wait for status update */ if (mUnicastSourceStreamStatus.isEmpty()) { /* Assistant was not active, inform about activation */ if (!mIsAssistantActive) { mIsAssistantActive = true; LeAudioService leAudioService = mServiceFactory.getLeAudioService(); if (leAudioService != null) { leAudioService.activeBroadcastAssistantNotification(true); } } return false; } return mUnicastSourceStreamStatus.get() == STATUS_LOCAL_STREAM_SUSPENDED; } /* Don't block if this is not a handover case */ return true; } private boolean isAnyReceiverReceivingBroadcast() { for (BluetoothDevice device : getConnectedDevices()) { for (BluetoothLeBroadcastReceiveState receiveState : getAllSources(device)) { for (int i = 0; i < receiveState.getNumSubgroups(); i++) { Long syncState = receiveState.getBisSyncState().get(i); /* Not synced to BIS of failed to sync to BIG */ if (syncState == 0x00000000 || syncState == 0xFFFFFFFF) { continue; } return true; } } } return false; } /** Request receivers to suspend broadcast sources synchronization */ public void suspendReceiversSourceSynchronization(int broadcastId) { sEventLogger.logd(DBG, TAG, "Suspend receivers source synchronization: " + broadcastId); stopLocalSourceReceivers(broadcastId, true); stopSourceReceivers(broadcastId, true); } /** Request all receivers to suspend broadcast sources synchronization */ public void suspendAllReceiversSourceSynchronization() { sEventLogger.logd(DBG, TAG, "Suspend all receivers source synchronization"); stopSourceReceivers(BassConstants.INVALID_BROADCAST_ID, true); } /** Request receivers to stop broadcast sources synchronization and remove them */ public void stopReceiversSourceSynchronization(int broadcastId) { sEventLogger.logd(DBG, TAG, "Stop receivers source synchronization: " + broadcastId); stopLocalSourceReceivers(broadcastId, false); stopSourceReceivers(broadcastId, false); } /** Request receivers to resume broadcast source synchronization */ public void resumeReceiversSourceSynchronization(int broadcastId) { sEventLogger.logd(DBG, TAG, "Resume receivers source synchronization: " + broadcastId); public void resumeReceiversSourceSynchronization() { sEventLogger.logd(DBG, TAG, "Resume receivers source synchronization"); while (!mPausedBroadcastSinks.isEmpty()) { BluetoothDevice sink = mPausedBroadcastSinks.remove(); sEventLogger.logd(DBG, TAG, "Remove broadcast sink from paused cache: " + sink); BluetoothLeBroadcastMetadata metadata = mBroadcastMetadataMap.get(sink); if (metadata != null) { addSource(sink, metadata, true); addSource(sink, metadata, false); } } } /** Handle Unicast source stream status change */ public void handleUnicastSourceStreamStatusChange(int status) { mUnicastSourceStreamStatus = Optional.of(status); if (status == STATUS_LOCAL_STREAM_REQUESTED) { if (isAnyReceiverReceivingBroadcast()) { suspendAllReceiversSourceSynchronization(); } } else if (status == STATUS_LOCAL_STREAM_SUSPENDED) { /* Resume paused receivers if there are some */ if (!mPausedBroadcastSinks.isEmpty()) { resumeReceiversSourceSynchronization(); } /* Add pending sources if there are some */ while (!mPendingAddSources.isEmpty()) { AddSourceData addSourceData = mPendingAddSources.pop(); addSource( addSourceData.mSink, addSourceData.mSourceMetadata, addSourceData.mIsGroupOp); } } else if (status == STATUS_LOCAL_STREAM_STREAMING) { Log.d(TAG, "Ignore STREAMING source status"); } } Loading Loading @@ -1912,6 +2102,9 @@ public class BassClientService extends ProfileService { void notifyReceiveStateChanged(BluetoothDevice sink, int sourceId, BluetoothLeBroadcastReceiveState state) { ObjParams param = new ObjParams(sink, state); sService.localNotifyReceiveStateChanged(); String subgroupState = " / SUB GROUPS: "; for (int i = 0; i < state.getNumSubgroups(); i++) { subgroupState += "IDX: " + i + ", SYNC: " + state.getBisSyncState().get(i); Loading android/app/src/com/android/bluetooth/btservice/AdapterService.java +1 −1 Original line number Diff line number Diff line Loading @@ -127,7 +127,7 @@ import com.android.bluetooth.btservice.storage.MetadataDatabase; import com.android.bluetooth.csip.CsipSetCoordinatorService; import com.android.bluetooth.flags.FeatureFlagsImpl; import com.android.bluetooth.gatt.GattService; import com.android.bluetooth.gatt.ScanManager; import com.android.bluetooth.le_scan.ScanManager; import com.android.bluetooth.hap.HapClientService; import com.android.bluetooth.hearingaid.HearingAidService; import com.android.bluetooth.hfp.HeadsetService; Loading android/app/src/com/android/bluetooth/btservice/storage/CustomizedMetadataEntity.java +4 −2 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ class CustomizedMetadataEntity { public byte[] le_audio; public byte[] gmcs_cccd; public byte[] gtbs_cccd; public byte[] exclusive_manager; public String toString() { StringBuilder builder = new StringBuilder(); Loading Loading @@ -109,8 +110,9 @@ class CustomizedMetadataEntity { .append("|gmcs_cccd=") .append(metadataToString(gmcs_cccd)) .append("|gtbs_cccd=") .append(metadataToString(gtbs_cccd)); .append(metadataToString(gtbs_cccd)) .append("|exclusive_manager=") .append(metadataToString(exclusive_manager)); return builder.toString(); } Loading android/app/src/com/android/bluetooth/btservice/storage/Metadata.java +6 −0 Original line number Diff line number Diff line Loading @@ -349,6 +349,9 @@ public class Metadata { case BluetoothDevice.METADATA_GTBS_CCCD: publicMetadata.gtbs_cccd = value; break; case BluetoothDevice.METADATA_EXCLUSIVE_MANAGER: publicMetadata.exclusive_manager = value; break; } } Loading Loading @@ -446,6 +449,9 @@ public class Metadata { case BluetoothDevice.METADATA_GTBS_CCCD: value = publicMetadata.gtbs_cccd; break; case BluetoothDevice.METADATA_EXCLUSIVE_MANAGER: value = publicMetadata.exclusive_manager; break; } return value; } Loading Loading
TEST_MAPPING +3 −0 Original line number Diff line number Diff line Loading @@ -326,6 +326,9 @@ { "name": "bluetooth_test_gdx_unit" }, { "name": "CtsStrictJavaPackagesTestCases" }, { "name": "asrc_resampler_test" } Loading
android/app/src/com/android/bluetooth/bass_client/BassClientService.java +207 −14 Original line number Diff line number Diff line Loading @@ -60,8 +60,10 @@ import com.android.bluetooth.le_audio.LeAudioService; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.ArrayDeque; import java.util.Arrays; import java.util.Collections; import java.util.Deque; import java.util.HashMap; import java.util.LinkedList; import java.util.List; Loading @@ -79,6 +81,10 @@ public class BassClientService extends ProfileService { private static final int MAX_BASS_CLIENT_STATE_MACHINES = 10; private static final int MAX_ACTIVE_SYNCED_SOURCES_NUM = 4; private static final int STATUS_LOCAL_STREAM_REQUESTED = 0; private static final int STATUS_LOCAL_STREAM_STREAMING = 1; private static final int STATUS_LOCAL_STREAM_SUSPENDED = 2; private static BassClientService sService; private final Map<BluetoothDevice, BassClientStateMachine> mStateMachines = new HashMap<>(); Loading @@ -94,6 +100,7 @@ public class BassClientService extends ProfileService { private final Map<BluetoothDevice, BluetoothLeBroadcastMetadata> mBroadcastMetadataMap = new ConcurrentHashMap<>(); private final LinkedList<BluetoothDevice> mPausedBroadcastSinks = new LinkedList<>(); private final Deque<AddSourceData> mPendingAddSources = new ArrayDeque<>(); private HandlerThread mStateMachinesThread; private HandlerThread mCallbackHandlerThread; Loading @@ -117,6 +124,8 @@ public class BassClientService extends ProfileService { mPeriodicAdvertisementResultMap; private ScanCallback mSearchScanCallback; private Callbacks mCallbacks; private boolean mIsAssistantActive = false; Optional<Integer> mUnicastSourceStreamStatus = Optional.empty(); private static final int LOG_NB_EVENTS = 100; private static final BluetoothEventLogger sEventLogger = Loading @@ -142,6 +151,21 @@ public class BassClientService extends ProfileService { && BluetoothProperties.isProfileBapBroadcastAssistEnabled().orElse(false); } private static class AddSourceData { BluetoothDevice mSink; BluetoothLeBroadcastMetadata mSourceMetadata; boolean mIsGroupOp; AddSourceData( BluetoothDevice sink, BluetoothLeBroadcastMetadata sourceMetadata, boolean isGroupOp) { mSink = sink; mSourceMetadata = sourceMetadata; mIsGroupOp = isGroupOp; } } void updatePeriodicAdvertisementResultMap( BluetoothDevice device, int addressType, Loading Loading @@ -389,6 +413,15 @@ public class BassClientService extends ProfileService { Log.d(TAG, "stop()"); } mUnicastSourceStreamStatus = Optional.empty(); if (mIsAssistantActive) { LeAudioService leAudioService = mServiceFactory.getLeAudioService(); if (leAudioService != null) { leAudioService.activeBroadcastAssistantNotification(false); } } synchronized (mStateMachines) { for (BassClientStateMachine sm : mStateMachines.values()) { BassObjectsFactory.getInstance().destroyStateMachine(sm); Loading Loading @@ -513,6 +546,24 @@ public class BassClientService extends ProfileService { return ret; } private boolean isAnyPendingAddSourceOperation() { for (BluetoothDevice device : getConnectedDevices()) { List<Pair<Integer, Object>> operations = mPendingGroupOp.get(device); if (operations == null) { continue; } boolean isAnyPendingAddSourceOperationForDevice = operations.stream() .anyMatch(e -> e.first.equals(BassClientStateMachine.ADD_BCAST_SOURCE)); if (isAnyPendingAddSourceOperationForDevice) { return true; } } return false; } private void checkForPendingGroupOpRequest(BluetoothDevice sink, int reason, int reqMsg, Object obj) { log("checkForPendingGroupOpRequest device: " + sink + ", reason: " + reason Loading Loading @@ -546,6 +597,17 @@ public class BassClientService extends ProfileService { (m.first.equals(BassClientStateMachine.ADD_BCAST_SOURCE)) && (metadata.getBroadcastId() == ((BluetoothLeBroadcastMetadata) m.second).getBroadcastId())); if (!isAnyPendingAddSourceOperation() && mIsAssistantActive && mPausedBroadcastSinks.isEmpty()) { LeAudioService leAudioService = mServiceFactory.getLeAudioService(); mIsAssistantActive = false; mUnicastSourceStreamStatus = Optional.empty(); if (leAudioService != null) { leAudioService.activeBroadcastAssistantNotification(false); } } } break; case BassClientStateMachine.REMOVE_BCAST_SOURCE: Loading @@ -561,6 +623,33 @@ public class BassClientService extends ProfileService { } } private void localNotifyReceiveStateChanged() { LeAudioService leAudioService = mServiceFactory.getLeAudioService(); if (leAudioService == null) { return; } boolean isAssistantActive = isAnyReceiverReceivingBroadcast(); if (isAssistantActive) { /* Assistant become active */ if (!mIsAssistantActive) { mIsAssistantActive = true; leAudioService.activeBroadcastAssistantNotification(true); return; } } else { /* Assistant become inactive */ if (mIsAssistantActive && mPausedBroadcastSinks.isEmpty()) { mIsAssistantActive = false; mUnicastSourceStreamStatus = Optional.empty(); leAudioService.activeBroadcastAssistantNotification(false); return; } } } private void setSourceGroupManaged(BluetoothDevice sink, int sourceId, boolean isGroupOp) { log("setSourceGroupManaged device: " + sink); if (isGroupOp) { Loading Loading @@ -1231,10 +1320,17 @@ public class BassClientService extends ProfileService { * @param isGroupOp set to true If Application wants to perform this operation for all * coordinated set members, False otherwise */ public void addSource(BluetoothDevice sink, BluetoothLeBroadcastMetadata sourceMetadata, public void addSource( BluetoothDevice sink, BluetoothLeBroadcastMetadata sourceMetadata, boolean isGroupOp) { log("addSource: device: " + sink + " sourceMetadata" + sourceMetadata + " isGroupOp: " + isGroupOp); log( "addSource: device: " + sink + " sourceMetadata" + sourceMetadata + " isGroupOp: " + isGroupOp); List<BluetoothDevice> devices = getTargetDeviceList(sink, isGroupOp); // Don't coordinate it as a group if there's no group or there is one device only Loading @@ -1247,6 +1343,13 @@ public class BassClientService extends ProfileService { return; } if (!isAllowedToAddSource()) { Log.d(TAG, "Add source to pending list"); mPendingAddSources.push(new AddSourceData(sink, sourceMetadata, isGroupOp)); return; } byte[] code = sourceMetadata.getBroadcastCode(); for (BluetoothDevice device : devices) { BassClientStateMachine stateMachine = getOrCreateStateMachine(device); Loading Loading @@ -1592,13 +1695,14 @@ public class BassClientService extends ProfileService { } } private void stopLocalSourceReceivers(int broadcastId, boolean store) { private void stopSourceReceivers(int broadcastId, boolean store) { if (DBG) { Log.d(TAG, "stopLocalSourceReceivers()"); Log.d(TAG, "stopSourceReceivers(), broadcastId: " + broadcastId + ", store: " + store); } if (store && !mPausedBroadcastSinks.isEmpty()) { Log.w(TAG, "stopLocalSourceReceivers(), paused broadcast sinks are replaced"); Log.w(TAG, "stopSourceReceivers(), paused broadcast sinks are replaced"); sEventLogger.logd(DBG, TAG, "Clear broadcast sinks paused cache"); mPausedBroadcastSinks.clear(); } Loading @@ -1606,44 +1710,130 @@ public class BassClientService extends ProfileService { for (BluetoothDevice device : getConnectedDevices()) { for (BluetoothLeBroadcastReceiveState receiveState : getAllSources(device)) { /* Check if local/last broadcast is the synced one */ if (receiveState.getBroadcastId() != broadcastId) continue; /* Check if local/last broadcast is the synced one. Invalid broadcast ID means * that all receivers should be considered. */ if ((broadcastId != BassConstants.INVALID_BROADCAST_ID) && (receiveState.getBroadcastId() != broadcastId)) { continue; } if (store && !mPausedBroadcastSinks.contains(device)) { sEventLogger.logd(DBG, TAG, "Add broadcast sink to paused cache: " + device); mPausedBroadcastSinks.add(device); } sourcesToRemove.put(device, receiveState.getSourceId()); } } for (Map.Entry<BluetoothDevice, Integer> entry : sourcesToRemove.entrySet()) { removeSource(entry.getKey(), entry.getValue()); } } private boolean isAllowedToAddSource() { if (mFeatureFlags.leaudioBroadcastAudioHandoverPolicies()) { /* Check if should wait for status update */ if (mUnicastSourceStreamStatus.isEmpty()) { /* Assistant was not active, inform about activation */ if (!mIsAssistantActive) { mIsAssistantActive = true; LeAudioService leAudioService = mServiceFactory.getLeAudioService(); if (leAudioService != null) { leAudioService.activeBroadcastAssistantNotification(true); } } return false; } return mUnicastSourceStreamStatus.get() == STATUS_LOCAL_STREAM_SUSPENDED; } /* Don't block if this is not a handover case */ return true; } private boolean isAnyReceiverReceivingBroadcast() { for (BluetoothDevice device : getConnectedDevices()) { for (BluetoothLeBroadcastReceiveState receiveState : getAllSources(device)) { for (int i = 0; i < receiveState.getNumSubgroups(); i++) { Long syncState = receiveState.getBisSyncState().get(i); /* Not synced to BIS of failed to sync to BIG */ if (syncState == 0x00000000 || syncState == 0xFFFFFFFF) { continue; } return true; } } } return false; } /** Request receivers to suspend broadcast sources synchronization */ public void suspendReceiversSourceSynchronization(int broadcastId) { sEventLogger.logd(DBG, TAG, "Suspend receivers source synchronization: " + broadcastId); stopLocalSourceReceivers(broadcastId, true); stopSourceReceivers(broadcastId, true); } /** Request all receivers to suspend broadcast sources synchronization */ public void suspendAllReceiversSourceSynchronization() { sEventLogger.logd(DBG, TAG, "Suspend all receivers source synchronization"); stopSourceReceivers(BassConstants.INVALID_BROADCAST_ID, true); } /** Request receivers to stop broadcast sources synchronization and remove them */ public void stopReceiversSourceSynchronization(int broadcastId) { sEventLogger.logd(DBG, TAG, "Stop receivers source synchronization: " + broadcastId); stopLocalSourceReceivers(broadcastId, false); stopSourceReceivers(broadcastId, false); } /** Request receivers to resume broadcast source synchronization */ public void resumeReceiversSourceSynchronization(int broadcastId) { sEventLogger.logd(DBG, TAG, "Resume receivers source synchronization: " + broadcastId); public void resumeReceiversSourceSynchronization() { sEventLogger.logd(DBG, TAG, "Resume receivers source synchronization"); while (!mPausedBroadcastSinks.isEmpty()) { BluetoothDevice sink = mPausedBroadcastSinks.remove(); sEventLogger.logd(DBG, TAG, "Remove broadcast sink from paused cache: " + sink); BluetoothLeBroadcastMetadata metadata = mBroadcastMetadataMap.get(sink); if (metadata != null) { addSource(sink, metadata, true); addSource(sink, metadata, false); } } } /** Handle Unicast source stream status change */ public void handleUnicastSourceStreamStatusChange(int status) { mUnicastSourceStreamStatus = Optional.of(status); if (status == STATUS_LOCAL_STREAM_REQUESTED) { if (isAnyReceiverReceivingBroadcast()) { suspendAllReceiversSourceSynchronization(); } } else if (status == STATUS_LOCAL_STREAM_SUSPENDED) { /* Resume paused receivers if there are some */ if (!mPausedBroadcastSinks.isEmpty()) { resumeReceiversSourceSynchronization(); } /* Add pending sources if there are some */ while (!mPendingAddSources.isEmpty()) { AddSourceData addSourceData = mPendingAddSources.pop(); addSource( addSourceData.mSink, addSourceData.mSourceMetadata, addSourceData.mIsGroupOp); } } else if (status == STATUS_LOCAL_STREAM_STREAMING) { Log.d(TAG, "Ignore STREAMING source status"); } } Loading Loading @@ -1912,6 +2102,9 @@ public class BassClientService extends ProfileService { void notifyReceiveStateChanged(BluetoothDevice sink, int sourceId, BluetoothLeBroadcastReceiveState state) { ObjParams param = new ObjParams(sink, state); sService.localNotifyReceiveStateChanged(); String subgroupState = " / SUB GROUPS: "; for (int i = 0; i < state.getNumSubgroups(); i++) { subgroupState += "IDX: " + i + ", SYNC: " + state.getBisSyncState().get(i); Loading
android/app/src/com/android/bluetooth/btservice/AdapterService.java +1 −1 Original line number Diff line number Diff line Loading @@ -127,7 +127,7 @@ import com.android.bluetooth.btservice.storage.MetadataDatabase; import com.android.bluetooth.csip.CsipSetCoordinatorService; import com.android.bluetooth.flags.FeatureFlagsImpl; import com.android.bluetooth.gatt.GattService; import com.android.bluetooth.gatt.ScanManager; import com.android.bluetooth.le_scan.ScanManager; import com.android.bluetooth.hap.HapClientService; import com.android.bluetooth.hearingaid.HearingAidService; import com.android.bluetooth.hfp.HeadsetService; Loading
android/app/src/com/android/bluetooth/btservice/storage/CustomizedMetadataEntity.java +4 −2 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ class CustomizedMetadataEntity { public byte[] le_audio; public byte[] gmcs_cccd; public byte[] gtbs_cccd; public byte[] exclusive_manager; public String toString() { StringBuilder builder = new StringBuilder(); Loading Loading @@ -109,8 +110,9 @@ class CustomizedMetadataEntity { .append("|gmcs_cccd=") .append(metadataToString(gmcs_cccd)) .append("|gtbs_cccd=") .append(metadataToString(gtbs_cccd)); .append(metadataToString(gtbs_cccd)) .append("|exclusive_manager=") .append(metadataToString(exclusive_manager)); return builder.toString(); } Loading
android/app/src/com/android/bluetooth/btservice/storage/Metadata.java +6 −0 Original line number Diff line number Diff line Loading @@ -349,6 +349,9 @@ public class Metadata { case BluetoothDevice.METADATA_GTBS_CCCD: publicMetadata.gtbs_cccd = value; break; case BluetoothDevice.METADATA_EXCLUSIVE_MANAGER: publicMetadata.exclusive_manager = value; break; } } Loading Loading @@ -446,6 +449,9 @@ public class Metadata { case BluetoothDevice.METADATA_GTBS_CCCD: value = publicMetadata.gtbs_cccd; break; case BluetoothDevice.METADATA_EXCLUSIVE_MANAGER: value = publicMetadata.exclusive_manager; break; } return value; } Loading