Merge "Spatializer: Fix usb headset" into tm-qpr-dev am: 77e1313118

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/19374318

Change-Id: Ib7e183745e9b999e960ad55a23717a45bd0e4211
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Andy Hung
2022-07-26 20:03:49 +00:00
committed by Automerger Merge Worker

View File

@@ -46,6 +46,8 @@ import android.util.Log;
import android.util.Pair; import android.util.Pair;
import android.util.SparseIntArray; import android.util.SparseIntArray;
import com.android.internal.annotations.GuardedBy;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -103,10 +105,6 @@ public class SpatializerHelper {
AudioDeviceInfo.TYPE_BLE_BROADCAST AudioDeviceInfo.TYPE_BLE_BROADCAST
}; };
private static final int[] WIRELESS_SPEAKER_TYPES = {
AudioDeviceInfo.TYPE_BLE_SPEAKER,
};
// Spatializer state machine // Spatializer state machine
private static final int STATE_UNINITIALIZED = 0; private static final int STATE_UNINITIALIZED = 0;
private static final int STATE_NOT_SUPPORTED = 1; 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 * List of devices where Spatial Audio is possible. Each device can be enabled or disabled
* (== user choice to use or not) * (== user choice to use or not)
*/ */
@GuardedBy("this")
private final ArrayList<SADeviceState> mSADevices = new ArrayList<>(0); private final ArrayList<SADeviceState> mSADevices = new ArrayList<>(0);
//------------------------------------------------------ //------------------------------------------------------
@@ -520,30 +519,30 @@ public class SpatializerHelper {
* set to true if the device is added to the list, otherwise, if already * set to true if the device is added to the list, otherwise, if already
* present, the setting is left untouched. * present, the setting is left untouched.
*/ */
@GuardedBy("this")
private void addCompatibleAudioDevice(@NonNull AudioDeviceAttributes ada, private void addCompatibleAudioDevice(@NonNull AudioDeviceAttributes ada,
boolean forceEnable) { boolean forceEnable) {
if (!isDeviceCompatibleWithSpatializationModes(ada)) { if (!isDeviceCompatibleWithSpatializationModes(ada)) {
return; return;
} }
loglogi("addCompatibleAudioDevice: dev=" + ada); loglogi("addCompatibleAudioDevice: dev=" + ada);
boolean isInList = false; final SADeviceState deviceState = findDeviceStateForAudioDeviceAttributes(ada);
SADeviceState deviceUpdated = null; // non-null on update. SADeviceState deviceUpdated = null; // non-null on update.
if (deviceState != null) {
for (SADeviceState deviceState : mSADevices) { if (forceEnable && !deviceState.mEnabled) {
if (deviceState.matchesAudioDeviceAttributes(ada)) {
isInList = true;
if (forceEnable) {
deviceState.mEnabled = true;
deviceUpdated = deviceState; 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;
} }
} deviceUpdated = new SADeviceState(canonicalDeviceType, ada.getAddress());
if (!isInList) { mSADevices.add(deviceUpdated);
final SADeviceState deviceState = new SADeviceState(ada.getType(), ada.getAddress());
deviceState.mEnabled = true;
mSADevices.add(deviceState);
deviceUpdated = deviceState;
} }
if (deviceUpdated != null) { if (deviceUpdated != null) {
onRoutingUpdated(); onRoutingUpdated();
@@ -574,34 +573,59 @@ public class SpatializerHelper {
synchronized void removeCompatibleAudioDevice(@NonNull AudioDeviceAttributes ada) { synchronized void removeCompatibleAudioDevice(@NonNull AudioDeviceAttributes ada) {
loglogi("removeCompatibleAudioDevice: dev=" + ada); loglogi("removeCompatibleAudioDevice: dev=" + ada);
SADeviceState deviceUpdated = null; // non-null on update.
for (SADeviceState deviceState : mSADevices) { final SADeviceState deviceState = findDeviceStateForAudioDeviceAttributes(ada);
if (deviceState.matchesAudioDeviceAttributes(ada)) { if (deviceState != null && deviceState.mEnabled) {
deviceState.mEnabled = false; deviceState.mEnabled = false;
deviceUpdated = deviceState;
break;
}
}
if (deviceUpdated != null) {
onRoutingUpdated(); onRoutingUpdated();
mAudioService.persistSpatialAudioDeviceSettings(); 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;
}
/** /**
* Return if Spatial Audio is enabled and available for the given device * Return if Spatial Audio is enabled and available for the given device
* @param ada * @param ada
* @return a pair of boolean, 1/ enabled? 2/ available? * @return a pair of boolean, 1/ enabled? 2/ available?
*/ */
private synchronized Pair<Boolean, Boolean> evaluateState(AudioDeviceAttributes ada) { private synchronized Pair<Boolean, Boolean> evaluateState(AudioDeviceAttributes ada) {
// if not a wireless device, this value will be overwritten to map the type final @AudioDeviceInfo.AudioDeviceType int deviceType = ada.getType();
// 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)) {
// is the device type capable of doing SA? // is the device type capable of doing SA?
if (!mSACapableDeviceTypes.contains(deviceType)) { if (!mSACapableDeviceTypes.contains(deviceType)) {
Log.i(TAG, "Device incompatible with Spatial Audio dev:" + ada); Log.i(TAG, "Device incompatible with Spatial Audio dev:" + ada);
@@ -614,50 +638,30 @@ public class SpatializerHelper {
Log.e(TAG, "no spatialization mode found for device type:" + deviceType); Log.e(TAG, "no spatialization mode found for device type:" + deviceType);
return new Pair<>(false, false); return new Pair<>(false, false);
} }
// map the spatialization mode to the SPEAKER or HEADPHONES device final SADeviceState deviceState = findDeviceStateForAudioDeviceAttributes(ada);
if (spatMode == SpatializationMode.SPATIALIZER_TRANSAURAL) { if (deviceState == null) {
deviceType = AudioDeviceInfo.TYPE_BUILTIN_SPEAKER; // no matching device state?
} else { Log.i(TAG, "no spatialization device state found for Spatial Audio device:" + ada);
deviceType = AudioDeviceInfo.TYPE_WIRED_HEADPHONES;
}
} else { // wireless device
if (isWirelessSpeaker(deviceType) && !mTransauralSupported) {
Log.i(TAG, "Device incompatible with Spatial Audio (no transaural) dev:"
+ ada);
return new Pair<>(false, false); return new Pair<>(false, false);
} }
if (!mBinauralSupported) { // found the matching device state.
Log.i(TAG, "Device incompatible with Spatial Audio (no binaural) dev:" return new Pair<>(deviceState.mEnabled, true /* available */);
+ 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);
} }
private synchronized void addWirelessDeviceIfNew(@NonNull AudioDeviceAttributes ada) { private synchronized void addWirelessDeviceIfNew(@NonNull AudioDeviceAttributes ada) {
if (!isDeviceCompatibleWithSpatializationModes(ada)) { if (!isDeviceCompatibleWithSpatializationModes(ada)) {
return; return;
} }
boolean knownDevice = false; if (findDeviceStateForAudioDeviceAttributes(ada) == null) {
for (SADeviceState deviceState : mSADevices) { // wireless device types should be canonical, but we translate to be sure.
if (deviceState.matchesAudioDeviceAttributes(ada)) { final int canonicalDeviceType = getCanonicalDeviceType((ada.getType()));
knownDevice = true; if (canonicalDeviceType == AudioDeviceInfo.TYPE_UNKNOWN) {
break; Log.e(TAG, "addWirelessDeviceIfNew with incompatible AudioDeviceAttributes "
+ ada);
return;
} }
} final SADeviceState deviceState =
if (!knownDevice) { new SADeviceState(canonicalDeviceType, ada.getAddress());
final SADeviceState deviceState = new SADeviceState(ada.getType(), ada.getAddress());
mSADevices.add(deviceState); mSADevices.add(deviceState);
mAudioService.persistSpatialAudioDeviceSettings(); mAudioService.persistSpatialAudioDeviceSettings();
logDeviceState(deviceState, "addWirelessDeviceIfNew"); // may be updated later. logDeviceState(deviceState, "addWirelessDeviceIfNew"); // may be updated later.
@@ -699,12 +703,7 @@ public class SpatializerHelper {
if (ada.getRole() != AudioDeviceAttributes.ROLE_OUTPUT) { if (ada.getRole() != AudioDeviceAttributes.ROLE_OUTPUT) {
return false; return false;
} }
for (SADeviceState deviceState : mSADevices) { return findDeviceStateForAudioDeviceAttributes(ada) != null;
if (deviceState.matchesAudioDeviceAttributes(ada)) {
return true;
}
}
return false;
} }
private synchronized boolean canBeSpatializedOnDevice(@NonNull AudioAttributes attributes, private synchronized boolean canBeSpatializedOnDevice(@NonNull AudioAttributes attributes,
@@ -1086,8 +1085,8 @@ public class SpatializerHelper {
Log.v(TAG, "no headtracking support, ignoring setHeadTrackerEnabled to " + enabled Log.v(TAG, "no headtracking support, ignoring setHeadTrackerEnabled to " + enabled
+ " for " + ada); + " for " + ada);
} }
for (SADeviceState deviceState : mSADevices) { final SADeviceState deviceState = findDeviceStateForAudioDeviceAttributes(ada);
if (deviceState.matchesAudioDeviceAttributes(ada)) { if (deviceState == null) return;
if (!deviceState.mHasHeadTracker) { if (!deviceState.mHasHeadTracker) {
Log.e(TAG, "Called setHeadTrackerEnabled enabled:" + enabled Log.e(TAG, "Called setHeadTrackerEnabled enabled:" + enabled
+ " device:" + ada + " on a device without headtracker"); + " device:" + ada + " on a device without headtracker");
@@ -1097,9 +1096,7 @@ public class SpatializerHelper {
deviceState.mHeadTrackerEnabled = enabled; deviceState.mHeadTrackerEnabled = enabled;
mAudioService.persistSpatialAudioDeviceSettings(); mAudioService.persistSpatialAudioDeviceSettings();
logDeviceState(deviceState, "setHeadTrackerEnabled"); logDeviceState(deviceState, "setHeadTrackerEnabled");
break;
}
}
// check current routing to see if it affects the headtracking mode // check current routing to see if it affects the headtracking mode
if (ROUTING_DEVICES[0].getType() == ada.getType() if (ROUTING_DEVICES[0].getType() == ada.getType()
&& ROUTING_DEVICES[0].getAddress().equals(ada.getAddress())) { && ROUTING_DEVICES[0].getAddress().equals(ada.getAddress())) {
@@ -1113,12 +1110,8 @@ public class SpatializerHelper {
Log.v(TAG, "no headtracking support, hasHeadTracker always false for " + ada); Log.v(TAG, "no headtracking support, hasHeadTracker always false for " + ada);
return false; return false;
} }
for (SADeviceState deviceState : mSADevices) { final SADeviceState deviceState = findDeviceStateForAudioDeviceAttributes(ada);
if (deviceState.matchesAudioDeviceAttributes(ada)) { return deviceState != null && deviceState.mHasHeadTracker;
return deviceState.mHasHeadTracker;
}
}
return false;
} }
/** /**
@@ -1131,8 +1124,8 @@ public class SpatializerHelper {
Log.v(TAG, "no headtracking support, setHasHeadTracker always false for " + ada); Log.v(TAG, "no headtracking support, setHasHeadTracker always false for " + ada);
return false; return false;
} }
for (SADeviceState deviceState : mSADevices) { final SADeviceState deviceState = findDeviceStateForAudioDeviceAttributes(ada);
if (deviceState.matchesAudioDeviceAttributes(ada)) { if (deviceState != null) {
if (!deviceState.mHasHeadTracker) { if (!deviceState.mHasHeadTracker) {
deviceState.mHasHeadTracker = true; deviceState.mHasHeadTracker = true;
mAudioService.persistSpatialAudioDeviceSettings(); mAudioService.persistSpatialAudioDeviceSettings();
@@ -1140,7 +1133,6 @@ public class SpatializerHelper {
} }
return deviceState.mHeadTrackerEnabled; return deviceState.mHeadTrackerEnabled;
} }
}
Log.e(TAG, "setHasHeadTracker: device not found for:" + ada); Log.e(TAG, "setHasHeadTracker: device not found for:" + ada);
return false; return false;
} }
@@ -1150,15 +1142,9 @@ public class SpatializerHelper {
Log.v(TAG, "no headtracking support, isHeadTrackerEnabled always false for " + ada); Log.v(TAG, "no headtracking support, isHeadTrackerEnabled always false for " + ada);
return false; return false;
} }
for (SADeviceState deviceState : mSADevices) { final SADeviceState deviceState = findDeviceStateForAudioDeviceAttributes(ada);
if (deviceState.matchesAudioDeviceAttributes(ada)) { return deviceState != null
if (!deviceState.mHasHeadTracker) { && deviceState.mHasHeadTracker && deviceState.mHeadTrackerEnabled;
return false;
}
return deviceState.mHeadTrackerEnabled;
}
}
return false;
} }
synchronized boolean isHeadTrackerAvailable() { synchronized boolean isHeadTrackerAvailable() {
@@ -1582,12 +1568,6 @@ public class SpatializerHelper {
mDeviceType, mDeviceAddress == null ? "" : mDeviceAddress); 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() { /*package*/ synchronized String getSADeviceSettings() {
@@ -1608,7 +1588,10 @@ public class SpatializerHelper {
// small list, not worth overhead of Arrays.stream(devSettings) // small list, not worth overhead of Arrays.stream(devSettings)
for (String setting : devSettings) { for (String setting : devSettings) {
SADeviceState devState = SADeviceState.fromPersistedString(setting); 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 if (devState != null
&& devState.mDeviceType == getCanonicalDeviceType(devState.mDeviceType)
&& isDeviceCompatibleWithSpatializationModes( && isDeviceCompatibleWithSpatializationModes(
devState.getAudioDeviceAttributes())) { devState.getAudioDeviceAttributes())) {
mSADevices.add(devState); mSADevices.add(devState);
@@ -1645,15 +1628,6 @@ public class SpatializerHelper {
return false; 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() { private int getHeadSensorHandleUpdateTracker() {
int headHandle = -1; int headHandle = -1;
UUID routingDeviceUuid = mAudioService.getDeviceSensorUuid(ROUTING_DEVICES[0]); UUID routingDeviceUuid = mAudioService.getDeviceSensorUuid(ROUTING_DEVICES[0]);