Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1bba3808 authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Snap for 11355999 from 542e1901 to 24Q2-release

Change-Id: Ib81efa285417184fba3436e0a9bcb2bc24bfe359
parents c3ed372a 542e1901
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -326,6 +326,9 @@
    {
      "name": "bluetooth_test_gdx_unit"
    },
    {
      "name": "CtsStrictJavaPackagesTestCases"
    },
    {
      "name": "asrc_resampler_test"
    }
+207 −14
Original line number Diff line number Diff line
@@ -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;
@@ -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<>();
@@ -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;
@@ -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 =
@@ -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,
@@ -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);
@@ -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
@@ -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:
@@ -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) {
@@ -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
@@ -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);
@@ -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();
        }

@@ -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");
        }
    }

@@ -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);
+1 −1
Original line number Diff line number Diff line
@@ -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;
+4 −2
Original line number Diff line number Diff line
@@ -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();
@@ -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();
    }
+6 −0
Original line number Diff line number Diff line
@@ -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;
        }
    }

@@ -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