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

Commit 31f344d2 authored by Jakub Pawlowski's avatar Jakub Pawlowski Committed by Gerrit Code Review
Browse files

Merge "leaudio: Improve set active device"

parents bd2b531a 36d9682d
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -218,12 +218,24 @@ static jboolean disconnectLeAudioNative(JNIEnv* env, jobject object,
  return JNI_TRUE;
}

static void groupSetActiveNative(JNIEnv* env, jobject object, jint group_id) {
  LOG(INFO) << __func__;

  if (!sLeAudioClientInterface) {
    LOG(ERROR) << __func__ << ": Failed to get the Bluetooth LeAudio Interface";
    return;
  }

  sLeAudioClientInterface->GroupSetActive(group_id);
}

static JNINativeMethod sMethods[] = {
    {"classInitNative", "()V", (void*)classInitNative},
    {"initNative", "()V", (void*)initNative},
    {"cleanupNative", "()V", (void*)cleanupNative},
    {"connectLeAudioNative", "([B)Z", (void*)connectLeAudioNative},
    {"disconnectLeAudioNative", "([B)Z", (void*)disconnectLeAudioNative},
    {"groupSetActiveNative", "(I)V", (void*)groupSetActiveNative},
};

int register_com_android_bluetooth_le_audio(JNIEnv* env) {
+9 −0
Original line number Diff line number Diff line
@@ -176,10 +176,19 @@ public class LeAudioNativeInterface {
        return disconnectLeAudioNative(getByteAddress(device));
    }

    /**
     * Set active group.
     * @param groupId group ID to set as active
     */
    public void groupSetActive(int groupId) {
        groupSetActiveNative(groupId);
    }

    // Native methods that call into the JNI interface
    private static native void classInitNative();
    private native void initNative();
    private native void cleanupNative();
    private native boolean connectLeAudioNative(byte[] address);
    private native boolean disconnectLeAudioNative(byte[] address);
    private native void groupSetActiveNative(int groupId);
}
+151 −74
Original line number Diff line number Diff line
@@ -435,104 +435,161 @@ public class LeAudioService extends ProfileService {
        return supportedAudioDirections;
    }

    private BluetoothDevice getFirstConnectedDeviceFromGroup(Integer groupId) {
    private BluetoothDevice getFirstDeviceFromGroup(Integer groupId) {
        if (groupId != LE_AUDIO_GROUP_ID_INVALID) {
            for(Map.Entry<BluetoothDevice, Integer> entry : mDeviceGroupIdMap.entrySet()) {
                if ((entry.getValue() == groupId) && (entry.getKey().isConnected())) {
                    return entry.getKey();
                if (entry.getValue() != groupId) {
                    continue;
                }

                LeAudioStateMachine sm = mStateMachines.get(entry.getKey());
                if (sm == null || sm.getConnectionState() != BluetoothProfile.STATE_CONNECTED) {
                    continue;
                }

                return entry.getKey();
            }
        }

        return null;
    }

    /**
     * Report the active devices change to the active device manager and the media framework.
     * @param groupId id of group which devices should be updated
     * @param newActiveContexts new active contexts for group of devices
     */
    private void updateActiveDevices(Integer groupId, Integer oldActiveContexts,
    private void updateActiveInDevice(BluetoothDevice device, Integer groupId, Integer oldActiveContexts,
    Integer newActiveContexts) {
        LeAudioGroupDescriptor descriptor = mGroupDescriptors.get(groupId);
        if (descriptor == null) {
            Log.w(TAG, "Invalid group id: " + String.valueOf(groupId));
            return;
        }

        BluetoothDevice device = getFirstConnectedDeviceFromGroup(groupId);

        Integer oldSupportedAudioDirections =
                getAudioDirectionsFromActiveContextsMap(oldActiveContexts);
        boolean oldSupportedByDeviceOutput = (oldSupportedAudioDirections
                & AUDIO_DIRECTION_OUTPUT_BIT) != 0;
        Integer newSupportedAudioDirections =
                getAudioDirectionsFromActiveContextsMap(newActiveContexts);

        boolean oldSupportedByDeviceInput = (oldSupportedAudioDirections
                & AUDIO_DIRECTION_INPUT_BIT) != 0;
        boolean newSupportedByDeviceInput = (newSupportedAudioDirections
                & AUDIO_DIRECTION_INPUT_BIT) != 0;

        if (device != null && mPreviousAudioInDevice != null) {
            int previousGroupId = getGroupId(mPreviousAudioInDevice);
            if (previousGroupId == groupId) {
                /* This is thes same group as aleady notified to the system.
                * Therefore do not change the device we have connected to the group,
                * unless, previous one is disconnected now
                */
                if (mPreviousAudioInDevice.isConnected())
                    device = mPreviousAudioInDevice;
            }
        }

        /* Disconnect input:
         * - If active input device changed (to none or any)
         * - If device stops supporting input
         */
        boolean inActiveDeviceReplace = (device != mPreviousAudioInDevice);
        if (mPreviousAudioInDevice != null) {
            mAudioManager.setBluetoothLeAudioInDeviceConnectionState(
                    mPreviousAudioInDevice, BluetoothProfile.STATE_DISCONNECTED);
        }

        mPreviousAudioInDevice = device;

        if (device == null) {
            Log.d(TAG,  " device is null.");
            return;
        }

        if (inActiveDeviceReplace == false ||
             (oldSupportedByDeviceInput == newSupportedByDeviceInput)) {
            Log.d(TAG,  " Nothing to do.");
            return;
        }

        /* Connect input:
         * - If active input device changed
         * - If device starts support input
         */
        mAudioManager.setBluetoothLeAudioInDeviceConnectionState(
                   device, BluetoothProfile.STATE_CONNECTED);

    }

    private void updateActiveOutDevice(BluetoothDevice device, Integer groupId,
                                       Integer oldActiveContexts,
                                       Integer newActiveContexts) {
        Integer oldSupportedAudioDirections =
                getAudioDirectionsFromActiveContextsMap(oldActiveContexts);
        Integer newSupportedAudioDirections =
                getAudioDirectionsFromActiveContextsMap(newActiveContexts);

        boolean oldSupportedByDeviceOutput = (oldSupportedAudioDirections
                & AUDIO_DIRECTION_OUTPUT_BIT) != 0;
        boolean newSupportedByDeviceOutput = (newSupportedAudioDirections
                & AUDIO_DIRECTION_OUTPUT_BIT) != 0;
        boolean newSupportedByDeviceInput = (newSupportedAudioDirections
                & AUDIO_DIRECTION_INPUT_BIT) != 0;


        if (device != null && mPreviousAudioOutDevice != null) {
            int previousGroupId = getGroupId(mPreviousAudioOutDevice);
            if (previousGroupId == groupId) {
                /* This is thes same group as aleady notified to the system.
                * Therefore do not change the device we have connected to the group,
                * unless, previous one is disconnected now
                */
             if (mPreviousAudioOutDevice.isConnected())
                device = mPreviousAudioOutDevice;
            }
        }

         /* Disconnect output:
         * - If active output device changed (to none or any)
         * - If device stops supporting output
         */
        boolean outActiveDeviceReplace = (mPreviousAudioOutDevice != null) &&
                !(device == mPreviousAudioOutDevice);
        if (outActiveDeviceReplace || (oldSupportedByDeviceOutput && !newSupportedByDeviceOutput)) {
        boolean outActiveDeviceReplace = (device != mPreviousAudioOutDevice);
        if (mPreviousAudioOutDevice != null) {
            boolean suppressNoisyIntent =
                    (getConnectionState(mPreviousAudioOutDevice) ==
                    BluetoothProfile.STATE_CONNECTED);
            mAudioManager.setBluetoothLeAudioOutDeviceConnectionState(
                    mPreviousAudioOutDevice, BluetoothProfile.STATE_DISCONNECTED,
                    suppressNoisyIntent);
            mPreviousAudioOutDevice = null;
        }

        mPreviousAudioOutDevice = device;

        if (device == null) {
            Log.d(TAG,  " device is null.");
            return;
        }

        if (outActiveDeviceReplace == false ||
            (oldSupportedByDeviceOutput == newSupportedByDeviceOutput)) {
            Log.d(TAG,  " Nothing to do.");
            return;
        }

        /* Connect output:
         * - If active output device changed
         * - If device starts support output
         */
        if ((outActiveDeviceReplace && (device != null)) ||
                (!oldSupportedByDeviceOutput && newSupportedByDeviceOutput)) {
         mAudioManager.setBluetoothLeAudioOutDeviceConnectionState(
                    device, BluetoothProfile.STATE_CONNECTED, true);
            mPreviousAudioOutDevice = device;
    }

        /* Disconnect input:
         * - If active input device changed (to none or any)
         * - If device stops supporting input
    /**
     * Report the active devices change to the active device manager and the media framework.
     * @param groupId id of group which devices should be updated
     * @param newActiveContexts new active contexts for group of devices
     */
        boolean inActiveDeviceReplace = (mPreviousAudioInDevice != null) &&
                !(device == mPreviousAudioInDevice);
        if (inActiveDeviceReplace || (oldSupportedByDeviceInput && !newSupportedByDeviceInput)) {
            mAudioManager.setBluetoothLeAudioInDeviceConnectionState(
                    mPreviousAudioInDevice, BluetoothProfile.STATE_DISCONNECTED);
            mPreviousAudioInDevice = null;
        }
    private void updateActiveDevices(Integer groupId, Integer oldActiveContexts,
            Integer newActiveContexts, boolean isActive) {

        /* Connect input:
         * - If active input device changed
         * - If device starts support input
         */
        if ((inActiveDeviceReplace && (device != null)) ||
                (!oldSupportedByDeviceInput && newSupportedByDeviceInput)) {
            mAudioManager.setBluetoothLeAudioInDeviceConnectionState(
                   device, BluetoothProfile.STATE_CONNECTED);
            mPreviousAudioInDevice = device;
        }
        BluetoothDevice device = null;

        if (isActive)
            device = getFirstDeviceFromGroup(groupId);

        updateActiveOutDevice(device, groupId, oldActiveContexts, newActiveContexts);
        updateActiveInDevice(device, groupId, oldActiveContexts, newActiveContexts);

        Intent intent = new Intent(BluetoothLeAudio.ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED);
        if ((mPreviousAudioInDevice == null) && (mPreviousAudioOutDevice == null)) {
            /* Device has to be unabigous, represented by empty BluetoothDevice */
        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mPreviousAudioOutDevice);
        } else {
            intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
        }
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
                | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
        sendBroadcast(intent, BLUETOOTH_CONNECT);
@@ -558,6 +615,7 @@ public class LeAudioService extends ProfileService {
            return;
        }

        mLeAudioNativeInterface.groupSetActive(groupId);
        mActiveDeviceGroupId = groupId;
    }

@@ -679,7 +737,8 @@ public class LeAudioService extends ProfileService {
            LeAudioGroupDescriptor descriptor = mGroupDescriptors.get(group_id);
            if (descriptor != null) {
                if (descriptor.mIsActive) {
                    updateActiveDevices(group_id, descriptor.mActiveContexts, available_contexts);
                    updateActiveDevices(group_id, descriptor.mActiveContexts,
                                        available_contexts, descriptor.mIsActive);
                }
                descriptor.mActiveContexts = available_contexts;
            } else {
@@ -708,9 +767,9 @@ public class LeAudioService extends ProfileService {
                    LeAudioGroupDescriptor descriptor = mGroupDescriptors.get(group_id);
                    if (descriptor != null) {
                        if (!descriptor.mIsActive) {
                            updateActiveDevices(group_id, ACTIVE_CONTEXTS_NONE,
                                    descriptor.mActiveContexts);
                            descriptor.mIsActive = true;
                            updateActiveDevices(group_id, ACTIVE_CONTEXTS_NONE,
                                                descriptor.mActiveContexts, descriptor.mIsActive);
                        }
                    } else {
                        Log.e(TAG, "no descriptors for group: " + group_id);
@@ -721,9 +780,9 @@ public class LeAudioService extends ProfileService {
                    LeAudioGroupDescriptor descriptor = mGroupDescriptors.get(group_id);
                    if (descriptor != null) {
                        if (descriptor.mIsActive) {
                            updateActiveDevices(group_id, descriptor.mActiveContexts,
                                    ACTIVE_CONTEXTS_NONE);
                            descriptor.mIsActive = false;
                            updateActiveDevices(group_id, descriptor.mActiveContexts,
                                    ACTIVE_CONTEXTS_NONE, descriptor.mIsActive);
                        }
                    } else {
                        Log.e(TAG, "no descriptors for group: " + group_id);
@@ -871,17 +930,6 @@ public class LeAudioService extends ProfileService {
                mcpService.setDeviceAuthorized(device, true);
            }
        }
        if (fromState == BluetoothProfile.STATE_CONNECTED && getConnectedDevices().isEmpty()) {
            setActiveDevice(null);
            int myGroupId = getGroupId(device);

            LeAudioGroupDescriptor descriptor = mGroupDescriptors.get(myGroupId);
            if (descriptor != null) {
                descriptor.mIsConnected = true;
            } else {
                Log.e(TAG, "no descriptors for group: " + myGroupId);
            }
        }
        // Check if the device is disconnected - if unbond, remove the state machine
        if (toState == BluetoothProfile.STATE_DISCONNECTED) {
            int bondState = mAdapterService.getBondState(device);
@@ -896,6 +944,35 @@ public class LeAudioService extends ProfileService {
            if (mcpService != null) {
                mcpService.setDeviceAuthorized(device, false);
            }

            int myGroupId = getGroupId(device);
            LeAudioGroupDescriptor descriptor = mGroupDescriptors.get(myGroupId);
            if (descriptor == null) {
                Log.e(TAG, "no descriptors for group: " + myGroupId);
                return;
            }

            if (getConnectedDevices().isEmpty()){
                descriptor.mIsConnected = false;
                if (descriptor.mIsActive) {
                    /* Notify Native layer */
                    setActiveDevice(null);
                    descriptor.mIsActive = false;
                    /* Update audio framework */
                    updateActiveDevices(myGroupId,
                                    descriptor.mActiveContexts,
                                    descriptor.mActiveContexts,
                                    descriptor.mIsActive);
                    return;
                }
            }

            if (descriptor.mIsActive) {
                updateActiveDevices(myGroupId,
                                    descriptor.mActiveContexts,
                                    descriptor.mActiveContexts,
                                    descriptor.mIsActive);
            }
        }
    }