Merge "Spatializer: add getter/listener for head tracker availability" into tm-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
1a89ec7056
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user