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

Commit 68043b02 authored by Andy Hung's avatar Andy Hung Committed by Gerrit Code Review
Browse files

Merge "Spatializer: Fix usb headset"

parents a12efe5b 12f9b9fa
Loading
Loading
Loading
Loading
+114 −140
Original line number Diff line number Diff line
@@ -46,6 +46,8 @@ import android.util.Log;
import android.util.Pair;
import android.util.SparseIntArray;

import com.android.internal.annotations.GuardedBy;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
@@ -103,10 +105,6 @@ public class SpatializerHelper {
            AudioDeviceInfo.TYPE_BLE_BROADCAST
    };

    private static final int[] WIRELESS_SPEAKER_TYPES = {
            AudioDeviceInfo.TYPE_BLE_SPEAKER,
    };

    // Spatializer state machine
    private static final int STATE_UNINITIALIZED = 0;
    private static final int STATE_NOT_SUPPORTED = 1;
@@ -166,6 +164,7 @@ public class SpatializerHelper {
     * List of devices where Spatial Audio is possible. Each device can be enabled or disabled
     * (== user choice to use or not)
     */
    @GuardedBy("this")
    private final ArrayList<SADeviceState> mSADevices = new ArrayList<>(0);

    //------------------------------------------------------
@@ -521,30 +520,30 @@ public class SpatializerHelper {
     *                    set to true if the device is added to the list, otherwise, if already
     *                    present, the setting is left untouched.
     */
    @GuardedBy("this")
    private void addCompatibleAudioDevice(@NonNull AudioDeviceAttributes ada,
            boolean forceEnable) {
        if (!isDeviceCompatibleWithSpatializationModes(ada)) {
            return;
        }
        loglogi("addCompatibleAudioDevice: dev=" + ada);
        boolean isInList = false;
        final SADeviceState deviceState = findDeviceStateForAudioDeviceAttributes(ada);
        SADeviceState deviceUpdated = null; // non-null on update.

        for (SADeviceState deviceState : mSADevices) {
            if (deviceState.matchesAudioDeviceAttributes(ada)) {
                isInList = true;
                if (forceEnable) {
                    deviceState.mEnabled = true;
        if (deviceState != null) {
            if (forceEnable && !deviceState.mEnabled) {
                deviceUpdated = deviceState;
                deviceUpdated.mEnabled = true;
            }
                break;
        } else {
            // When adding, force the device type to be a canonical one.
            final int canonicalDeviceType = getCanonicalDeviceType(ada.getType());
            if (canonicalDeviceType == AudioDeviceInfo.TYPE_UNKNOWN) {
                Log.e(TAG, "addCompatibleAudioDevice with incompatible AudioDeviceAttributes "
                        + ada);
                return;
            }
        }
        if (!isInList) {
            final SADeviceState deviceState = new SADeviceState(ada.getType(), ada.getAddress());
            deviceState.mEnabled = true;
            mSADevices.add(deviceState);
            deviceUpdated = deviceState;
            deviceUpdated = new SADeviceState(canonicalDeviceType, ada.getAddress());
            mSADevices.add(deviceUpdated);
        }
        if (deviceUpdated != null) {
            onRoutingUpdated();
@@ -575,20 +574,50 @@ public class SpatializerHelper {

    synchronized void removeCompatibleAudioDevice(@NonNull AudioDeviceAttributes ada) {
        loglogi("removeCompatibleAudioDevice: dev=" + ada);
        SADeviceState deviceUpdated = null; // non-null on update.

        for (SADeviceState deviceState : mSADevices) {
            if (deviceState.matchesAudioDeviceAttributes(ada)) {
        final SADeviceState deviceState = findDeviceStateForAudioDeviceAttributes(ada);
        if (deviceState != null && deviceState.mEnabled) {
            deviceState.mEnabled = false;
                deviceUpdated = deviceState;
                break;
            }
        }
        if (deviceUpdated != null) {
            onRoutingUpdated();
            mAudioService.persistSpatialAudioDeviceSettings();
            logDeviceState(deviceUpdated, "removeCompatibleAudioDevice");
            logDeviceState(deviceState, "removeCompatibleAudioDevice");
        }
    }

    /**
     * Returns a possibly aliased device type which is used
     * for spatial audio settings (or TYPE_UNKNOWN  if it doesn't exist).
     */
    private static @AudioDeviceInfo.AudioDeviceType int getCanonicalDeviceType(int deviceType) {
        if (isWireless(deviceType)) return deviceType;

        final int spatMode = SPAT_MODE_FOR_DEVICE_TYPE.get(deviceType, Integer.MIN_VALUE);
        if (spatMode == SpatializationMode.SPATIALIZER_TRANSAURAL) {
            return AudioDeviceInfo.TYPE_BUILTIN_SPEAKER;
        } else if (spatMode == SpatializationMode.SPATIALIZER_BINAURAL) {
            return AudioDeviceInfo.TYPE_WIRED_HEADPHONES;
        }
        return AudioDeviceInfo.TYPE_UNKNOWN;
    }

    /**
     * Returns the Spatial Audio device state for an audio device attributes
     * or null if it does not exist.
     */
    @GuardedBy("this")
    @Nullable
    private SADeviceState findDeviceStateForAudioDeviceAttributes(AudioDeviceAttributes ada) {
        final int deviceType = ada.getType();
        final boolean isWireless = isWireless(deviceType);
        final int canonicalDeviceType = getCanonicalDeviceType(deviceType);

        for (SADeviceState deviceState : mSADevices) {
            if (deviceState.mDeviceType == canonicalDeviceType
                    && (!isWireless || ada.getAddress().equals(deviceState.mDeviceAddress))) {
                return deviceState;
            }
        }
        return null;
    }

    /**
@@ -597,12 +626,7 @@ public class SpatializerHelper {
     * @return a pair of boolean, 1/ enabled? 2/ available?
     */
    private synchronized Pair<Boolean, Boolean> evaluateState(AudioDeviceAttributes ada) {
        // if not a wireless device, this value will be overwritten to map the type
        // to TYPE_BUILTIN_SPEAKER or TYPE_WIRED_HEADPHONES
        @AudioDeviceInfo.AudioDeviceType int deviceType = ada.getType();

        // if not a wireless device: find if media device is in the speaker, wired headphones
        if (!isWireless(deviceType)) {
        final @AudioDeviceInfo.AudioDeviceType int deviceType = ada.getType();
        // is the device type capable of doing SA?
        if (!mSACapableDeviceTypes.contains(deviceType)) {
            Log.i(TAG, "Device incompatible with Spatial Audio dev:" + ada);
@@ -615,50 +639,30 @@ public class SpatializerHelper {
            Log.e(TAG, "no spatialization mode found for device type:" + deviceType);
            return new Pair<>(false, false);
        }
            // map the spatialization mode to the SPEAKER or HEADPHONES device
            if (spatMode == SpatializationMode.SPATIALIZER_TRANSAURAL) {
                deviceType = AudioDeviceInfo.TYPE_BUILTIN_SPEAKER;
            } else {
                deviceType = AudioDeviceInfo.TYPE_WIRED_HEADPHONES;
            }
        } else { // wireless device
            if (isWirelessSpeaker(deviceType) && !mTransauralSupported) {
                Log.i(TAG, "Device incompatible with Spatial Audio (no transaural) dev:"
                        + ada);
        final SADeviceState deviceState = findDeviceStateForAudioDeviceAttributes(ada);
        if (deviceState == null) {
            // no matching device state?
            Log.i(TAG, "no spatialization device state found for Spatial Audio device:" + ada);
            return new Pair<>(false, false);
        }
            if (!mBinauralSupported) {
                Log.i(TAG, "Device incompatible with Spatial Audio (no binaural) dev:"
                        + ada);
                return new Pair<>(false, false);
            }
        }

        boolean enabled = false;
        boolean available = false;
        for (SADeviceState deviceState : mSADevices) {
            if (deviceState.matchesAudioDeviceAttributes(ada)) {
                available = true;
                enabled = deviceState.mEnabled;
                break;
            }
        }
        return new Pair<>(enabled, available);
        // found the matching device state.
        return new Pair<>(deviceState.mEnabled, true /* available */);
    }

    private synchronized void addWirelessDeviceIfNew(@NonNull AudioDeviceAttributes ada) {
        if (!isDeviceCompatibleWithSpatializationModes(ada)) {
            return;
        }
        boolean knownDevice = false;
        for (SADeviceState deviceState : mSADevices) {
            if (deviceState.matchesAudioDeviceAttributes(ada)) {
                knownDevice = true;
                break;
            }
        if (findDeviceStateForAudioDeviceAttributes(ada) == null) {
            // wireless device types should be canonical, but we translate to be sure.
            final int canonicalDeviceType = getCanonicalDeviceType((ada.getType()));
            if (canonicalDeviceType == AudioDeviceInfo.TYPE_UNKNOWN) {
                Log.e(TAG, "addWirelessDeviceIfNew with incompatible AudioDeviceAttributes "
                        + ada);
                return;
            }
        if (!knownDevice) {
            final SADeviceState deviceState = new SADeviceState(ada.getType(), ada.getAddress());
            final SADeviceState deviceState =
                    new SADeviceState(canonicalDeviceType, ada.getAddress());
            mSADevices.add(deviceState);
            mAudioService.persistSpatialAudioDeviceSettings();
            logDeviceState(deviceState, "addWirelessDeviceIfNew"); // may be updated later.
@@ -700,12 +704,7 @@ public class SpatializerHelper {
        if (ada.getRole() != AudioDeviceAttributes.ROLE_OUTPUT) {
            return false;
        }
        for (SADeviceState deviceState : mSADevices) {
            if (deviceState.matchesAudioDeviceAttributes(ada)) {
                return true;
            }
        }
        return false;
        return findDeviceStateForAudioDeviceAttributes(ada) != null;
    }

    private synchronized boolean canBeSpatializedOnDevice(@NonNull AudioAttributes attributes,
@@ -1086,8 +1085,8 @@ public class SpatializerHelper {
            Log.v(TAG, "no headtracking support, ignoring setHeadTrackerEnabled to " + enabled
                    + " for " + ada);
        }
        for (SADeviceState deviceState : mSADevices) {
            if (deviceState.matchesAudioDeviceAttributes(ada)) {
        final SADeviceState deviceState = findDeviceStateForAudioDeviceAttributes(ada);
        if (deviceState == null) return;
        if (!deviceState.mHasHeadTracker) {
            Log.e(TAG, "Called setHeadTrackerEnabled enabled:" + enabled
                    + " device:" + ada + " on a device without headtracker");
@@ -1097,9 +1096,7 @@ public class SpatializerHelper {
        deviceState.mHeadTrackerEnabled = enabled;
        mAudioService.persistSpatialAudioDeviceSettings();
        logDeviceState(deviceState, "setHeadTrackerEnabled");
                break;
            }
        }

        // check current routing to see if it affects the headtracking mode
        if (ROUTING_DEVICES[0] != null && ROUTING_DEVICES[0].getType() == ada.getType()
                && ROUTING_DEVICES[0].getAddress().equals(ada.getAddress())) {
@@ -1116,12 +1113,8 @@ public class SpatializerHelper {
            Log.v(TAG, "no headtracking support, hasHeadTracker always false for " + ada);
            return false;
        }
        for (SADeviceState deviceState : mSADevices) {
            if (deviceState.matchesAudioDeviceAttributes(ada)) {
                return deviceState.mHasHeadTracker;
            }
        }
        return false;
        final SADeviceState deviceState = findDeviceStateForAudioDeviceAttributes(ada);
        return deviceState != null && deviceState.mHasHeadTracker;
    }

    /**
@@ -1134,8 +1127,8 @@ public class SpatializerHelper {
            Log.v(TAG, "no headtracking support, setHasHeadTracker always false for " + ada);
            return false;
        }
        for (SADeviceState deviceState : mSADevices) {
            if (deviceState.matchesAudioDeviceAttributes(ada)) {
        final SADeviceState deviceState = findDeviceStateForAudioDeviceAttributes(ada);
        if (deviceState != null) {
            if (!deviceState.mHasHeadTracker) {
                deviceState.mHasHeadTracker = true;
                mAudioService.persistSpatialAudioDeviceSettings();
@@ -1143,7 +1136,6 @@ public class SpatializerHelper {
            }
            return deviceState.mHeadTrackerEnabled;
        }
        }
        Log.e(TAG, "setHasHeadTracker: device not found for:" + ada);
        return false;
    }
@@ -1153,15 +1145,9 @@ public class SpatializerHelper {
            Log.v(TAG, "no headtracking support, isHeadTrackerEnabled always false for " + ada);
            return false;
        }
        for (SADeviceState deviceState : mSADevices) {
            if (deviceState.matchesAudioDeviceAttributes(ada)) {
                if (!deviceState.mHasHeadTracker) {
                    return false;
                }
                return deviceState.mHeadTrackerEnabled;
            }
        }
        return false;
        final SADeviceState deviceState = findDeviceStateForAudioDeviceAttributes(ada);
        return deviceState != null
                && deviceState.mHasHeadTracker && deviceState.mHeadTrackerEnabled;
    }

    synchronized boolean isHeadTrackerAvailable() {
@@ -1585,12 +1571,6 @@ public class SpatializerHelper {
                    mDeviceType, mDeviceAddress == null ? "" : mDeviceAddress);
        }

        public boolean matchesAudioDeviceAttributes(AudioDeviceAttributes ada) {
            final int deviceType = ada.getType();
            final boolean wireless = isWireless(deviceType);
            return (deviceType == mDeviceType)
                        && (!wireless || ada.getAddress().equals(mDeviceAddress));
        }
    }

    /*package*/ synchronized String getSADeviceSettings() {
@@ -1611,7 +1591,10 @@ public class SpatializerHelper {
        // small list, not worth overhead of Arrays.stream(devSettings)
        for (String setting : devSettings) {
            SADeviceState devState = SADeviceState.fromPersistedString(setting);
            // Note if the device is not compatible with spatialization mode
            // or the device type is not canonical, it is ignored.
            if (devState != null
                    && devState.mDeviceType == getCanonicalDeviceType(devState.mDeviceType)
                    && isDeviceCompatibleWithSpatializationModes(
                            devState.getAudioDeviceAttributes())) {
                mSADevices.add(devState);
@@ -1648,15 +1631,6 @@ public class SpatializerHelper {
        return false;
    }

    private static boolean isWirelessSpeaker(@AudioDeviceInfo.AudioDeviceType int deviceType) {
        for (int type : WIRELESS_SPEAKER_TYPES) {
            if (type == deviceType) {
                return true;
            }
        }
        return false;
    }

    private int getHeadSensorHandleUpdateTracker() {
        int headHandle = -1;
        final AudioDeviceAttributes currentDevice = ROUTING_DEVICES[0];