diff options
15 files changed, 366 insertions, 185 deletions
diff --git a/config/preloaded-classes b/config/preloaded-classes index 29f6055ec6a5..5e88d97db91f 100644 --- a/config/preloaded-classes +++ b/config/preloaded-classes @@ -3716,9 +3716,9 @@ android.media.IRemoteVolumeObserver android.media.IRingtonePlayer$Stub$Proxy android.media.IRingtonePlayer$Stub android.media.IRingtonePlayer -android.media.IStrategyPreferredDeviceDispatcher$Stub$Proxy -android.media.IStrategyPreferredDeviceDispatcher$Stub -android.media.IStrategyPreferredDeviceDispatcher +android.media.IStrategyPreferredDevicesDispatcher$Stub$Proxy +android.media.IStrategyPreferredDevicesDispatcher$Stub +android.media.IStrategyPreferredDevicesDispatcher android.media.IVolumeController$Stub$Proxy android.media.IVolumeController$Stub android.media.IVolumeController diff --git a/core/api/system-current.txt b/core/api/system-current.txt index ad43ad66aa83..05d7bb6da361 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -4145,7 +4145,8 @@ package android.media { public class AudioManager { method @Deprecated public int abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes); - method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDeviceForStrategyChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDeviceForStrategyChangedListener) throws java.lang.SecurityException; + method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDeviceForStrategyChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDeviceForStrategyChangedListener) throws java.lang.SecurityException; + method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDevicesForStrategyChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDevicesForStrategyChangedListener) throws java.lang.SecurityException; method public void clearAudioServerStateCallback(); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int dispatchAudioFocusChange(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy); method @IntRange(from=0) public long getAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo); @@ -4156,13 +4157,15 @@ package android.media { method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMaxVolumeIndexForAttributes(@NonNull android.media.AudioAttributes); method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMinVolumeIndexForAttributes(@NonNull android.media.AudioAttributes); method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.media.AudioDeviceAttributes getPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy); + method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioDeviceAttributes> getPreferredDevicesForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy); method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int[] getSupportedSystemUsages(); method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getVolumeIndexForAttributes(@NonNull android.media.AudioAttributes); method public boolean isAudioServerRunning(); method public boolean isHdmiSystemAudioSupported(); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int registerAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy); method public void registerVolumeGroupCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.VolumeGroupCallback); - method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnPreferredDeviceForStrategyChangedListener(@NonNull android.media.AudioManager.OnPreferredDeviceForStrategyChangedListener); + method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnPreferredDeviceForStrategyChangedListener(@NonNull android.media.AudioManager.OnPreferredDeviceForStrategyChangedListener); + method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnPreferredDevicesForStrategyChangedListener(@NonNull android.media.AudioManager.OnPreferredDevicesForStrategyChangedListener); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean removePreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, @NonNull android.media.AudioAttributes, int, int) throws java.lang.IllegalArgumentException; method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.MODIFY_AUDIO_ROUTING}) public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, @NonNull android.media.AudioAttributes, int, int, android.media.audiopolicy.AudioPolicy) throws java.lang.IllegalArgumentException; @@ -4171,6 +4174,7 @@ package android.media { method public void setAudioServerStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioServerStateCallback); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setFocusRequestResult(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull android.media.AudioDeviceAttributes); + method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDevicesForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull java.util.List<android.media.AudioDeviceAttributes>); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setSupportedSystemUsages(@NonNull int[]); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setVolumeIndexForAttributes(@NonNull android.media.AudioAttributes, int, int); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void unregisterAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy); @@ -4189,8 +4193,12 @@ package android.media { method public void onAudioServerUp(); } - public static interface AudioManager.OnPreferredDeviceForStrategyChangedListener { - method public void onPreferredDeviceForStrategyChanged(@NonNull android.media.audiopolicy.AudioProductStrategy, @Nullable android.media.AudioDeviceAttributes); + @Deprecated public static interface AudioManager.OnPreferredDeviceForStrategyChangedListener { + method @Deprecated public void onPreferredDeviceForStrategyChanged(@NonNull android.media.audiopolicy.AudioProductStrategy, @Nullable android.media.AudioDeviceAttributes); + } + + public static interface AudioManager.OnPreferredDevicesForStrategyChangedListener { + method public void onPreferredDevicesForStrategyChanged(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull java.util.List<android.media.AudioDeviceAttributes>); } public abstract static class AudioManager.VolumeGroupCallback { diff --git a/core/api/test-current.txt b/core/api/test-current.txt index feadd06761f9..b6bd687a3a88 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -871,6 +871,9 @@ package android.media { method public static float getMasterBalance(); method public static final int getNumStreamTypes(); method public static int setMasterBalance(float); + field public static final int DEVICE_ROLE_DISABLED = 2; // 0x2 + field public static final int DEVICE_ROLE_NONE = 0; // 0x0 + field public static final int DEVICE_ROLE_PREFERRED = 1; // 0x1 field public static final int STREAM_DEFAULT = -1; // 0xffffffff } diff --git a/core/jni/android_media_AudioDeviceAttributes.cpp b/core/jni/android_media_AudioDeviceAttributes.cpp index e79c95edbeb5..2a16dce99125 100644 --- a/core/jni/android_media_AudioDeviceAttributes.cpp +++ b/core/jni/android_media_AudioDeviceAttributes.cpp @@ -31,7 +31,7 @@ jint createAudioDeviceAttributesFromNative(JNIEnv *env, jobject *jAudioDeviceAtt const AudioDeviceTypeAddr *devTypeAddr) { jint jStatus = (jint)AUDIO_JAVA_SUCCESS; jint jNativeType = (jint)devTypeAddr->mType; - ScopedLocalRef<jstring> jAddress(env, env->NewStringUTF(devTypeAddr->mAddress.data())); + ScopedLocalRef<jstring> jAddress(env, env->NewStringUTF(devTypeAddr->getAddress())); *jAudioDeviceAttributes = env->NewObject(gAudioDeviceAttributesClass, gAudioDeviceAttributesCstor, jNativeType, jAddress.get()); diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index c4a06567c48d..ae725259d0ca 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -172,6 +172,8 @@ static struct { jmethodID postRecordConfigEventFromNative; } gAudioPolicyEventHandlerMethods; +static struct { jmethodID add; } gListMethods; + // // JNI Initialization for OpenSLES routing // @@ -2362,48 +2364,48 @@ android_media_AudioSystem_isCallScreeningModeSupported(JNIEnv *env, jobject thiz return AudioSystem::isCallScreenModeSupported(); } -static jint -android_media_AudioSystem_setPreferredDeviceForStrategy(JNIEnv *env, jobject thiz, - jint strategy, jint deviceType, jstring deviceAddress) { - - const char *c_address = env->GetStringUTFChars(deviceAddress, NULL); +static jint android_media_AudioSystem_setDevicesRoleForStrategy(JNIEnv *env, jobject thiz, + jint strategy, jint role, + jintArray jDeviceTypes, + jobjectArray jDeviceAddresses) { + AudioDeviceTypeAddrVector nDevices; + jint results = getVectorOfAudioDeviceTypeAddr(env, jDeviceTypes, jDeviceAddresses, nDevices); + if (results != NO_ERROR) { + return results; + } int status = check_AudioSystem_Command( - AudioSystem::setPreferredDeviceForStrategy((product_strategy_t)strategy, - AudioDeviceTypeAddr((audio_devices_t) - deviceType, - c_address))); - env->ReleaseStringUTFChars(deviceAddress, c_address); + AudioSystem::setDevicesRoleForStrategy((product_strategy_t)strategy, + (device_role_t)role, nDevices)); return (jint) status; } -static jint -android_media_AudioSystem_removePreferredDeviceForStrategy(JNIEnv *env, jobject thiz, jint strategy) -{ - return (jint) check_AudioSystem_Command( - AudioSystem::removePreferredDeviceForStrategy((product_strategy_t) strategy)); +static jint android_media_AudioSystem_removeDevicesRoleForStrategy(JNIEnv *env, jobject thiz, + jint strategy, jint role) { + return (jint)check_AudioSystem_Command( + AudioSystem::removeDevicesRoleForStrategy((product_strategy_t)strategy, + (device_role_t)role)); } -static jint -android_media_AudioSystem_getPreferredDeviceForStrategy(JNIEnv *env, jobject thiz, - jint strategy, jobjectArray jDeviceArray) -{ - if (jDeviceArray == nullptr || env->GetArrayLength(jDeviceArray) != 1) { - ALOGE("%s invalid array to store AudioDeviceAttributes", __FUNCTION__); - return (jint)AUDIO_JAVA_BAD_VALUE; - } - - AudioDeviceTypeAddr elDevice; +static jint android_media_AudioSystem_getDevicesForRoleAndStrategy(JNIEnv *env, jobject thiz, + jint strategy, jint role, + jobject jDevices) { + AudioDeviceTypeAddrVector nDevices; status_t status = check_AudioSystem_Command( - AudioSystem::getPreferredDeviceForStrategy((product_strategy_t) strategy, elDevice)); + AudioSystem::getDevicesForRoleAndStrategy((product_strategy_t)strategy, + (device_role_t)role, nDevices)); if (status != NO_ERROR) { return (jint) status; } - jobject jAudioDeviceAttributes = NULL; - jint jStatus = createAudioDeviceAttributesFromNative(env, &jAudioDeviceAttributes, &elDevice); - if (jStatus == AUDIO_JAVA_SUCCESS) { - env->SetObjectArrayElement(jDeviceArray, 0, jAudioDeviceAttributes); + for (const auto &device : nDevices) { + jobject jAudioDeviceAttributes = NULL; + jint jStatus = createAudioDeviceAttributesFromNative(env, &jAudioDeviceAttributes, &device); + if (jStatus != AUDIO_JAVA_SUCCESS) { + return jStatus; + } + env->CallBooleanMethod(jDevices, gListMethods.add, jAudioDeviceAttributes); + env->DeleteLocalRef(jAudioDeviceAttributes); } - return jStatus; + return AUDIO_JAVA_SUCCESS; } static jint @@ -2551,12 +2553,12 @@ static const JNINativeMethod gMethods[] = {"setAudioHalPids", "([I)I", (void *)android_media_AudioSystem_setAudioHalPids}, {"isCallScreeningModeSupported", "()Z", (void *)android_media_AudioSystem_isCallScreeningModeSupported}, - {"setPreferredDeviceForStrategy", "(IILjava/lang/String;)I", - (void *)android_media_AudioSystem_setPreferredDeviceForStrategy}, - {"removePreferredDeviceForStrategy", "(I)I", - (void *)android_media_AudioSystem_removePreferredDeviceForStrategy}, - {"getPreferredDeviceForStrategy", "(I[Landroid/media/AudioDeviceAttributes;)I", - (void *)android_media_AudioSystem_getPreferredDeviceForStrategy}, + {"setDevicesRoleForStrategy", "(II[I[Ljava/lang/String;)I", + (void *)android_media_AudioSystem_setDevicesRoleForStrategy}, + {"removeDevicesRoleForStrategy", "(II)I", + (void *)android_media_AudioSystem_removeDevicesRoleForStrategy}, + {"getDevicesForRoleAndStrategy", "(IILjava/util/List;)I", + (void *)android_media_AudioSystem_getDevicesForRoleAndStrategy}, {"getDevicesForAttributes", "(Landroid/media/AudioAttributes;[Landroid/media/AudioDeviceAttributes;)I", (void *)android_media_AudioSystem_getDevicesForAttributes}, @@ -2758,6 +2760,9 @@ int register_android_media_AudioSystem(JNIEnv *env) gMidAudioRecordRoutingProxy_release = android::GetMethodIDOrDie(env, gClsAudioRecordRoutingProxy, "native_release", "()V"); + jclass listClass = FindClassOrDie(env, "java/util/List"); + gListMethods.add = GetMethodIDOrDie(env, listClass, "add", "(Ljava/lang/Object;)Z"); + AudioSystem::addErrorCallback(android_media_AudioSystem_error_callback); RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods)); diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 107d6565a29e..b33003737ccd 100755 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -75,6 +75,7 @@ import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -1598,11 +1599,25 @@ public class AudioManager { @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy, @NonNull AudioDeviceAttributes device) { + return setPreferredDevicesForStrategy(strategy, Arrays.asList(device)); + } + + /** + * @hide + * Removes the preferred audio device(s) previously set with + * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or + * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}. + * @param strategy the audio strategy whose routing will be affected + * @return true if the operation was successful, false otherwise (invalid strategy, or no + * device set for example) + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + public boolean removePreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy) { Objects.requireNonNull(strategy); - Objects.requireNonNull(device); try { final int status = - getService().setPreferredDeviceForStrategy(strategy.getId(), device); + getService().removePreferredDevicesForStrategy(strategy.getId()); return status == AudioSystem.SUCCESS; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -1611,19 +1626,52 @@ public class AudioManager { /** * @hide - * Removes the preferred audio device previously set with - * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)}. + * Return the preferred device for an audio strategy, previously set with + * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or + * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)} + * @param strategy the strategy to query + * @return the preferred device for that strategy, if multiple devices are set as preferred + * devices, the first one in the list will be returned. Null will be returned if none was + * ever set or if the strategy is invalid + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + @Nullable + public AudioDeviceAttributes getPreferredDeviceForStrategy( + @NonNull AudioProductStrategy strategy) { + List<AudioDeviceAttributes> devices = getPreferredDevicesForStrategy(strategy); + return devices.isEmpty() ? null : devices.get(0); + } + + /** + * @hide + * Set the preferred devices for a given strategy, i.e. the audio routing to be used by + * this audio strategy. Note that the devices may not be available at the time the preferred + * devices is set, but it will be used once made available. + * <p>Use {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} to cancel setting + * this preference for this strategy.</p> + * Note that the list of devices is not a list ranked by preference, but a list of one or more + * devices used simultaneously to output the same audio signal. * @param strategy the audio strategy whose routing will be affected - * @return true if the operation was successful, false otherwise (invalid strategy, or no - * device set for example) + * @param devices a non-empty list of the audio devices to route to when available + * @return true if the operation was successful, false otherwise */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) - public boolean removePreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy) { + public boolean setPreferredDevicesForStrategy(@NonNull AudioProductStrategy strategy, + @NonNull List<AudioDeviceAttributes> devices) { Objects.requireNonNull(strategy); + Objects.requireNonNull(devices); + if (devices.isEmpty()) { + throw new IllegalArgumentException( + "Tried to set preferred devices for strategy with a empty list"); + } + for (AudioDeviceAttributes device : devices) { + Objects.requireNonNull(device); + } try { final int status = - getService().removePreferredDeviceForStrategy(strategy.getId()); + getService().setPreferredDevicesForStrategy(strategy.getId(), devices); return status == AudioSystem.SUCCESS; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -1632,19 +1680,21 @@ public class AudioManager { /** * @hide - * Return the preferred device for an audio strategy, previously set with + * Return the preferred devices for an audio strategy, previously set with * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} + * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)} * @param strategy the strategy to query * @return the preferred device for that strategy, or null if none was ever set or if the * strategy is invalid */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) - public @Nullable AudioDeviceAttributes getPreferredDeviceForStrategy( + @NonNull + public List<AudioDeviceAttributes> getPreferredDevicesForStrategy( @NonNull AudioProductStrategy strategy) { Objects.requireNonNull(strategy); try { - return getService().getPreferredDeviceForStrategy(strategy.getId()); + return getService().getPreferredDevicesForStrategy(strategy.getId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1656,6 +1706,7 @@ public class AudioManager { * strategy. * <p>Note that this listener will only be invoked whenever * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or + * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)} * {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in * preferred device. It will not be invoked directly after registration with * {@link #addOnPreferredDeviceForStrategyChangedListener(Executor, OnPreferredDeviceForStrategyChangedListener)} @@ -1663,8 +1714,10 @@ public class AudioManager { * @see #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes) * @see #removePreferredDeviceForStrategy(AudioProductStrategy) * @see #getPreferredDeviceForStrategy(AudioProductStrategy) + * @deprecated use #OnPreferredDevicesForStrategyChangedListener */ @SystemApi + @Deprecated public interface OnPreferredDeviceForStrategyChangedListener { /** * Called on the listener to indicate that the preferred audio device for the given @@ -1679,23 +1732,87 @@ public class AudioManager { /** * @hide + * Interface to be notified of changes in the preferred audio devices set for a given audio + * strategy. + * <p>Note that this listener will only be invoked whenever + * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or + * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)} + * {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in + * preferred device(s). It will not be invoked directly after registration with + * {@link #addOnPreferredDevicesForStrategyChangedListener( + * Executor, OnPreferredDevicesForStrategyChangedListener)} + * to indicate which strategies had preferred devices at the time of registration.</p> + * @see #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes) + * @see #setPreferredDevicesForStrategy(AudioProductStrategy, List) + * @see #removePreferredDeviceForStrategy(AudioProductStrategy) + * @see #getPreferredDeviceForStrategy(AudioProductStrategy) + * @see #getPreferredDevicesForStrategy(AudioProductStrategy) + */ + @SystemApi + public interface OnPreferredDevicesForStrategyChangedListener { + /** + * Called on the listener to indicate that the preferred audio devices for the given + * strategy has changed. + * @param strategy the {@link AudioProductStrategy} whose preferred device changed + * @param devices a list of newly set preferred audio devices + */ + void onPreferredDevicesForStrategyChanged(@NonNull AudioProductStrategy strategy, + @NonNull List<AudioDeviceAttributes> devices); + } + + /** + * @hide * Adds a listener for being notified of changes to the strategy-preferred audio device. * @param executor * @param listener * @throws SecurityException if the caller doesn't hold the required permission + * @deprecated use {@link #addOnPreferredDevicesForStrategyChangedListener( + * Executor, AudioManager.OnPreferredDevicesForStrategyChangedListener)} instead */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + @Deprecated public void addOnPreferredDeviceForStrategyChangedListener( @NonNull @CallbackExecutor Executor executor, @NonNull OnPreferredDeviceForStrategyChangedListener listener) throws SecurityException { + // No-op, the method is deprecated. + } + + /** + * @hide + * Removes a previously added listener of changes to the strategy-preferred audio device. + * @param listener + * @deprecated use {@link #removeOnPreferredDevicesForStrategyChangedListener( + * AudioManager.OnPreferredDevicesForStrategyChangedListener)} instead + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + @Deprecated + public void removeOnPreferredDeviceForStrategyChangedListener( + @NonNull OnPreferredDeviceForStrategyChangedListener listener) { + // No-op, the method is deprecated. + } + + /** + * @hide + * Adds a listener for being notified of changes to the strategy-preferred audio device. + * @param executor + * @param listener + * @throws SecurityException if the caller doesn't hold the required permission + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + public void addOnPreferredDevicesForStrategyChangedListener( + @NonNull @CallbackExecutor Executor executor, + @NonNull OnPreferredDevicesForStrategyChangedListener listener) + throws SecurityException { Objects.requireNonNull(executor); Objects.requireNonNull(listener); synchronized (mPrefDevListenerLock) { if (hasPrefDevListener(listener)) { throw new IllegalArgumentException( - "attempt to call addOnPreferredDeviceForStrategyChangedListener() " + "attempt to call addOnPreferredDevicesForStrategyChangedListener() " + "on a previously registered listener"); } // lazy initialization of the list of strategy-preferred device listener @@ -1707,10 +1824,10 @@ public class AudioManager { if (oldCbCount == 0 && mPrefDevListeners.size() > 0) { // register binder for callbacks if (mPrefDevDispatcherStub == null) { - mPrefDevDispatcherStub = new StrategyPreferredDeviceDispatcherStub(); + mPrefDevDispatcherStub = new StrategyPreferredDevicesDispatcherStub(); } try { - getService().registerStrategyPreferredDeviceDispatcher(mPrefDevDispatcherStub); + getService().registerStrategyPreferredDevicesDispatcher(mPrefDevDispatcherStub); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1725,8 +1842,8 @@ public class AudioManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) - public void removeOnPreferredDeviceForStrategyChangedListener( - @NonNull OnPreferredDeviceForStrategyChangedListener listener) { + public void removeOnPreferredDevicesForStrategyChangedListener( + @NonNull OnPreferredDevicesForStrategyChangedListener listener) { Objects.requireNonNull(listener); synchronized (mPrefDevListenerLock) { if (!removePrefDevListener(listener)) { @@ -1737,7 +1854,7 @@ public class AudioManager { if (mPrefDevListeners.size() == 0) { // unregister binder for callbacks try { - getService().unregisterStrategyPreferredDeviceDispatcher( + getService().unregisterStrategyPreferredDevicesDispatcher( mPrefDevDispatcherStub); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -1759,23 +1876,23 @@ public class AudioManager { private @Nullable ArrayList<PrefDevListenerInfo> mPrefDevListeners; private static class PrefDevListenerInfo { - final @NonNull OnPreferredDeviceForStrategyChangedListener mListener; + final @NonNull OnPreferredDevicesForStrategyChangedListener mListener; final @NonNull Executor mExecutor; - PrefDevListenerInfo(OnPreferredDeviceForStrategyChangedListener listener, Executor exe) { + PrefDevListenerInfo(OnPreferredDevicesForStrategyChangedListener listener, Executor exe) { mListener = listener; mExecutor = exe; } } @GuardedBy("mPrefDevListenerLock") - private StrategyPreferredDeviceDispatcherStub mPrefDevDispatcherStub; + private StrategyPreferredDevicesDispatcherStub mPrefDevDispatcherStub; - private final class StrategyPreferredDeviceDispatcherStub - extends IStrategyPreferredDeviceDispatcher.Stub { + private final class StrategyPreferredDevicesDispatcherStub + extends IStrategyPreferredDevicesDispatcher.Stub { @Override - public void dispatchPrefDeviceChanged(int strategyId, - @Nullable AudioDeviceAttributes device) { + public void dispatchPrefDevicesChanged(int strategyId, + @NonNull List<AudioDeviceAttributes> devices) { // make a shallow copy of listeners so callback is not executed under lock final ArrayList<PrefDevListenerInfo> prefDevListeners; synchronized (mPrefDevListenerLock) { @@ -1790,7 +1907,7 @@ public class AudioManager { try { for (PrefDevListenerInfo info : prefDevListeners) { info.mExecutor.execute(() -> - info.mListener.onPreferredDeviceForStrategyChanged(strategy, device)); + info.mListener.onPreferredDevicesForStrategyChanged(strategy, devices)); } } finally { Binder.restoreCallingIdentity(ident); @@ -1800,7 +1917,7 @@ public class AudioManager { @GuardedBy("mPrefDevListenerLock") private @Nullable PrefDevListenerInfo getPrefDevListenerInfo( - OnPreferredDeviceForStrategyChangedListener listener) { + OnPreferredDevicesForStrategyChangedListener listener) { if (mPrefDevListeners == null) { return null; } @@ -1813,7 +1930,7 @@ public class AudioManager { } @GuardedBy("mPrefDevListenerLock") - private boolean hasPrefDevListener(OnPreferredDeviceForStrategyChangedListener listener) { + private boolean hasPrefDevListener(OnPreferredDevicesForStrategyChangedListener listener) { return getPrefDevListenerInfo(listener) != null; } @@ -1821,7 +1938,7 @@ public class AudioManager { /** * @return true if the listener was removed from the list */ - private boolean removePrefDevListener(OnPreferredDeviceForStrategyChangedListener listener) { + private boolean removePrefDevListener(OnPreferredDevicesForStrategyChangedListener listener) { final PrefDevListenerInfo infoToRemove = getPrefDevListenerInfo(listener); if (infoToRemove != null) { mPrefDevListeners.remove(infoToRemove); diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index f1eb53dda5b9..159048548ce8 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -33,6 +33,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; @@ -1371,6 +1372,11 @@ public class AudioSystem /** @hide */ public static final int FOR_VIBRATE_RINGING = 7; private static final int NUM_FORCE_USE = 8; + // Device role in audio policy + public static final int DEVICE_ROLE_NONE = 0; + public static final int DEVICE_ROLE_PREFERRED = 1; + public static final int DEVICE_ROLE_DISABLED = 2; + /** @hide */ public static String forceUseUsageToString(int usage) { switch (usage) { @@ -1691,47 +1697,58 @@ public class AudioSystem /** * @hide - * Sets the preferred device to use for a given audio strategy in the audio policy engine + * Set device as role for product strategy. * @param strategy the id of the strategy to configure - * @param device the device type and address to route to when available + * @param role the role of the devices + * @param devices the list of devices to be set as role for the given strategy * @return {@link #SUCCESS} if successfully set */ - public static int setPreferredDeviceForStrategy( - int strategy, @NonNull AudioDeviceAttributes device) { - return setPreferredDeviceForStrategy(strategy, - AudioDeviceInfo.convertDeviceTypeToInternalDevice(device.getType()), - device.getAddress()); + public static int setDevicesRoleForStrategy( + int strategy, int role, @NonNull List<AudioDeviceAttributes> devices) { + if (devices.isEmpty()) { + return BAD_VALUE; + } + int[] types = new int[devices.size()]; + String[] addresses = new String[devices.size()]; + for (int i = 0; i < devices.size(); ++i) { + types[i] = AudioDeviceInfo.convertDeviceTypeToInternalDevice(devices.get(i).getType()); + addresses[i] = devices.get(i).getAddress(); + } + return setDevicesRoleForStrategy(strategy, role, types, addresses); } + /** * @hide - * Set device routing per product strategy. + * Set device as role for product strategy. * @param strategy the id of the strategy to configure - * @param deviceType the native device type, NOT AudioDeviceInfo types - * @param deviceAddress the address of the device + * @param role the role of the devices + * @param types all device types + * @param addresses all device addresses * @return {@link #SUCCESS} if successfully set */ - private static native int setPreferredDeviceForStrategy( - int strategy, int deviceType, String deviceAddress); + private static native int setDevicesRoleForStrategy( + int strategy, int role, @NonNull int[] types, @NonNull String[] addresses); /** * @hide - * Remove preferred routing for the strategy + * Remove devices as role for the strategy * @param strategy the id of the strategy to configure + * @param role the role of the devices * @return {@link #SUCCESS} if successfully removed */ - public static native int removePreferredDeviceForStrategy(int strategy); + public static native int removeDevicesRoleForStrategy(int strategy, int role); /** * @hide - * Query previously set preferred device for a strategy + * Query previously set devices as role for a strategy * @param strategy the id of the strategy to query for - * @param device an array of size 1 that will contain the preferred device, or null if - * none was set + * @param role the role of the devices + * @param devices a list that will contain the devices of role * @return {@link #SUCCESS} if there is a preferred device and it was successfully retrieved * and written to the array */ - public static native int getPreferredDeviceForStrategy(int strategy, - AudioDeviceAttributes[] device); + public static native int getDevicesForRoleAndStrategy( + int strategy, int role, @NonNull List<AudioDeviceAttributes> devices); // Items shared with audio service diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 78806eb9e547..bc2839ea214d 100755 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -29,7 +29,7 @@ import android.media.IAudioServerStateDispatcher; import android.media.IPlaybackConfigDispatcher; import android.media.IRecordingConfigDispatcher; import android.media.IRingtonePlayer; -import android.media.IStrategyPreferredDeviceDispatcher; +import android.media.IStrategyPreferredDevicesDispatcher; import android.media.IVolumeController; import android.media.IVolumeController; import android.media.PlayerBase; @@ -279,11 +279,11 @@ interface IAudioService { boolean isCallScreeningModeSupported(); - int setPreferredDeviceForStrategy(in int strategy, in AudioDeviceAttributes device); + int setPreferredDevicesForStrategy(in int strategy, in List<AudioDeviceAttributes> device); - int removePreferredDeviceForStrategy(in int strategy); + int removePreferredDevicesForStrategy(in int strategy); - AudioDeviceAttributes getPreferredDeviceForStrategy(in int strategy); + List<AudioDeviceAttributes> getPreferredDevicesForStrategy(in int strategy); List<AudioDeviceAttributes> getDevicesForAttributes(in AudioAttributes attributes); @@ -291,10 +291,10 @@ interface IAudioService { int getAllowedCapturePolicy(); - void registerStrategyPreferredDeviceDispatcher(IStrategyPreferredDeviceDispatcher dispatcher); + void registerStrategyPreferredDevicesDispatcher(IStrategyPreferredDevicesDispatcher dispatcher); - oneway void unregisterStrategyPreferredDeviceDispatcher( - IStrategyPreferredDeviceDispatcher dispatcher); + oneway void unregisterStrategyPreferredDevicesDispatcher( + IStrategyPreferredDevicesDispatcher dispatcher); oneway void setRttEnabled(in boolean rttEnabled); diff --git a/media/java/android/media/IStrategyPreferredDeviceDispatcher.aidl b/media/java/android/media/IStrategyPreferredDevicesDispatcher.aidl index b1f99e6b729e..db674c36a5c9 100644 --- a/media/java/android/media/IStrategyPreferredDeviceDispatcher.aidl +++ b/media/java/android/media/IStrategyPreferredDevicesDispatcher.aidl @@ -19,12 +19,12 @@ package android.media; import android.media.AudioDeviceAttributes; /** - * AIDL for AudioService to signal audio strategy-preferred device updates. + * AIDL for AudioService to signal audio strategy-preferred devices updates. * * {@hide} */ -oneway interface IStrategyPreferredDeviceDispatcher { +oneway interface IStrategyPreferredDevicesDispatcher { - void dispatchPrefDeviceChanged(int strategyId, in AudioDeviceAttributes device); + void dispatchPrefDevicesChanged(int strategyId, in List<AudioDeviceAttributes> devices); } diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp index d55e9d0efffd..0d53ab152129 100644 --- a/media/jni/audioeffect/android_media_AudioEffect.cpp +++ b/media/jni/audioeffect/android_media_AudioEffect.cpp @@ -333,7 +333,7 @@ android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_t if (deviceType != AUDIO_DEVICE_NONE) { device.mType = (audio_devices_t)deviceType; ScopedUtfChars address(env, deviceAddress); - device.mAddress = address.c_str(); + device.setAddress(address.c_str()); } // create the native AudioEffect object diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index 074d3fe10816..5447605a36d1 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -28,7 +28,7 @@ import android.media.AudioDeviceAttributes; import android.media.AudioRoutesInfo; import android.media.AudioSystem; import android.media.IAudioRoutesObserver; -import android.media.IStrategyPreferredDeviceDispatcher; +import android.media.IStrategyPreferredDevicesDispatcher; import android.media.MediaMetrics; import android.os.Binder; import android.os.Handler; @@ -47,6 +47,7 @@ import com.android.internal.annotations.GuardedBy; import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashSet; +import java.util.List; import java.util.NoSuchElementException; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; @@ -526,23 +527,23 @@ import java.util.concurrent.atomic.AtomicBoolean; } } - /*package*/ int setPreferredDeviceForStrategySync(int strategy, - @NonNull AudioDeviceAttributes device) { - return mDeviceInventory.setPreferredDeviceForStrategySync(strategy, device); + /*package*/ int setPreferredDevicesForStrategySync(int strategy, + @NonNull List<AudioDeviceAttributes> devices) { + return mDeviceInventory.setPreferredDevicesForStrategySync(strategy, devices); } - /*package*/ int removePreferredDeviceForStrategySync(int strategy) { - return mDeviceInventory.removePreferredDeviceForStrategySync(strategy); + /*package*/ int removePreferredDevicesForStrategySync(int strategy) { + return mDeviceInventory.removePreferredDevicesForStrategySync(strategy); } - /*package*/ void registerStrategyPreferredDeviceDispatcher( - @NonNull IStrategyPreferredDeviceDispatcher dispatcher) { - mDeviceInventory.registerStrategyPreferredDeviceDispatcher(dispatcher); + /*package*/ void registerStrategyPreferredDevicesDispatcher( + @NonNull IStrategyPreferredDevicesDispatcher dispatcher) { + mDeviceInventory.registerStrategyPreferredDevicesDispatcher(dispatcher); } - /*package*/ void unregisterStrategyPreferredDeviceDispatcher( - @NonNull IStrategyPreferredDeviceDispatcher dispatcher) { - mDeviceInventory.unregisterStrategyPreferredDeviceDispatcher(dispatcher); + /*package*/ void unregisterStrategyPreferredDevicesDispatcher( + @NonNull IStrategyPreferredDevicesDispatcher dispatcher) { + mDeviceInventory.unregisterStrategyPreferredDevicesDispatcher(dispatcher); } //--------------------------------------------------------------------- @@ -683,14 +684,14 @@ import java.util.concurrent.atomic.AtomicBoolean; sendLMsgNoDelay(MSG_L_SPEAKERPHONE_CLIENT_DIED, SENDMSG_QUEUE, obj); } - /*package*/ void postSaveSetPreferredDeviceForStrategy(int strategy, - AudioDeviceAttributes device) + /*package*/ void postSaveSetPreferredDevicesForStrategy(int strategy, + List<AudioDeviceAttributes> devices) { - sendILMsgNoDelay(MSG_IL_SAVE_PREF_DEVICE_FOR_STRATEGY, SENDMSG_QUEUE, strategy, device); + sendILMsgNoDelay(MSG_IL_SAVE_PREF_DEVICES_FOR_STRATEGY, SENDMSG_QUEUE, strategy, devices); } - /*package*/ void postSaveRemovePreferredDeviceForStrategy(int strategy) { - sendIMsgNoDelay(MSG_I_SAVE_REMOVE_PREF_DEVICE_FOR_STRATEGY, SENDMSG_QUEUE, strategy); + /*package*/ void postSaveRemovePreferredDevicesForStrategy(int strategy) { + sendIMsgNoDelay(MSG_I_SAVE_REMOVE_PREF_DEVICES_FOR_STRATEGY, SENDMSG_QUEUE, strategy); } //--------------------------------------------------------------------- @@ -1084,14 +1085,15 @@ import java.util.concurrent.atomic.AtomicBoolean; info.mDevice, info.mState, info.mSupprNoisy, info.mMusicDevice); } } break; - case MSG_IL_SAVE_PREF_DEVICE_FOR_STRATEGY: { + case MSG_IL_SAVE_PREF_DEVICES_FOR_STRATEGY: { final int strategy = msg.arg1; - final AudioDeviceAttributes device = (AudioDeviceAttributes) msg.obj; - mDeviceInventory.onSaveSetPreferredDevice(strategy, device); + final List<AudioDeviceAttributes> devices = + (List<AudioDeviceAttributes>) msg.obj; + mDeviceInventory.onSaveSetPreferredDevices(strategy, devices); } break; - case MSG_I_SAVE_REMOVE_PREF_DEVICE_FOR_STRATEGY: { + case MSG_I_SAVE_REMOVE_PREF_DEVICES_FOR_STRATEGY: { final int strategy = msg.arg1; - mDeviceInventory.onSaveRemovePreferredDevice(strategy); + mDeviceInventory.onSaveRemovePreferredDevices(strategy); } break; case MSG_CHECK_MUTE_MUSIC: checkMessagesMuteMusic(0); @@ -1165,8 +1167,8 @@ import java.util.concurrent.atomic.AtomicBoolean; // a ScoClient died in BtHelper private static final int MSG_L_SCOCLIENT_DIED = 32; - private static final int MSG_IL_SAVE_PREF_DEVICE_FOR_STRATEGY = 33; - private static final int MSG_I_SAVE_REMOVE_PREF_DEVICE_FOR_STRATEGY = 34; + private static final int MSG_IL_SAVE_PREF_DEVICES_FOR_STRATEGY = 33; + private static final int MSG_I_SAVE_REMOVE_PREF_DEVICES_FOR_STRATEGY = 34; private static final int MSG_L_SPEAKERPHONE_CLIENT_DIED = 35; private static final int MSG_CHECK_MUTE_MUSIC = 36; diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java index 02a846e3dc82..fbf07cc591ff 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java +++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java @@ -16,7 +16,6 @@ package com.android.server.audio; import android.annotation.NonNull; -import android.annotation.Nullable; import android.app.ActivityManager; import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothAdapter; @@ -32,7 +31,7 @@ import android.media.AudioPort; import android.media.AudioRoutesInfo; import android.media.AudioSystem; import android.media.IAudioRoutesObserver; -import android.media.IStrategyPreferredDeviceDispatcher; +import android.media.IStrategyPreferredDevicesDispatcher; import android.media.MediaMetrics; import android.os.Binder; import android.os.RemoteCallbackList; @@ -51,6 +50,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedHashMap; +import java.util.List; import java.util.Set; /** @@ -137,7 +137,8 @@ public class AudioDeviceInventory { private final ArrayMap<Integer, String> mApmConnectedDevices = new ArrayMap<>(); // List of preferred devices for strategies - private final ArrayMap<Integer, AudioDeviceAttributes> mPreferredDevices = new ArrayMap<>(); + private final ArrayMap<Integer, List<AudioDeviceAttributes>> mPreferredDevices = + new ArrayMap<>(); // the wrapper for AudioSystem static methods, allows us to spy AudioSystem private final @NonNull AudioSystemAdapter mAudioSystem; @@ -150,8 +151,8 @@ public class AudioDeviceInventory { new RemoteCallbackList<IAudioRoutesObserver>(); // Monitoring of strategy-preferred device - final RemoteCallbackList<IStrategyPreferredDeviceDispatcher> mPrefDevDispatchers = - new RemoteCallbackList<IStrategyPreferredDeviceDispatcher>(); + final RemoteCallbackList<IStrategyPreferredDevicesDispatcher> mPrefDevDispatchers = + new RemoteCallbackList<IStrategyPreferredDevicesDispatcher>(); /*package*/ AudioDeviceInventory(@NonNull AudioDeviceBroker broker) { mDeviceBroker = broker; @@ -265,8 +266,9 @@ public class AudioDeviceInventory { } } synchronized (mPreferredDevices) { - mPreferredDevices.forEach((strategy, device) -> { - mAudioSystem.setPreferredDeviceForStrategy(strategy, device); }); + mPreferredDevices.forEach((strategy, devices) -> { + mAudioSystem.setDevicesRoleForStrategy( + strategy, AudioSystem.DEVICE_ROLE_PREFERRED, devices); }); } } @@ -600,49 +602,52 @@ public class AudioDeviceInventory { mmi.record(); } - /*package*/ void onSaveSetPreferredDevice(int strategy, @NonNull AudioDeviceAttributes device) { - mPreferredDevices.put(strategy, device); - dispatchPreferredDevice(strategy, device); + /*package*/ void onSaveSetPreferredDevices(int strategy, + @NonNull List<AudioDeviceAttributes> devices) { + mPreferredDevices.put(strategy, devices); + dispatchPreferredDevice(strategy, devices); } - /*package*/ void onSaveRemovePreferredDevice(int strategy) { + /*package*/ void onSaveRemovePreferredDevices(int strategy) { mPreferredDevices.remove(strategy); - dispatchPreferredDevice(strategy, null); + dispatchPreferredDevice(strategy, new ArrayList<AudioDeviceAttributes>()); } //------------------------------------------------------------ // - /*package*/ int setPreferredDeviceForStrategySync(int strategy, - @NonNull AudioDeviceAttributes device) { + /*package*/ int setPreferredDevicesForStrategySync(int strategy, + @NonNull List<AudioDeviceAttributes> devices) { final long identity = Binder.clearCallingIdentity(); - final int status = mAudioSystem.setPreferredDeviceForStrategy(strategy, device); + final int status = mAudioSystem.setDevicesRoleForStrategy( + strategy, AudioSystem.DEVICE_ROLE_PREFERRED, devices); Binder.restoreCallingIdentity(identity); if (status == AudioSystem.SUCCESS) { - mDeviceBroker.postSaveSetPreferredDeviceForStrategy(strategy, device); + mDeviceBroker.postSaveSetPreferredDevicesForStrategy(strategy, devices); } return status; } - /*package*/ int removePreferredDeviceForStrategySync(int strategy) { + /*package*/ int removePreferredDevicesForStrategySync(int strategy) { final long identity = Binder.clearCallingIdentity(); - final int status = mAudioSystem.removePreferredDeviceForStrategy(strategy); + final int status = mAudioSystem.removeDevicesRoleForStrategy( + strategy, AudioSystem.DEVICE_ROLE_PREFERRED); Binder.restoreCallingIdentity(identity); if (status == AudioSystem.SUCCESS) { - mDeviceBroker.postSaveRemovePreferredDeviceForStrategy(strategy); + mDeviceBroker.postSaveRemovePreferredDevicesForStrategy(strategy); } return status; } - /*package*/ void registerStrategyPreferredDeviceDispatcher( - @NonNull IStrategyPreferredDeviceDispatcher dispatcher) { + /*package*/ void registerStrategyPreferredDevicesDispatcher( + @NonNull IStrategyPreferredDevicesDispatcher dispatcher) { mPrefDevDispatchers.register(dispatcher); } - /*package*/ void unregisterStrategyPreferredDeviceDispatcher( - @NonNull IStrategyPreferredDeviceDispatcher dispatcher) { + /*package*/ void unregisterStrategyPreferredDevicesDispatcher( + @NonNull IStrategyPreferredDevicesDispatcher dispatcher) { mPrefDevDispatchers.unregister(dispatcher); } @@ -1288,11 +1293,13 @@ public class AudioDeviceInventory { } } - private void dispatchPreferredDevice(int strategy, @Nullable AudioDeviceAttributes device) { + private void dispatchPreferredDevice(int strategy, + @NonNull List<AudioDeviceAttributes> devices) { final int nbDispatchers = mPrefDevDispatchers.beginBroadcast(); for (int i = 0; i < nbDispatchers; i++) { try { - mPrefDevDispatchers.getBroadcastItem(i).dispatchPrefDeviceChanged(strategy, device); + mPrefDevDispatchers.getBroadcastItem(i).dispatchPrefDevicesChanged( + strategy, devices); } catch (RemoteException e) { } } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index a06f9ddcfc37..dda57d0aaba9 100755 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -87,7 +87,7 @@ import android.media.IAudioService; import android.media.IPlaybackConfigDispatcher; import android.media.IRecordingConfigDispatcher; import android.media.IRingtonePlayer; -import android.media.IStrategyPreferredDeviceDispatcher; +import android.media.IStrategyPreferredDevicesDispatcher; import android.media.IVolumeController; import android.media.MediaExtractor; import android.media.MediaFormat; @@ -171,6 +171,7 @@ import java.util.Objects; import java.util.Set; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; /** * The implementation of the audio service for volume, audio focus, device management... @@ -1850,22 +1851,28 @@ public class AudioService extends IAudioService.Stub /////////////////////////////////////////////////////////////////////////// // IPC methods /////////////////////////////////////////////////////////////////////////// - /** @see AudioManager#setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceInfo) */ - public int setPreferredDeviceForStrategy(int strategy, AudioDeviceAttributes device) { - if (device == null) { + /** + * @see AudioManager#setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes) + * @see AudioManager#setPreferredDevicesForStrategy(AudioProductStrategy, + * List<AudioDeviceAttributes>) + */ + public int setPreferredDevicesForStrategy(int strategy, List<AudioDeviceAttributes> devices) { + if (devices == null) { return AudioSystem.ERROR; } enforceModifyAudioRoutingPermission(); final String logString = String.format( "setPreferredDeviceForStrategy u/pid:%d/%d strat:%d dev:%s", - Binder.getCallingUid(), Binder.getCallingPid(), strategy, device.toString()); + Binder.getCallingUid(), Binder.getCallingPid(), strategy, + devices.stream().map(e -> e.toString()).collect(Collectors.joining(","))); sDeviceLogger.log(new AudioEventLogger.StringEvent(logString).printLog(TAG)); - if (device.getRole() == AudioDeviceAttributes.ROLE_INPUT) { + if (devices.stream().anyMatch(device -> + device.getRole() == AudioDeviceAttributes.ROLE_INPUT)) { Log.e(TAG, "Unsupported input routing in " + logString); return AudioSystem.ERROR; } - final int status = mDeviceBroker.setPreferredDeviceForStrategySync(strategy, device); + final int status = mDeviceBroker.setPreferredDevicesForStrategySync(strategy, devices); if (status != AudioSystem.SUCCESS) { Log.e(TAG, String.format("Error %d in %s)", status, logString)); } @@ -1874,53 +1881,61 @@ public class AudioService extends IAudioService.Stub } /** @see AudioManager#removePreferredDeviceForStrategy(AudioProductStrategy) */ - public int removePreferredDeviceForStrategy(int strategy) { + public int removePreferredDevicesForStrategy(int strategy) { enforceModifyAudioRoutingPermission(); final String logString = String.format("removePreferredDeviceForStrategy strat:%d", strategy); sDeviceLogger.log(new AudioEventLogger.StringEvent(logString).printLog(TAG)); - final int status = mDeviceBroker.removePreferredDeviceForStrategySync(strategy); + final int status = mDeviceBroker.removePreferredDevicesForStrategySync(strategy); if (status != AudioSystem.SUCCESS) { Log.e(TAG, String.format("Error %d in %s)", status, logString)); } return status; } - /** @see AudioManager#getPreferredDeviceForStrategy(AudioProductStrategy) */ - public AudioDeviceAttributes getPreferredDeviceForStrategy(int strategy) { + /** + * @see AudioManager#getPreferredDeviceForStrategy(AudioProductStrategy) + * @see AudioManager#getPreferredDevicesForStrategy(AudioProductStrategy) + */ + public List<AudioDeviceAttributes> getPreferredDevicesForStrategy(int strategy) { enforceModifyAudioRoutingPermission(); - AudioDeviceAttributes[] devices = new AudioDeviceAttributes[1]; + List<AudioDeviceAttributes> devices = new ArrayList<>(); final long identity = Binder.clearCallingIdentity(); - final int status = AudioSystem.getPreferredDeviceForStrategy(strategy, devices); + final int status = AudioSystem.getDevicesForRoleAndStrategy( + strategy, AudioSystem.DEVICE_ROLE_PREFERRED, devices); Binder.restoreCallingIdentity(identity); if (status != AudioSystem.SUCCESS) { Log.e(TAG, String.format("Error %d in getPreferredDeviceForStrategy(%d)", status, strategy)); - return null; + return new ArrayList<AudioDeviceAttributes>(); } else { - return devices[0]; + return devices; } } - /** @see AudioManager#addOnPreferredDeviceForStrategyChangedListener(Executor, AudioManager.OnPreferredDeviceForStrategyChangedListener) */ - public void registerStrategyPreferredDeviceDispatcher( - @Nullable IStrategyPreferredDeviceDispatcher dispatcher) { + /** @see AudioManager#addOnPreferredDevicesForStrategyChangedListener( + * Executor, AudioManager.OnPreferredDevicesForStrategyChangedListener) + */ + public void registerStrategyPreferredDevicesDispatcher( + @Nullable IStrategyPreferredDevicesDispatcher dispatcher) { if (dispatcher == null) { return; } enforceModifyAudioRoutingPermission(); - mDeviceBroker.registerStrategyPreferredDeviceDispatcher(dispatcher); + mDeviceBroker.registerStrategyPreferredDevicesDispatcher(dispatcher); } - /** @see AudioManager#removeOnPreferredDeviceForStrategyChangedListener(AudioManager.OnPreferredDeviceForStrategyChangedListener) */ - public void unregisterStrategyPreferredDeviceDispatcher( - @Nullable IStrategyPreferredDeviceDispatcher dispatcher) { + /** @see AudioManager#removeOnPreferredDevicesForStrategyChangedListener( + * AudioManager.OnPreferredDevicesForStrategyChangedListener) + */ + public void unregisterStrategyPreferredDevicesDispatcher( + @Nullable IStrategyPreferredDevicesDispatcher dispatcher) { if (dispatcher == null) { return; } enforceModifyAudioRoutingPermission(); - mDeviceBroker.unregisterStrategyPreferredDeviceDispatcher(dispatcher); + mDeviceBroker.unregisterStrategyPreferredDevicesDispatcher(dispatcher); } /** @see AudioManager#getDevicesForAttributes(AudioAttributes) */ diff --git a/services/core/java/com/android/server/audio/AudioSystemAdapter.java b/services/core/java/com/android/server/audio/AudioSystemAdapter.java index e60243fc481c..a0e1ca78a5e7 100644 --- a/services/core/java/com/android/server/audio/AudioSystemAdapter.java +++ b/services/core/java/com/android/server/audio/AudioSystemAdapter.java @@ -20,6 +20,8 @@ import android.annotation.NonNull; import android.media.AudioDeviceAttributes; import android.media.AudioSystem; +import java.util.List; + /** * Provides an adapter to access functionality of the android.media.AudioSystem class for device * related functionality. @@ -77,22 +79,25 @@ public class AudioSystemAdapter { } /** - * Same as {@link AudioSystem#setPreferredDeviceForStrategy(int, AudioDeviceAttributes)} + * Same as {@link AudioSystem#setDevicesRoleForStrategy(int, int, List)} * @param strategy - * @param device + * @param role + * @param devices * @return */ - public int setPreferredDeviceForStrategy(int strategy, @NonNull AudioDeviceAttributes device) { - return AudioSystem.setPreferredDeviceForStrategy(strategy, device); + public int setDevicesRoleForStrategy(int strategy, int role, + @NonNull List<AudioDeviceAttributes> devices) { + return AudioSystem.setDevicesRoleForStrategy(strategy, role, devices); } /** - * Same as {@link AudioSystem#removePreferredDeviceForStrategy(int)} + * Same as {@link AudioSystem#removeDevicesRoleForStrategy(int, int)} * @param strategy + * @param role * @return */ - public int removePreferredDeviceForStrategy(int strategy) { - return AudioSystem.removePreferredDeviceForStrategy(strategy); + public int removeDevicesRoleForStrategy(int strategy, int role) { + return AudioSystem.removeDevicesRoleForStrategy(strategy, role); } /** diff --git a/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java b/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java index a9cef20268f4..609af8d5bf4d 100644 --- a/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java +++ b/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java @@ -21,6 +21,8 @@ import android.media.AudioDeviceAttributes; import android.media.AudioSystem; import android.util.Log; +import java.util.List; + /** * Provides an adapter for AudioSystem that does nothing. * Overridden methods can be configured. @@ -66,13 +68,13 @@ public class NoOpAudioSystemAdapter extends AudioSystemAdapter { } @Override - public int setPreferredDeviceForStrategy(int strategy, - @NonNull AudioDeviceAttributes device) { + public int setDevicesRoleForStrategy(int strategy, int role, + @NonNull List<AudioDeviceAttributes> devices) { return AudioSystem.AUDIO_STATUS_OK; } @Override - public int removePreferredDeviceForStrategy(int strategy) { + public int removeDevicesRoleForStrategy(int strategy, int role) { return AudioSystem.AUDIO_STATUS_OK; } |