diff options
| author | 2021-09-14 09:45:29 +0000 | |
|---|---|---|
| committer | 2021-09-14 09:45:29 +0000 | |
| commit | 0917c8c9672242999abba7001aa0e785d293d782 (patch) | |
| tree | 3b6efe7fefb0b8a7dbce7cb2e42e406e3c66e90d | |
| parent | a58a7d6a4322e7f116083a81490e6035e1905632 (diff) | |
| parent | 838913c584d0f3a94d35c378f1869a279a4e216a (diff) | |
Merge "AudioService: initialize Spatializer, track routing changes" into sc-v2-dev
5 files changed, 462 insertions, 34 deletions
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 5db9ddfac870..ee75a8d6f4b2 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -2443,8 +2443,7 @@ public class AudioManager { /** * Return a handle to the optional platform's {@link Spatializer} - * @return {@code null} if spatialization is not supported, the {@code Spatializer} instance - * otherwise. + * @return the {@code Spatializer} instance. */ public @Nullable Spatializer getSpatializer() { int level = Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE; diff --git a/media/java/android/media/Spatializer.java b/media/java/android/media/Spatializer.java index 3ed8b58959a1..c64bf2c60117 100644 --- a/media/java/android/media/Spatializer.java +++ b/media/java/android/media/Spatializer.java @@ -114,6 +114,7 @@ public class Spatializer { /** @hide */ @IntDef(flag = false, value = { + SPATIALIZER_IMMERSIVE_LEVEL_OTHER, SPATIALIZER_IMMERSIVE_LEVEL_NONE, SPATIALIZER_IMMERSIVE_LEVEL_MULTICHANNEL, }) @@ -122,21 +123,46 @@ public class Spatializer { /** * @hide + * Constant indicating the {@code Spatializer} on this device supports a spatialization + * mode that differs from the ones available at this SDK level. + * @see #getImmersiveAudioLevel() + */ + public static final int SPATIALIZER_IMMERSIVE_LEVEL_OTHER = -1; + + /** + * @hide * Constant indicating there are no spatialization capabilities supported on this device. - * @see AudioManager#getImmersiveAudioLevel() + * @see #getImmersiveAudioLevel() */ public static final int SPATIALIZER_IMMERSIVE_LEVEL_NONE = 0; /** * @hide - * Constant indicating the {@link Spatializer} on this device supports multichannel + * Constant indicating the {@code Spatializer} on this device supports multichannel * spatialization. - * @see AudioManager#getImmersiveAudioLevel() + * @see #getImmersiveAudioLevel() */ public static final int SPATIALIZER_IMMERSIVE_LEVEL_MULTICHANNEL = 1; /** * @hide + * Return the level of support for the spatialization feature on this device. + * This level of support is independent of whether the {@code Spatializer} is currently + * enabled or available and will not change over time. + * @return the level of spatialization support + * @see #isEnabled() + * @see #isAvailable() + */ + public @ImmersiveAudioLevel int getImmersiveAudioLevel() { + int level = Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE; + try { + level = mAm.getService().getSpatializerImmersiveAudioLevel(); + } catch (Exception e) { /* using NONE */ } + return level; + } + + /** + * @hide * Enables / disables the spatializer effect. * Changing the enabled state will trigger the public * {@link OnSpatializerStateChangedListener#onSpatializerEnabledChanged(Spatializer, boolean)} diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index b9b90c0f64ea..f2ba42c6ceea 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -200,7 +200,8 @@ import java.util.stream.Collectors; */ public class AudioService extends IAudioService.Stub implements AccessibilityManager.TouchExplorationStateChangeListener, - AccessibilityManager.AccessibilityServicesStateChangeListener { + AccessibilityManager.AccessibilityServicesStateChangeListener, + AudioSystemAdapter.OnRoutingUpdatedListener { private static final String TAG = "AS.AudioService"; @@ -314,12 +315,14 @@ public class AudioService extends IAudioService.Stub private static final int MSG_SET_A2DP_DEV_CONNECTION_STATE = 38; private static final int MSG_A2DP_DEV_CONFIG_CHANGE = 39; private static final int MSG_DISPATCH_AUDIO_MODE = 40; + private static final int MSG_ROUTING_UPDATED = 41; // start of messages handled under wakelock // these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(), // and not with sendMsg(..., ..., SENDMSG_QUEUE, ...) private static final int MSG_DISABLE_AUDIO_FOR_UID = 100; private static final int MSG_INIT_STREAMS_VOLUMES = 101; + private static final int MSG_INIT_SPATIALIZER = 102; // end of messages handled under wakelock // retry delay in case of failure to indicate system ready to AudioFlinger @@ -869,6 +872,8 @@ public class AudioService extends IAudioService.Stub mSfxHelper = new SoundEffectsHelper(mContext); + mSpatializerHelper = new SpatializerHelper(this, mAudioSystem); + mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); mHasVibrator = mVibrator == null ? false : mVibrator.hasVibrator(); @@ -1033,6 +1038,9 @@ public class AudioService extends IAudioService.Stub // done with service initialization, continue additional work in our Handler thread queueMsgUnderWakeLock(mAudioHandler, MSG_INIT_STREAMS_VOLUMES, 0 /* arg1 */, 0 /* arg2 */, null /* obj */, 0 /* delay */); + queueMsgUnderWakeLock(mAudioHandler, MSG_INIT_SPATIALIZER, + 0 /* arg1 */, 0 /* arg2 */, null /* obj */, 0 /* delay */); + } /** @@ -1222,6 +1230,22 @@ public class AudioService extends IAudioService.Stub updateVibratorInfos(); } + //----------------------------------------------------------------- + // routing monitoring from AudioSystemAdapter + @Override + public void onRoutingUpdatedFromNative() { + sendMsg(mAudioHandler, + MSG_ROUTING_UPDATED, + SENDMSG_REPLACE, 0, 0, null, + /*delay*/ 0); + } + + void monitorRoutingChanges(boolean enabled) { + mAudioSystem.setRoutingListener(enabled ? this : null); + } + + + //----------------------------------------------------------------- RoleObserver mRoleObserver; class RoleObserver implements OnRoleHoldersChangedListener { @@ -1406,6 +1430,9 @@ public class AudioService extends IAudioService.Stub } } + // TODO check property if feature enabled + mSpatializerHelper.reset(/* featureEnabled */ true); + onIndicateSystemReady(); // indicate the end of reconfiguration phase to audio HAL AudioSystem.setParameters("restarting=false"); @@ -7539,6 +7566,13 @@ public class AudioService extends IAudioService.Stub mAudioEventWakeLock.release(); break; + case MSG_INIT_SPATIALIZER: + mSpatializerHelper.init(); + // TODO read property to see if enabled + mSpatializerHelper.setFeatureEnabled(true); + mAudioEventWakeLock.release(); + break; + case MSG_CHECK_MUSIC_ACTIVE: onCheckMusicActive((String) msg.obj); break; @@ -7671,6 +7705,10 @@ public class AudioService extends IAudioService.Stub case MSG_DISPATCH_AUDIO_MODE: dispatchMode(msg.arg1); break; + + case MSG_ROUTING_UPDATED: + mSpatializerHelper.onRoutingUpdated(); + break; } } } @@ -8239,7 +8277,7 @@ public class AudioService extends IAudioService.Stub } //========================================================================================== - private final SpatializerHelper mSpatializerHelper = new SpatializerHelper(); + private final @NonNull SpatializerHelper mSpatializerHelper; private void enforceModifyDefaultAudioEffectsPermission() { if (mContext.checkCallingOrSelfPermission( @@ -8249,9 +8287,12 @@ public class AudioService extends IAudioService.Stub } } - /** @see AudioManager#getSpatializerImmersiveAudioLevel() */ + /** + * Returns the immersive audio level that the platform is capable of + * @see Spatializer#getImmersiveAudioLevel() + */ public int getSpatializerImmersiveAudioLevel() { - return mSpatializerHelper.getImmersiveAudioLevel(); + return mSpatializerHelper.getCapableImmersiveAudioLevel(); } /** @see Spatializer#isEnabled() */ @@ -8267,7 +8308,7 @@ public class AudioService extends IAudioService.Stub /** @see Spatializer#setSpatializerEnabled(boolean) */ public void setSpatializerEnabled(boolean enabled) { enforceModifyDefaultAudioEffectsPermission(); - mSpatializerHelper.setEnabled(enabled); + mSpatializerHelper.setFeatureEnabled(enabled); } /** @see Spatializer#canBeSpatialized() */ diff --git a/services/core/java/com/android/server/audio/AudioSystemAdapter.java b/services/core/java/com/android/server/audio/AudioSystemAdapter.java index 6d567807f357..ac212eee21e6 100644 --- a/services/core/java/com/android/server/audio/AudioSystemAdapter.java +++ b/services/core/java/com/android/server/audio/AudioSystemAdapter.java @@ -17,6 +17,7 @@ package com.android.server.audio; import android.annotation.NonNull; +import android.annotation.Nullable; import android.media.AudioAttributes; import android.media.AudioDeviceAttributes; import android.media.AudioSystem; @@ -24,6 +25,8 @@ import android.media.audiopolicy.AudioMix; import android.os.SystemClock; import android.util.Log; +import com.android.internal.annotations.GuardedBy; + import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; @@ -59,6 +62,9 @@ public class AudioSystemAdapter implements AudioSystem.RoutingUpdateCallback { private ConcurrentHashMap<AudioAttributes, ArrayList<AudioDeviceAttributes>> mDevicesForAttrCache; private int[] mMethodCacheHit; + private static final Object sRoutingListenerLock = new Object(); + @GuardedBy("sRoutingListenerLock") + private static @Nullable OnRoutingUpdatedListener sRoutingListener; /** * should be false except when trying to debug caching errors. When true, the value retrieved @@ -76,6 +82,23 @@ public class AudioSystemAdapter implements AudioSystem.RoutingUpdateCallback { Log.d(TAG, "---- onRoutingUpdated (from native) ----------"); } invalidateRoutingCache(); + final OnRoutingUpdatedListener listener; + synchronized (sRoutingListenerLock) { + listener = sRoutingListener; + } + if (listener != null) { + listener.onRoutingUpdatedFromNative(); + } + } + + interface OnRoutingUpdatedListener { + void onRoutingUpdatedFromNative(); + } + + static void setRoutingListener(@Nullable OnRoutingUpdatedListener listener) { + synchronized (sRoutingListenerLock) { + sRoutingListener = listener; + } } /** diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java index 708d9e10ad73..2ca100c91043 100644 --- a/services/core/java/com/android/server/audio/SpatializerHelper.java +++ b/services/core/java/com/android/server/audio/SpatializerHelper.java @@ -17,9 +17,13 @@ package com.android.server.audio; import android.annotation.NonNull; +import android.annotation.Nullable; import android.media.AudioAttributes; import android.media.AudioDeviceAttributes; import android.media.AudioFormat; +import android.media.AudioSystem; +import android.media.INativeSpatializerCallback; +import android.media.ISpatializer; import android.media.ISpatializerCallback; import android.media.Spatializer; import android.os.RemoteCallbackList; @@ -28,6 +32,7 @@ import android.util.Log; import java.util.ArrayList; import java.util.List; +import java.util.Locale; /** * A helper class to manage Spatializer related functionality @@ -35,12 +40,167 @@ import java.util.List; public class SpatializerHelper { private static final String TAG = "AS.SpatializerHelper"; + private static final boolean DEBUG = true; + + private static void logd(String s) { + if (DEBUG) { + Log.i(TAG, s); + } + } + + private final @NonNull AudioSystemAdapter mASA; + private final @NonNull AudioService mAudioService; + + //------------------------------------------------------------ + // Spatializer state machine + private static final int STATE_UNINITIALIZED = 0; + private static final int STATE_NOT_SUPPORTED = 1; + private static final int STATE_DISABLED_UNAVAILABLE = 3; + private static final int STATE_ENABLED_UNAVAILABLE = 4; + private static final int STATE_ENABLED_AVAILABLE = 5; + private static final int STATE_DISABLED_AVAILABLE = 6; + private int mState = STATE_UNINITIALIZED; + + /** current level as reported by native Spatializer in callback */ + private int mSpatLevel = Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE; + private int mCapableSpatLevel = Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE; + private @Nullable ISpatializer mSpat; + private @Nullable SpatializerCallback mSpatCallback; + + // default attributes and format that determine basic availability of spatialization + private static final AudioAttributes DEFAULT_ATTRIBUTES = new AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_MEDIA) + .build(); + private static final AudioFormat DEFAULT_FORMAT = new AudioFormat.Builder() + .setEncoding(AudioFormat.ENCODING_PCM_16BIT) + .setSampleRate(48000) + .setChannelMask(AudioFormat.CHANNEL_OUT_5POINT1) + .build(); + // device array to store the routing for the default attributes and format, size 1 because + // media is never expected to be duplicated + private static final AudioDeviceAttributes[] ROUTING_DEVICES = new AudioDeviceAttributes[1]; //--------------------------------------------------------------- // audio device compatibility / enabled private final ArrayList<AudioDeviceAttributes> mCompatibleAudioDevices = new ArrayList<>(0); + //------------------------------------------------------ + // initialization + SpatializerHelper(@NonNull AudioService mother, @NonNull AudioSystemAdapter asa) { + mAudioService = mother; + mASA = asa; + } + + synchronized void init() { + Log.i(TAG, "Initializing"); + if (mState != STATE_UNINITIALIZED) { + throw new IllegalStateException(("init() called in state:" + mState)); + } + // is there a spatializer? + mSpatCallback = new SpatializerCallback(); + final ISpatializer spat = AudioSystem.getSpatializer(mSpatCallback); + if (spat == null) { + Log.i(TAG, "init(): No Spatializer found"); + mState = STATE_NOT_SUPPORTED; + return; + } + // capabilities of spatializer? + try { + byte[] levels = spat.getSupportedLevels(); + if (levels == null + || levels.length == 0 + || (levels.length == 1 + && levels[0] == Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE)) { + Log.e(TAG, "Spatializer is useless"); + mState = STATE_NOT_SUPPORTED; + return; + } + for (byte level : levels) { + logd("found support for level: " + level); + if (level == Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_MULTICHANNEL) { + logd("Setting Spatializer to LEVEL_MULTICHANNEL"); + mCapableSpatLevel = level; + break; + } + } + } catch (RemoteException e) { /* capable level remains at NONE*/ } + if (mCapableSpatLevel == Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE) { + mState = STATE_NOT_SUPPORTED; + return; + } + mState = STATE_DISABLED_UNAVAILABLE; + // note at this point mSpat is still not instantiated + } + + /** + * Like init() but resets the state and spatializer levels + * @param featureEnabled + */ + synchronized void reset(boolean featureEnabled) { + Log.i(TAG, "Resetting"); + mState = STATE_UNINITIALIZED; + mSpatLevel = Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE; + mCapableSpatLevel = Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE; + init(); + setFeatureEnabled(featureEnabled); + } + + //------------------------------------------------------ + // routing monitoring + void onRoutingUpdated() { + switch (mState) { + case STATE_UNINITIALIZED: + case STATE_NOT_SUPPORTED: + return; + case STATE_DISABLED_UNAVAILABLE: + case STATE_ENABLED_UNAVAILABLE: + case STATE_ENABLED_AVAILABLE: + case STATE_DISABLED_AVAILABLE: + break; + } + mASA.getDevicesForAttributes(DEFAULT_ATTRIBUTES).toArray(ROUTING_DEVICES); + final boolean able = + AudioSystem.canBeSpatialized(DEFAULT_ATTRIBUTES, DEFAULT_FORMAT, ROUTING_DEVICES); + logd("onRoutingUpdated: can spatialize media 5.1:" + able + + " on device:" + ROUTING_DEVICES[0]); + setDispatchAvailableState(able); + } + + //------------------------------------------------------ + // spatializer callback from native + private final class SpatializerCallback extends INativeSpatializerCallback.Stub { + + public void onLevelChanged(byte level) { + logd("SpatializerCallback.onLevelChanged level:" + level); + synchronized (SpatializerHelper.this) { + mSpatLevel = level; + } + // TODO use reported spat level to change state + } + + public void onHeadTrackingModeChanged(byte mode) { + logd("SpatializerCallback.onHeadTrackingModeChanged mode:" + mode); + } + + public void onHeadToSoundStagePoseUpdated(float[] headToStage) { + if (headToStage == null) { + Log.e(TAG, "SpatializerCallback.onHeadToStagePoseUpdated null transform"); + return; + } + if (DEBUG) { + // 6 values * (4 digits + 1 dot + 2 brackets) = 42 characters + StringBuilder t = new StringBuilder(42); + for (float val : headToStage) { + t.append("[").append(String.format(Locale.ENGLISH, "%.3f", val)).append("]"); + } + logd("SpatializerCallback.onHeadToStagePoseUpdated headToStage:" + t); + } + } + }; + + //------------------------------------------------------ + // compatible devices /** * @return a shallow copy of the list of compatible audio devices */ @@ -59,37 +219,72 @@ public class SpatializerHelper { } //------------------------------------------------------ - // enabled state - - // global state of feature - boolean mFeatureEnabled = false; - // initialized state, checked after each audio_server start - boolean mInitialized = false; + // states synchronized boolean isEnabled() { - return mFeatureEnabled; + switch (mState) { + case STATE_UNINITIALIZED: + case STATE_NOT_SUPPORTED: + case STATE_DISABLED_UNAVAILABLE: + case STATE_DISABLED_AVAILABLE: + return false; + case STATE_ENABLED_UNAVAILABLE: + case STATE_ENABLED_AVAILABLE: + default: + return true; + } } synchronized boolean isAvailable() { - if (!mInitialized) { - return false; + switch (mState) { + case STATE_UNINITIALIZED: + case STATE_NOT_SUPPORTED: + case STATE_ENABLED_UNAVAILABLE: + case STATE_DISABLED_UNAVAILABLE: + return false; + case STATE_DISABLED_AVAILABLE: + case STATE_ENABLED_AVAILABLE: + default: + return true; } - // TODO check device compatibility - // ... - return true; } - synchronized void setEnabled(boolean enabled) { - final boolean oldState = mFeatureEnabled; - mFeatureEnabled = enabled; - if (oldState != enabled) { - dispatchEnabledState(); + synchronized void setFeatureEnabled(boolean enabled) { + switch (mState) { + case STATE_UNINITIALIZED: + if (enabled) { + throw(new IllegalStateException("Can't enable when uninitialized")); + } + return; + case STATE_NOT_SUPPORTED: + if (enabled) { + Log.e(TAG, "Can't enable when unsupported"); + } + return; + case STATE_DISABLED_UNAVAILABLE: + case STATE_DISABLED_AVAILABLE: + if (enabled) { + createSpat(); + break; + } else { + // already in disabled state + return; + } + case STATE_ENABLED_UNAVAILABLE: + case STATE_ENABLED_AVAILABLE: + if (!enabled) { + releaseSpat(); + break; + } else { + // already in enabled state + return; + } } + setDispatchFeatureEnabledState(enabled); } - public int getImmersiveAudioLevel() { - // TODO replace placeholder code with actual effect discovery - return Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE; + synchronized int getCapableImmersiveAudioLevel() { + return mCapableSpatLevel; } final RemoteCallbackList<ISpatializerCallback> mStateCallbacks = @@ -105,24 +300,168 @@ public class SpatializerHelper { mStateCallbacks.unregister(callback); } - private synchronized void dispatchEnabledState() { + /** + * precondition: mState = STATE_* + * isFeatureEnabled() != featureEnabled + * @param featureEnabled + */ + private synchronized void setDispatchFeatureEnabledState(boolean featureEnabled) { + if (featureEnabled) { + switch (mState) { + case STATE_DISABLED_UNAVAILABLE: + mState = STATE_ENABLED_UNAVAILABLE; + break; + case STATE_DISABLED_AVAILABLE: + mState = STATE_ENABLED_AVAILABLE; + break; + default: + throw(new IllegalStateException("Invalid mState:" + mState + + " for enabled true")); + } + } else { + switch (mState) { + case STATE_ENABLED_UNAVAILABLE: + mState = STATE_DISABLED_UNAVAILABLE; + break; + case STATE_ENABLED_AVAILABLE: + mState = STATE_DISABLED_AVAILABLE; + break; + default: + throw (new IllegalStateException("Invalid mState:" + mState + + " for enabled false")); + } + } final int nbCallbacks = mStateCallbacks.beginBroadcast(); for (int i = 0; i < nbCallbacks; i++) { try { mStateCallbacks.getBroadcastItem(i) - .dispatchSpatializerEnabledChanged(mFeatureEnabled); + .dispatchSpatializerEnabledChanged(featureEnabled); } catch (RemoteException e) { Log.e(TAG, "Error in dispatchSpatializerEnabledChanged", e); } } mStateCallbacks.finishBroadcast(); + // TODO persist enabled state + } + + private synchronized void setDispatchAvailableState(boolean available) { + switch (mState) { + case STATE_UNINITIALIZED: + case STATE_NOT_SUPPORTED: + throw(new IllegalStateException( + "Should not update available state in state:" + mState)); + case STATE_DISABLED_UNAVAILABLE: + if (available) { + mState = STATE_DISABLED_AVAILABLE; + break; + } else { + // already in unavailable state + return; + } + case STATE_ENABLED_UNAVAILABLE: + if (available) { + mState = STATE_ENABLED_AVAILABLE; + break; + } else { + // already in unavailable state + return; + } + case STATE_DISABLED_AVAILABLE: + if (available) { + // already in available state + return; + } else { + mState = STATE_DISABLED_UNAVAILABLE; + break; + } + case STATE_ENABLED_AVAILABLE: + if (available) { + // already in available state + return; + } else { + mState = STATE_ENABLED_UNAVAILABLE; + break; + } + } + final int nbCallbacks = mStateCallbacks.beginBroadcast(); + for (int i = 0; i < nbCallbacks; i++) { + try { + mStateCallbacks.getBroadcastItem(i) + .dispatchSpatializerAvailableChanged(available); + } catch (RemoteException e) { + Log.e(TAG, "Error in dispatchSpatializerEnabledChanged", e); + } + } + mStateCallbacks.finishBroadcast(); + } + + //------------------------------------------------------ + // native Spatializer management + + /** + * precondition: mState == STATE_DISABLED_* + */ + private void createSpat() { + if (mSpat == null) { + mSpatCallback = new SpatializerCallback(); + mSpat = AudioSystem.getSpatializer(mSpatCallback); + try { + mSpat.setLevel((byte) Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_MULTICHANNEL); + } catch (RemoteException e) { + Log.e(TAG, "Can't set spatializer level", e); + mState = STATE_NOT_SUPPORTED; + mCapableSpatLevel = Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE; + } + } + } + + /** + * precondition: mState == STATE_ENABLED_* + */ + private void releaseSpat() { + if (mSpat != null) { + mSpatCallback = null; + try { + mSpat.release(); + mSpat = null; + } catch (RemoteException e) { + Log.e(TAG, "Can't set release spatializer cleanly", e); + } + } } //------------------------------------------------------ // virtualization capabilities synchronized boolean canBeSpatialized( @NonNull AudioAttributes attributes, @NonNull AudioFormat format) { - // TODO hook up to spatializer effect for query - return false; + logd("canBeSpatialized usage:" + attributes.getUsage() + + " format:" + format.toLogFriendlyString()); + switch (mState) { + case STATE_UNINITIALIZED: + case STATE_NOT_SUPPORTED: + case STATE_ENABLED_UNAVAILABLE: + case STATE_DISABLED_UNAVAILABLE: + logd("canBeSpatialized false due to state:" + mState); + return false; + case STATE_DISABLED_AVAILABLE: + case STATE_ENABLED_AVAILABLE: + break; + } + + // filter on AudioAttributes usage + switch (attributes.getUsage()) { + case AudioAttributes.USAGE_MEDIA: + case AudioAttributes.USAGE_GAME: + break; + default: + logd("canBeSpatialized false due to usage:" + attributes.getUsage()); + return false; + } + AudioDeviceAttributes[] devices = + // going through adapter to take advantage of routing cache + (AudioDeviceAttributes[]) mASA.getDevicesForAttributes(attributes).toArray(); + final boolean able = AudioSystem.canBeSpatialized(attributes, format, devices); + logd("canBeSpatialized returning " + able); + return able; } } |