Loading services/core/java/com/android/server/audio/AudioDeviceBroker.java +7 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -1794,4 +1795,10 @@ import java.util.concurrent.atomic.AtomicBoolean; } return null; } UUID getDeviceSensorUuid(AudioDeviceAttributes device) { synchronized (mDeviceStateLock) { return mDeviceInventory.getDeviceSensorUuid(device); } } } services/core/java/com/android/server/audio/AudioDeviceInventory.java +30 −3 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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 Loading @@ -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() { Loading Loading @@ -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 Loading Loading @@ -1456,6 +1472,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 Loading services/core/java/com/android/server/audio/AudioService.java +5 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -11017,6 +11018,10 @@ public class AudioService extends IAudioService.Stub return delayMillis; } UUID getDeviceSensorUuid(AudioDeviceAttributes device) { return mDeviceBroker.getDeviceSensorUuid(device); } //====================== // misc //====================== Loading services/core/java/com/android/server/audio/SpatializerHelper.java +22 −6 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 } Loading Loading @@ -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(); } } //------------------------------------------------------ Loading Loading @@ -909,13 +916,22 @@ 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)) { 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); screenHandle = screenSensor.getHandle(); Loading services/core/java/com/android/server/audio/UuidUtils.java 0 → 100644 +70 −0 Original line number Diff line number Diff line /* * 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; } } } Loading
services/core/java/com/android/server/audio/AudioDeviceBroker.java +7 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -1794,4 +1795,10 @@ import java.util.concurrent.atomic.AtomicBoolean; } return null; } UUID getDeviceSensorUuid(AudioDeviceAttributes device) { synchronized (mDeviceStateLock) { return mDeviceInventory.getDeviceSensorUuid(device); } } }
services/core/java/com/android/server/audio/AudioDeviceInventory.java +30 −3 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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 Loading @@ -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() { Loading Loading @@ -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 Loading Loading @@ -1456,6 +1472,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 Loading
services/core/java/com/android/server/audio/AudioService.java +5 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -11017,6 +11018,10 @@ public class AudioService extends IAudioService.Stub return delayMillis; } UUID getDeviceSensorUuid(AudioDeviceAttributes device) { return mDeviceBroker.getDeviceSensorUuid(device); } //====================== // misc //====================== Loading
services/core/java/com/android/server/audio/SpatializerHelper.java +22 −6 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 } Loading Loading @@ -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(); } } //------------------------------------------------------ Loading Loading @@ -909,13 +916,22 @@ 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)) { 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); screenHandle = screenSensor.getHandle(); Loading
services/core/java/com/android/server/audio/UuidUtils.java 0 → 100644 +70 −0 Original line number Diff line number Diff line /* * 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; } } }