AudioService: Pick head tracking sensor based on UUID

When the connected Bluetooth A2DP device reports a head tracker UUID,
use a head tracking sensor with this same UUID in priority over any
other head tracking sensor.

Bug: 210803914
Test: make
Change-Id: I8fa148e45fa36a01f1f44a79c7766595953fcc3f
This commit is contained in:
Eric Laurent
2022-01-06 14:37:28 +01:00
parent ae36c6a891
commit 13ae20f310
5 changed files with 134 additions and 9 deletions

View File

@@ -59,6 +59,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -1794,4 +1795,10 @@ import java.util.concurrent.atomic.AtomicBoolean;
}
return null;
}
UUID getDeviceSensorUuid(AudioDeviceAttributes device) {
synchronized (mDeviceStateLock) {
return mDeviceInventory.getDeviceSensorUuid(device);
}
}
}

View File

@@ -48,7 +48,9 @@ import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
/**
* Class to manage the inventory of all connected devices.
@@ -185,12 +187,20 @@ public class AudioDeviceInventory {
final @NonNull String mDeviceName;
final @NonNull String mDeviceAddress;
int mDeviceCodecFormat;
final UUID mSensorUuid;
DeviceInfo(int deviceType, String deviceName, String deviceAddress, int deviceCodecFormat) {
DeviceInfo(int deviceType, String deviceName, String deviceAddress,
int deviceCodecFormat, UUID sensorUuid) {
mDeviceType = deviceType;
mDeviceName = deviceName == null ? "" : deviceName;
mDeviceAddress = deviceAddress == null ? "" : deviceAddress;
mDeviceCodecFormat = deviceCodecFormat;
mSensorUuid = sensorUuid;
}
DeviceInfo(int deviceType, String deviceName, String deviceAddress,
int deviceCodecFormat) {
this(deviceType, deviceName, deviceAddress, deviceCodecFormat, null);
}
@Override
@@ -199,7 +209,8 @@ public class AudioDeviceInventory {
+ " (" + AudioSystem.getDeviceName(mDeviceType)
+ ") name:" + mDeviceName
+ " addr:" + mDeviceAddress
+ " codec: " + Integer.toHexString(mDeviceCodecFormat) + "]";
+ " codec: " + Integer.toHexString(mDeviceCodecFormat)
+ " sensorUuid: " + Objects.toString(mSensorUuid) + "]";
}
@NonNull String getKey() {
@@ -980,8 +991,13 @@ public class AudioDeviceInventory {
// Reset A2DP suspend state each time a new sink is connected
mAudioSystem.setParameters("A2dpSuspended=false");
// The convention for head tracking sensors associated with A2DP devices is to
// use a UUID derived from the MAC address as follows:
// time_low = 0, time_mid = 0, time_hi = 0, clock_seq = 0, node = MAC Address
UUID sensorUuid = UuidUtils.uuidFromAudioDeviceAttributes(
new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
final DeviceInfo di = new DeviceInfo(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, name,
address, a2dpCodec);
address, a2dpCodec, sensorUuid);
final String diKey = di.getKey();
mConnectedDevices.put(diKey, di);
// on a connection always overwrite the device seen by AudioPolicy, see comment above when
@@ -1453,6 +1469,17 @@ public class AudioDeviceInventory {
mDevRoleCapturePresetDispatchers.finishBroadcast();
}
UUID getDeviceSensorUuid(AudioDeviceAttributes device) {
final String key = DeviceInfo.makeDeviceListKey(device.getInternalType(),
device.getAddress());
synchronized (mDevicesLock) {
DeviceInfo di = mConnectedDevices.get(key);
if (di == null) {
return null;
}
return di.mSensorUuid;
}
}
//----------------------------------------------------------
// For tests only

View File

@@ -190,6 +190,7 @@ import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
@@ -11017,6 +11018,10 @@ public class AudioService extends IAudioService.Stub
return delayMillis;
}
UUID getDeviceSensorUuid(AudioDeviceAttributes device) {
return mDeviceBroker.getDeviceSensorUuid(device);
}
//======================
// misc
//======================

View File

@@ -43,6 +43,7 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.UUID;
/**
* A helper class to manage Spatializer related functionality
@@ -168,6 +169,7 @@ public class SpatializerHelper {
return;
}
mState = STATE_DISABLED_UNAVAILABLE;
mASA.getDevicesForAttributes(DEFAULT_ATTRIBUTES).toArray(ROUTING_DEVICES);
// note at this point mSpat is still not instantiated
}
@@ -204,6 +206,11 @@ public class SpatializerHelper {
logd("onRoutingUpdated: can spatialize media 5.1:" + able
+ " on device:" + ROUTING_DEVICES[0]);
setDispatchAvailableState(able);
if (mDesiredHeadTrackingMode != Spatializer.HEAD_TRACKING_MODE_UNSUPPORTED
&& mDesiredHeadTrackingMode != Spatializer.HEAD_TRACKING_MODE_DISABLED) {
postInitSensors();
}
}
//------------------------------------------------------
@@ -909,12 +916,21 @@ public class SpatializerHelper {
}
}
// initialize sensor handles
// TODO-HT update to non-private sensor once head tracker sensor is defined
for (Sensor sensor : mSensorManager.getDynamicSensorList(
Sensor.TYPE_DEVICE_PRIVATE_BASE)) {
if (sensor.getStringType().equals(HEADTRACKER_SENSOR)) {
headHandle = sensor.getHandle();
break;
UUID routingDeviceUuid = mAudioService.getDeviceSensorUuid(ROUTING_DEVICES[0]);
List<Sensor> sensors = new ArrayList<Sensor>(0);
sensors.addAll(mSensorManager.getDynamicSensorList(Sensor.TYPE_HEAD_TRACKER));
sensors.addAll(mSensorManager.getDynamicSensorList(Sensor.TYPE_DEVICE_PRIVATE_BASE));
for (Sensor sensor : sensors) {
if (sensor.getType() == Sensor.TYPE_HEAD_TRACKER
|| sensor.getStringType().equals(HEADTRACKER_SENSOR)) {
UUID uuid = sensor.getUuid();
if (uuid.equals(routingDeviceUuid)) {
headHandle = sensor.getHandle();
break;
}
if (uuid.equals(UuidUtils.STANDALONE_UUID)) {
headHandle = sensor.getHandle();
}
}
}
Sensor screenSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);

View File

@@ -0,0 +1,70 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.audio;
import android.media.AudioDeviceAttributes;
import android.media.AudioSystem;
import android.util.Slog;
import java.util.UUID;
/**
* UuidUtils class implements helper functions to handle unique identifiers
* used to associate head tracking sensors to audio devices.
*/
class UuidUtils {
private static final String TAG = "AudioService.UuidUtils";
private static final long LSB_PREFIX_MASK = 0xFFFF000000000000L;
private static final long LSB_SUFFIX_MASK = 0x0000FFFFFFFFFFFFL;
// The sensor UUID for Bluetooth devices is defined as follows:
// - 8 most significant bytes: All 0s
// - 8 most significant bytes: Ascii B, Ascii T, Device MAC address on 6 bytes
private static final long LSB_PREFIX_BT = 0x4254000000000000L;
/**
* Special UUID for a head tracking sensor not associated with an audio device.
*/
public static final UUID STANDALONE_UUID = new UUID(0, 0);
/**
* Generate a headtracking UUID from AudioDeviceAttributes
*/
public static UUID uuidFromAudioDeviceAttributes(AudioDeviceAttributes device) {
switch (device.getInternalType()) {
case AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP:
String address = device.getAddress().replace(":", "");
if (address.length() != 12) {
return null;
}
address = "0x" + address;
long lsb = LSB_PREFIX_BT;
try {
lsb |= Long.decode(address).longValue();
} catch (NumberFormatException e) {
return null;
}
if (AudioService.DEBUG_DEVICES) {
Slog.i(TAG, "uuidFromAudioDeviceAttributes lsb: " + Long.toHexString(lsb));
}
return new UUID(0, lsb);
default:
// Handle other device types here
return null;
}
}
}