Spatializer: Fix usb headset
Fixes the general transaural and binaural equivalence of different devices. Prior to this fix only speaker and true 3.5mm wired headphones could be enabled. Now all SADevices will have a canonical device type. Test: Plug in USB headset, verify spatializer works. Bug: 239081163 Merged-In: I904a299556f1cccb9d8d69a23245e387f7a5d35e Change-Id: I904a299556f1cccb9d8d69a23245e387f7a5d35e
This commit is contained in:
parent
a36a023dae
commit
12f9b9fafd
@ -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);
|
||||
|
||||
//------------------------------------------------------
|
||||
@ -513,30 +512,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;
|
||||
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();
|
||||
@ -567,90 +566,95 @@ 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)) {
|
||||
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.
|
||||
@ -692,12 +696,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,
|
||||
@ -1079,20 +1078,18 @@ public class SpatializerHelper {
|
||||
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())) {
|
||||
@ -1106,12 +1103,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;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1124,15 +1117,14 @@ public class SpatializerHelper {
|
||||
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;
|
||||
@ -1143,15 +1135,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() {
|
||||
@ -1575,12 +1561,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() {
|
||||
@ -1601,7 +1581,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);
|
||||
@ -1638,15 +1621,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;
|
||||
UUID routingDeviceUuid = mAudioService.getDeviceSensorUuid(ROUTING_DEVICES[0]);
|
||||
|
Loading…
x
Reference in New Issue
Block a user