Merge "Spatializer: add getter/listener for head tracker availability" into tm-dev am: 1a89ec7056

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

Change-Id: I5af6fdad033d23bcf7d1a7b7f63a90f7ab027d05
This commit is contained in:
Jean-Michel Trivi
2022-03-16 19:45:03 +00:00
committed by Automerger Merge Worker
6 changed files with 179 additions and 2 deletions

View File

@@ -23548,17 +23548,24 @@ package android.media {
}
public class Spatializer {
method public void addOnHeadTrackerAvailableListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.Spatializer.OnHeadTrackerAvailableListener);
method public void addOnSpatializerStateChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.Spatializer.OnSpatializerStateChangedListener);
method public boolean canBeSpatialized(@NonNull android.media.AudioAttributes, @NonNull android.media.AudioFormat);
method public int getImmersiveAudioLevel();
method public boolean isAvailable();
method public boolean isEnabled();
method public boolean isHeadTrackerAvailable();
method public void removeOnHeadTrackerAvailableListener(@NonNull android.media.Spatializer.OnHeadTrackerAvailableListener);
method public void removeOnSpatializerStateChangedListener(@NonNull android.media.Spatializer.OnSpatializerStateChangedListener);
field public static final int SPATIALIZER_IMMERSIVE_LEVEL_MULTICHANNEL = 1; // 0x1
field public static final int SPATIALIZER_IMMERSIVE_LEVEL_NONE = 0; // 0x0
field public static final int SPATIALIZER_IMMERSIVE_LEVEL_OTHER = -1; // 0xffffffff
}
public static interface Spatializer.OnHeadTrackerAvailableListener {
method public void onHeadTrackerAvailableChanged(@NonNull android.media.Spatializer, boolean);
}
public static interface Spatializer.OnSpatializerStateChangedListener {
method public void onSpatializerAvailableChanged(@NonNull android.media.Spatializer, boolean);
method public void onSpatializerEnabledChanged(@NonNull android.media.Spatializer, boolean);

View File

@@ -39,6 +39,7 @@ import android.media.IRecordingConfigDispatcher;
import android.media.IRingtonePlayer;
import android.media.IStrategyPreferredDevicesDispatcher;
import android.media.ISpatializerCallback;
import android.media.ISpatializerHeadTrackerAvailableCallback;
import android.media.ISpatializerHeadTrackingModeCallback;
import android.media.ISpatializerHeadToSoundStagePoseCallback;
import android.media.ISpatializerOutputCallback;
@@ -414,6 +415,11 @@ interface IAudioService {
boolean isHeadTrackerEnabled(in AudioDeviceAttributes device);
boolean isHeadTrackerAvailable();
void registerSpatializerHeadTrackerAvailableCallback(
in ISpatializerHeadTrackerAvailableCallback cb, boolean register);
void setSpatializerEnabled(boolean enabled);
boolean canBeSpatialized(in AudioAttributes aa, in AudioFormat af);

View File

@@ -0,0 +1,27 @@
/*
* 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 android.media;
/**
* AIDL for the AudioService to signal whether audio device used by Spatializer has head tracker.
*
* {@hide}
*/
oneway interface ISpatializerHeadTrackerAvailableCallback {
void dispatchSpatializerHeadTrackerAvailable(boolean available);
}

View File

@@ -185,6 +185,45 @@ public class Spatializer {
return false;
}
/**
* Returns whether a head tracker is currently available for the audio device used by the
* spatializer effect.
* @return true if a head tracker is available and the effect is enabled, false otherwise.
* @see OnHeadTrackerAvailableListener
* @see #addOnHeadTrackerAvailableListener(Executor, OnHeadTrackerAvailableListener)
*/
public boolean isHeadTrackerAvailable() {
try {
return mAm.getService().isHeadTrackerAvailable();
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
return false;
}
/**
* Adds a listener to be notified of changes to the availability of a head tracker.
* @param executor the {@code Executor} handling the callback
* @param listener the listener to receive availability updates
* @see #removeOnHeadTrackerAvailableListener(OnHeadTrackerAvailableListener)
*/
public void addOnHeadTrackerAvailableListener(@NonNull @CallbackExecutor Executor executor,
@NonNull OnHeadTrackerAvailableListener listener) {
mHeadTrackerListenerMgr.addListener(executor, listener,
"addOnHeadTrackerAvailableListener",
() -> new SpatializerHeadTrackerAvailableDispatcherStub());
}
/**
* Removes a previously registered listener for the availability of a head tracker.
* @param listener the listener previously registered with
* {@link #addOnHeadTrackerAvailableListener(Executor, OnHeadTrackerAvailableListener)}
*/
public void removeOnHeadTrackerAvailableListener(
@NonNull OnHeadTrackerAvailableListener listener) {
mHeadTrackerListenerMgr.removeListener(listener, "removeOnHeadTrackerAvailableListener");
}
/** @hide */
@IntDef(flag = false, value = {
SPATIALIZER_IMMERSIVE_LEVEL_OTHER,
@@ -401,6 +440,22 @@ public class Spatializer {
@HeadTrackingModeSet int mode);
}
/**
* Interface to be notified of changes to the availability of a head tracker on the audio
* device to be used by the spatializer effect.
*/
public interface OnHeadTrackerAvailableListener {
/**
* Called when the availability of the head tracker changed.
* @param spatializer the {@code Spatializer} instance for which the head tracker
* availability was updated
* @param available true if the audio device that would output audio processed by
* the {@code Spatializer} has a head tracker associated with it, false
* otherwise.
*/
void onHeadTrackerAvailableChanged(@NonNull Spatializer spatializer,
boolean available);
}
/**
* @hide
@@ -934,6 +989,36 @@ public class Spatializer {
}
}
//-----------------------------------------------------------------------------
// head tracker availability callback management and stub
/**
* manages the OnHeadTrackerAvailableListener listeners and the
* SpatializerHeadTrackerAvailableDispatcherStub
*/
private final CallbackUtil.LazyListenerManager<OnHeadTrackerAvailableListener>
mHeadTrackerListenerMgr = new CallbackUtil.LazyListenerManager();
private final class SpatializerHeadTrackerAvailableDispatcherStub
extends ISpatializerHeadTrackerAvailableCallback.Stub
implements CallbackUtil.DispatcherStub {
@Override
public void register(boolean register) {
try {
mAm.getService().registerSpatializerHeadTrackerAvailableCallback(this, register);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
}
@Override
@SuppressLint("GuardedBy") // lock applied inside callListeners method
public void dispatchSpatializerHeadTrackerAvailable(boolean available) {
mHeadTrackerListenerMgr.callListeners(
(listener) -> listener.onHeadTrackerAvailableChanged(
Spatializer.this, available));
}
}
//-----------------------------------------------------------------------------
// head pose callback management and stub
private final Object mPoseListenerLock = new Object();

View File

@@ -102,6 +102,7 @@ import android.media.IRecordingConfigDispatcher;
import android.media.IRingtonePlayer;
import android.media.ISpatializerCallback;
import android.media.ISpatializerHeadToSoundStagePoseCallback;
import android.media.ISpatializerHeadTrackerAvailableCallback;
import android.media.ISpatializerHeadTrackingModeCallback;
import android.media.ISpatializerOutputCallback;
import android.media.IStrategyPreferredDevicesDispatcher;
@@ -8723,6 +8724,11 @@ public class AudioService extends IAudioService.Stub
return mSpatializerHelper.isHeadTrackerEnabled(Objects.requireNonNull(device));
}
/** @see Spatializer#isHeadTrackerAvailable() */
public boolean isHeadTrackerAvailable() {
return mSpatializerHelper.isHeadTrackerAvailable();
}
/** @see Spatializer#setSpatializerEnabled(boolean) */
public void setSpatializerEnabled(boolean enabled) {
enforceModifyDefaultAudioEffectsPermission();
@@ -8767,6 +8773,13 @@ public class AudioService extends IAudioService.Stub
mSpatializerHelper.unregisterHeadTrackingModeCallback(cb);
}
/** @see Spatializer.SpatializerHeadTrackerAvailableDispatcherStub */
public void registerSpatializerHeadTrackerAvailableCallback(
@NonNull ISpatializerHeadTrackerAvailableCallback cb, boolean register) {
Objects.requireNonNull(cb);
mSpatializerHelper.registerHeadTrackerAvailableCallback(cb, register);
}
/** @see Spatializer#setOnHeadToSoundstagePoseUpdatedListener */
public void registerHeadToSoundstagePoseCallback(
@NonNull ISpatializerHeadToSoundStagePoseCallback cb) {

View File

@@ -30,6 +30,7 @@ import android.media.INativeSpatializerCallback;
import android.media.ISpatializer;
import android.media.ISpatializerCallback;
import android.media.ISpatializerHeadToSoundStagePoseCallback;
import android.media.ISpatializerHeadTrackerAvailableCallback;
import android.media.ISpatializerHeadTrackingCallback;
import android.media.ISpatializerHeadTrackingModeCallback;
import android.media.ISpatializerOutputCallback;
@@ -126,6 +127,7 @@ public class SpatializerHelper {
private boolean mBinauralSupported = false;
private int mActualHeadTrackingMode = Spatializer.HEAD_TRACKING_MODE_UNSUPPORTED;
private int mDesiredHeadTrackingMode = Spatializer.HEAD_TRACKING_MODE_RELATIVE_WORLD;
private boolean mHeadTrackerAvailable = false;
/**
* The desired head tracking mode when enabling head tracking, tracks mDesiredHeadTrackingMode,
* except when head tracking gets disabled through setting the desired mode to
@@ -831,6 +833,7 @@ public class SpatializerHelper {
mSpatCallback = null;
try {
mSpat.registerHeadTrackingCallback(null);
mHeadTrackerAvailable = false;
mSpat.release();
} catch (RemoteException e) {
Log.e(TAG, "Can't set release spatializer cleanly", e);
@@ -890,6 +893,18 @@ public class SpatializerHelper {
mHeadTrackingModeCallbacks.unregister(callback);
}
final RemoteCallbackList<ISpatializerHeadTrackerAvailableCallback> mHeadTrackerCallbacks =
new RemoteCallbackList<>();
synchronized void registerHeadTrackerAvailableCallback(
@NonNull ISpatializerHeadTrackerAvailableCallback cb, boolean register) {
if (register) {
mHeadTrackerCallbacks.register(cb);
} else {
mHeadTrackerCallbacks.unregister(cb);
}
}
synchronized int[] getSupportedHeadTrackingModes() {
switch (mState) {
case STATE_UNINITIALIZED:
@@ -1090,6 +1105,10 @@ public class SpatializerHelper {
return false;
}
synchronized boolean isHeadTrackerAvailable() {
return mHeadTrackerAvailable;
}
private boolean checkSpatForHeadTracking(String funcName) {
switch (mState) {
case STATE_UNINITIALIZED:
@@ -1115,7 +1134,8 @@ public class SpatializerHelper {
mHeadTrackingModeCallbacks.getBroadcastItem(i)
.dispatchSpatializerActualHeadTrackingModeChanged(newMode);
} catch (RemoteException e) {
Log.e(TAG, "Error in dispatchSpatializerActualHeadTrackingModeChanged", e);
Log.e(TAG, "Error in dispatchSpatializerActualHeadTrackingModeChanged("
+ newMode + ")", e);
}
}
mHeadTrackingModeCallbacks.finishBroadcast();
@@ -1128,12 +1148,27 @@ public class SpatializerHelper {
mHeadTrackingModeCallbacks.getBroadcastItem(i)
.dispatchSpatializerDesiredHeadTrackingModeChanged(newMode);
} catch (RemoteException e) {
Log.e(TAG, "Error in dispatchSpatializerDesiredHeadTrackingModeChanged", e);
Log.e(TAG, "Error in dispatchSpatializerDesiredHeadTrackingModeChanged("
+ newMode + ")", e);
}
}
mHeadTrackingModeCallbacks.finishBroadcast();
}
private void dispatchHeadTrackerAvailable(boolean available) {
final int nbCallbacks = mHeadTrackerCallbacks.beginBroadcast();
for (int i = 0; i < nbCallbacks; i++) {
try {
mHeadTrackerCallbacks.getBroadcastItem(i)
.dispatchSpatializerHeadTrackerAvailable(available);
} catch (RemoteException e) {
Log.e(TAG, "Error in dispatchSpatializerHeadTrackerAvailable("
+ available + ")", e);
}
}
mHeadTrackerCallbacks.finishBroadcast();
}
//------------------------------------------------------
// head pose
final RemoteCallbackList<ISpatializerHeadToSoundStagePoseCallback> mHeadPoseCallbacks =
@@ -1348,6 +1383,10 @@ public class SpatializerHelper {
try {
Log.i(TAG, "setHeadSensor:" + headHandle);
mSpat.setHeadSensor(headHandle);
if (mHeadTrackerAvailable != (headHandle != -1)) {
mHeadTrackerAvailable = (headHandle != -1);
dispatchHeadTrackerAvailable(mHeadTrackerAvailable);
}
} catch (Exception e) {
Log.e(TAG, "Error calling setHeadSensor:" + headHandle, e);
}