Merge "Spatializer: Fix usb headset" into tm-qpr-dev
diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java
index cd5960f..1def72b 100644
--- a/services/core/java/com/android/server/audio/SpatializerHelper.java
+++ b/services/core/java/com/android/server/audio/SpatializerHelper.java
@@ -46,6 +46,8 @@
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 @@
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 @@
* 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);
//------------------------------------------------------
@@ -520,30 +519,30 @@
* 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;
- deviceUpdated = deviceState;
- }
- break;
+ if (deviceState != null) {
+ if (forceEnable && !deviceState.mEnabled) {
+ deviceUpdated = deviceState;
+ deviceUpdated.mEnabled = true;
}
- }
- if (!isInList) {
- final SADeviceState deviceState = new SADeviceState(ada.getType(), ada.getAddress());
- deviceState.mEnabled = true;
- mSADevices.add(deviceState);
- deviceUpdated = deviceState;
+ } 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());
+ mSADevices.add(deviceUpdated);
}
if (deviceUpdated != null) {
onRoutingUpdated();
@@ -574,90 +573,95 @@
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)) {
- deviceState.mEnabled = false;
- deviceUpdated = deviceState;
- break;
- }
- }
- if (deviceUpdated != null) {
+ final SADeviceState deviceState = findDeviceStateForAudioDeviceAttributes(ada);
+ if (deviceState != null && deviceState.mEnabled) {
+ deviceState.mEnabled = false;
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;
+ }
+
+ /**
* Return if Spatial Audio is enabled and available for the given device
* @param ada
* @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)) {
- // is the device type capable of doing SA?
- if (!mSACapableDeviceTypes.contains(deviceType)) {
- Log.i(TAG, "Device incompatible with Spatial Audio dev:" + ada);
- return new Pair<>(false, false);
- }
- // what spatialization mode to use for this device?
- final int spatMode = SPAT_MODE_FOR_DEVICE_TYPE.get(deviceType, Integer.MIN_VALUE);
- if (spatMode == Integer.MIN_VALUE) {
- // error case, device not found
- 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);
- return new Pair<>(false, false);
- }
- if (!mBinauralSupported) {
- Log.i(TAG, "Device incompatible with Spatial Audio (no binaural) dev:"
- + ada);
- return new Pair<>(false, false);
- }
+ 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);
+ 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;
- }
+ // what spatialization mode to use for this device?
+ final int spatMode = SPAT_MODE_FOR_DEVICE_TYPE.get(deviceType, Integer.MIN_VALUE);
+ if (spatMode == Integer.MIN_VALUE) {
+ // error case, device not found
+ Log.e(TAG, "no spatialization mode found for device type:" + deviceType);
+ return new Pair<>(false, false);
}
- return new Pair<>(enabled, available);
+ 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);
+ }
+ // 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.
@@ -699,12 +703,7 @@
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,20 +1085,18 @@
Log.v(TAG, "no headtracking support, ignoring setHeadTrackerEnabled to " + enabled
+ " for " + ada);
}
- for (SADeviceState deviceState : mSADevices) {
- if (deviceState.matchesAudioDeviceAttributes(ada)) {
- if (!deviceState.mHasHeadTracker) {
- Log.e(TAG, "Called setHeadTrackerEnabled enabled:" + enabled
- + " device:" + ada + " on a device without headtracker");
- return;
- }
- Log.i(TAG, "setHeadTrackerEnabled enabled:" + enabled + " device:" + ada);
- deviceState.mHeadTrackerEnabled = enabled;
- mAudioService.persistSpatialAudioDeviceSettings();
- logDeviceState(deviceState, "setHeadTrackerEnabled");
- break;
- }
+ 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");
+ return;
}
+ Log.i(TAG, "setHeadTrackerEnabled enabled:" + enabled + " device:" + ada);
+ deviceState.mHeadTrackerEnabled = enabled;
+ mAudioService.persistSpatialAudioDeviceSettings();
+ logDeviceState(deviceState, "setHeadTrackerEnabled");
+
// check current routing to see if it affects the headtracking mode
if (ROUTING_DEVICES[0].getType() == ada.getType()
&& ROUTING_DEVICES[0].getAddress().equals(ada.getAddress())) {
@@ -1113,12 +1110,8 @@
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;
}
/**
@@ -1131,15 +1124,14 @@
Log.v(TAG, "no headtracking support, setHasHeadTracker always false for " + ada);
return false;
}
- for (SADeviceState deviceState : mSADevices) {
- if (deviceState.matchesAudioDeviceAttributes(ada)) {
- if (!deviceState.mHasHeadTracker) {
- deviceState.mHasHeadTracker = true;
- mAudioService.persistSpatialAudioDeviceSettings();
- logDeviceState(deviceState, "setHasHeadTracker");
- }
- return deviceState.mHeadTrackerEnabled;
+ final SADeviceState deviceState = findDeviceStateForAudioDeviceAttributes(ada);
+ if (deviceState != null) {
+ if (!deviceState.mHasHeadTracker) {
+ deviceState.mHasHeadTracker = true;
+ mAudioService.persistSpatialAudioDeviceSettings();
+ logDeviceState(deviceState, "setHasHeadTracker");
}
+ return deviceState.mHeadTrackerEnabled;
}
Log.e(TAG, "setHasHeadTracker: device not found for:" + ada);
return false;
@@ -1150,15 +1142,9 @@
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() {
@@ -1582,12 +1568,6 @@
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() {
@@ -1608,7 +1588,10 @@
// 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);
@@ -1645,15 +1628,6 @@
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;
UUID routingDeviceUuid = mAudioService.getDeviceSensorUuid(ROUTING_DEVICES[0]);