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

This commit is contained in:
Jean-Michel Trivi
2022-03-16 19:38:24 +00:00
committed by Android (Google) Code Review
6 changed files with 179 additions and 2 deletions

View File

@@ -23548,17 +23548,24 @@ package android.media {
} }
public class Spatializer { 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 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 boolean canBeSpatialized(@NonNull android.media.AudioAttributes, @NonNull android.media.AudioFormat);
method public int getImmersiveAudioLevel(); method public int getImmersiveAudioLevel();
method public boolean isAvailable(); method public boolean isAvailable();
method public boolean isEnabled(); 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); 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_MULTICHANNEL = 1; // 0x1
field public static final int SPATIALIZER_IMMERSIVE_LEVEL_NONE = 0; // 0x0 field public static final int SPATIALIZER_IMMERSIVE_LEVEL_NONE = 0; // 0x0
field public static final int SPATIALIZER_IMMERSIVE_LEVEL_OTHER = -1; // 0xffffffff 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 { public static interface Spatializer.OnSpatializerStateChangedListener {
method public void onSpatializerAvailableChanged(@NonNull android.media.Spatializer, boolean); method public void onSpatializerAvailableChanged(@NonNull android.media.Spatializer, boolean);
method public void onSpatializerEnabledChanged(@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.IRingtonePlayer;
import android.media.IStrategyPreferredDevicesDispatcher; import android.media.IStrategyPreferredDevicesDispatcher;
import android.media.ISpatializerCallback; import android.media.ISpatializerCallback;
import android.media.ISpatializerHeadTrackerAvailableCallback;
import android.media.ISpatializerHeadTrackingModeCallback; import android.media.ISpatializerHeadTrackingModeCallback;
import android.media.ISpatializerHeadToSoundStagePoseCallback; import android.media.ISpatializerHeadToSoundStagePoseCallback;
import android.media.ISpatializerOutputCallback; import android.media.ISpatializerOutputCallback;
@@ -414,6 +415,11 @@ interface IAudioService {
boolean isHeadTrackerEnabled(in AudioDeviceAttributes device); boolean isHeadTrackerEnabled(in AudioDeviceAttributes device);
boolean isHeadTrackerAvailable();
void registerSpatializerHeadTrackerAvailableCallback(
in ISpatializerHeadTrackerAvailableCallback cb, boolean register);
void setSpatializerEnabled(boolean enabled); void setSpatializerEnabled(boolean enabled);
boolean canBeSpatialized(in AudioAttributes aa, in AudioFormat af); 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; 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 */ /** @hide */
@IntDef(flag = false, value = { @IntDef(flag = false, value = {
SPATIALIZER_IMMERSIVE_LEVEL_OTHER, SPATIALIZER_IMMERSIVE_LEVEL_OTHER,
@@ -401,6 +440,22 @@ public class Spatializer {
@HeadTrackingModeSet int mode); @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 * @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 // head pose callback management and stub
private final Object mPoseListenerLock = new Object(); private final Object mPoseListenerLock = new Object();

View File

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

View File

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