Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ee4774a4 authored by Paul Wang's avatar Paul Wang
Browse files

Expose API to set audio device as non-default playback

Bug: 259094683
Test: atest AudioServiceHostTest#testPreferredDeviceRouting

Change-Id: I38fd6f06f695691fde57aef7e3aa59fde67fe2d8
parent 8ee2960b
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -6574,6 +6574,7 @@ 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 addAssistantServicesUids(@NonNull int[]);
    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnNonDefaultDevicesForStrategyChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnNonDefaultDevicesForStrategyChangedListener) 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 addOnPreferredDevicesForCapturePresetChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDevicesForCapturePresetChangedListener) 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;
@@ -6595,6 +6596,7 @@ 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 getMutingExpectedDevice();
    method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioDeviceAttributes> getNonDefaultDevicesForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy);
    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> getPreferredDevicesForCapturePreset(int);
    method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioDeviceAttributes> getPreferredDevicesForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy);
@@ -6610,6 +6612,8 @@ package android.media {
    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void registerMuteAwaitConnectionCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.MuteAwaitConnectionCallback);
    method public void registerVolumeGroupCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.VolumeGroupCallback);
    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeAssistantServicesUids(@NonNull int[]);
    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean removeDeviceAsNonDefaultForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull android.media.AudioDeviceAttributes);
    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnNonDefaultDevicesForStrategyChangedListener(@NonNull android.media.AudioManager.OnNonDefaultDevicesForStrategyChangedListener);
    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 removeOnPreferredDevicesForCapturePresetChangedListener(@NonNull android.media.AudioManager.OnPreferredDevicesForCapturePresetChangedListener);
    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnPreferredDevicesForStrategyChangedListener(@NonNull android.media.AudioManager.OnPreferredDevicesForStrategyChangedListener);
@@ -6621,6 +6625,7 @@ package android.media {
    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo, @IntRange(from=0) long);
    method public void setAudioServerStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioServerStateCallback);
    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setBluetoothVariableLatencyEnabled(boolean);
    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setDeviceAsNonDefaultForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull android.media.AudioDeviceAttributes);
    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes, int);
    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 setPreferredDeviceForCapturePreset(int, @NonNull android.media.AudioDeviceAttributes);
@@ -6665,6 +6670,10 @@ package android.media {
    field public static final int EVENT_TIMEOUT = 2; // 0x2
  }
  public static interface AudioManager.OnNonDefaultDevicesForStrategyChangedListener {
    method public void onNonDefaultDevicesForStrategyChanged(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull java.util.List<android.media.AudioDeviceAttributes>);
  }
  @Deprecated public static interface AudioManager.OnPreferredDeviceForStrategyChangedListener {
    method @Deprecated public void onPreferredDeviceForStrategyChanged(@NonNull android.media.audiopolicy.AudioProductStrategy, @Nullable android.media.AudioDeviceAttributes);
  }
+22 −6
Original line number Diff line number Diff line
@@ -2739,12 +2739,26 @@ static jint android_media_AudioSystem_setDevicesRoleForStrategy(JNIEnv *env, job
}

static jint android_media_AudioSystem_removeDevicesRoleForStrategy(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::removeDevicesRoleForStrategy((product_strategy_t)strategy,
                                                      (device_role_t)role, nDevices));
    return (jint)status;
}

static jint android_media_AudioSystem_clearDevicesRoleForStrategy(JNIEnv *env, jobject thiz,
                                                                  jint strategy, jint role) {
    return (jint)
            check_AudioSystem_Command(AudioSystem::removeDevicesRoleForStrategy((product_strategy_t)
            check_AudioSystem_Command(AudioSystem::clearDevicesRoleForStrategy((product_strategy_t)
                                                                                       strategy,
                                                                                (device_role_t)
                                                                                        role),
                                                                               (device_role_t)role),
                                      {NAME_NOT_FOUND});
}

@@ -3341,8 +3355,10 @@ static const JNINativeMethod gMethods[] =
          (void *)android_media_AudioSystem_isCallScreeningModeSupported},
         {"setDevicesRoleForStrategy", "(II[I[Ljava/lang/String;)I",
          (void *)android_media_AudioSystem_setDevicesRoleForStrategy},
         {"removeDevicesRoleForStrategy", "(II)I",
         {"removeDevicesRoleForStrategy", "(II[I[Ljava/lang/String;)I",
          (void *)android_media_AudioSystem_removeDevicesRoleForStrategy},
         {"clearDevicesRoleForStrategy", "(II)I",
          (void *)android_media_AudioSystem_clearDevicesRoleForStrategy},
         {"getDevicesForRoleAndStrategy", "(IILjava/util/List;)I",
          (void *)android_media_AudioSystem_getDevicesForRoleAndStrategy},
         {"setDevicesRoleForCapturePreset", "(II[I[Ljava/lang/String;)I",
+177 −3
Original line number Diff line number Diff line
@@ -1856,6 +1856,76 @@ public class AudioManager {
        }
    }

    /**
     * @hide
     * Set a device as non-default for a given strategy, i.e. the audio routing to be avoided by
     * this audio strategy.
     * <p>Use
     * {@link #removeDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
     * to cancel setting this preference for this strategy.</p>
     * @param strategy the audio strategy whose routing will be affected
     * @param device the audio device to not route to when available
     * @return true if the operation was successful, false otherwise
     */
    @SystemApi
    @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
    public boolean setDeviceAsNonDefaultForStrategy(@NonNull AudioProductStrategy strategy,
                                                    @NonNull AudioDeviceAttributes device) {
        Objects.requireNonNull(strategy);
        Objects.requireNonNull(device);
        try {
            final int status =
                    getService().setDeviceAsNonDefaultForStrategy(strategy.getId(), device);
            return status == AudioSystem.SUCCESS;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * @hide
     * Removes the audio device(s) from the non-default device list previously set with
     * {@link #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
     * @param strategy the audio strategy whose routing will be affected
     * @param device the audio device to remove from the non-default device list
     * @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 removeDeviceAsNonDefaultForStrategy(@NonNull AudioProductStrategy strategy,
                                                       @NonNull AudioDeviceAttributes device) {
        Objects.requireNonNull(strategy);
        Objects.requireNonNull(device);
        try {
            final int status =
                    getService().removeDeviceAsNonDefaultForStrategy(strategy.getId(), device);
            return status == AudioSystem.SUCCESS;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * @hide
     * Gets the audio device(s) from the non-default device list previously set with
     * {@link #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
     * @param strategy the audio strategy to query
     * @return list of non-default devices for the strategy
     */
    @SystemApi
    @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
    @NonNull
    public List<AudioDeviceAttributes> getNonDefaultDevicesForStrategy(
            @NonNull AudioProductStrategy strategy) {
        Objects.requireNonNull(strategy);
        try {
            return getService().getNonDefaultDevicesForStrategy(strategy.getId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * @hide
     * Interface to be notified of changes in the preferred audio device set for a given audio
@@ -1891,9 +1961,11 @@ public class AudioManager {
     * 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
     * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)},
     * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)},
     * {@link #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)},
     * {@link #removeDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
     * or {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in
     * preferred device(s). It will not be invoked directly after registration with
     * {@link #addOnPreferredDevicesForStrategyChangedListener(
     * Executor, OnPreferredDevicesForStrategyChangedListener)}
@@ -1983,6 +2055,72 @@ public class AudioManager {
                listener, "removeOnPreferredDevicesForStrategyChangedListener");
    }

    /**
     * @hide
     * Interface to be notified of changes in the non-default audio devices set for a given audio
     * strategy.
     * <p>Note that this listener will only be invoked whenever
     * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)},
     * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)},
     * {@link #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)},
     * {@link #removeDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
     * or {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in
     * non-default device(s). It will not be invoked directly after registration with
     * {@link #addOnNonDefaultDevicesForStrategyChangedListener(
     * Executor, OnNonDefaultDevicesForStrategyChangedListener)}
     * to indicate which strategies had preferred devices at the time of registration.</p>
     * @see #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)
     * @see #removeDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)
     */
    @SystemApi
    public interface OnNonDefaultDevicesForStrategyChangedListener {
        /**
         * Called on the listener to indicate that the non-default audio devices for the given
         * strategy has changed.
         * @param strategy the {@link AudioProductStrategy} whose non-default device changed
         * @param devices a list of newly set non-default audio devices
         */
        void onNonDefaultDevicesForStrategyChanged(@NonNull AudioProductStrategy strategy,
                                                   @NonNull List<AudioDeviceAttributes> devices);
    }

    /**
     * @hide
     * Adds a listener for being notified of changes to the non-default audio devices for
     * strategies.
     * @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 addOnNonDefaultDevicesForStrategyChangedListener(
            @NonNull @CallbackExecutor Executor executor,
            @NonNull OnNonDefaultDevicesForStrategyChangedListener listener)
            throws SecurityException {
        Objects.requireNonNull(executor);
        Objects.requireNonNull(listener);

        mNonDefDevListenerMgr.addListener(
                executor, listener, "addOnNonDefaultDevicesForStrategyChangedListener",
                () -> new StrategyNonDefaultDevicesDispatcherStub());
    }

    /**
     * @hide
     * Removes a previously added listener of changes to the non-default audio device for
     * strategies.
     * @param listener
     */
    @SystemApi
    @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
    public void removeOnNonDefaultDevicesForStrategyChangedListener(
            @NonNull OnNonDefaultDevicesForStrategyChangedListener listener) {
        Objects.requireNonNull(listener);
        mNonDefDevListenerMgr.removeListener(
                listener, "removeOnNonDefaultDevicesForStrategyChangedListener");
    }

    /**
     * Manages the OnPreferredDevicesForStrategyChangedListener listeners and the
     * StrategyPreferredDevicesDispatcherStub
@@ -1990,6 +2128,13 @@ public class AudioManager {
    private final CallbackUtil.LazyListenerManager<OnPreferredDevicesForStrategyChangedListener>
            mPrefDevListenerMgr = new CallbackUtil.LazyListenerManager();

    /**
     * Manages the OnNonDefaultDevicesForStrategyChangedListener listeners and the
     * StrategyNonDefaultDevicesDispatcherStub
     */
    private final CallbackUtil.LazyListenerManager<OnNonDefaultDevicesForStrategyChangedListener>
            mNonDefDevListenerMgr = new CallbackUtil.LazyListenerManager();

    private final class StrategyPreferredDevicesDispatcherStub
            extends IStrategyPreferredDevicesDispatcher.Stub
            implements CallbackUtil.DispatcherStub {
@@ -2018,6 +2163,35 @@ public class AudioManager {
        }
    }

    private final class StrategyNonDefaultDevicesDispatcherStub
            extends IStrategyNonDefaultDevicesDispatcher.Stub
            implements CallbackUtil.DispatcherStub {

        @Override
        public void dispatchNonDefDevicesChanged(int strategyId,
                                                 @NonNull List<AudioDeviceAttributes> devices) {
            final AudioProductStrategy strategy =
                    AudioProductStrategy.getAudioProductStrategyWithId(strategyId);

            mNonDefDevListenerMgr.callListeners(
                    (listener) -> listener.onNonDefaultDevicesForStrategyChanged(
                            strategy, devices));
        }

        @Override
        public void register(boolean register) {
            try {
                if (register) {
                    getService().registerStrategyNonDefaultDevicesDispatcher(this);
                } else {
                    getService().unregisterStrategyNonDefaultDevicesDispatcher(this);
                }
            } catch (RemoteException e) {
                e.rethrowFromSystemServer();
            }
        }
    }

    //====================================================================
    // Audio Capture Preset routing

+35 −1
Original line number Diff line number Diff line
@@ -2061,14 +2061,48 @@ public class AudioSystem
    private static native int setDevicesRoleForStrategy(
            int strategy, int role, @NonNull int[] types, @NonNull String[] addresses);

    /**
     * @hide
     * Remove device as role for product strategy.
     * @param strategy the id of the strategy to configure
     * @param role the role of the devices
     * @param devices the list of devices to be removed as role for the given strategy
     * @return {@link #SUCCESS} if successfully set
     */
    public static int removeDevicesRoleForStrategy(
            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] = devices.get(i).getInternalType();
            addresses[i] = devices.get(i).getAddress();
        }
        return removeDevicesRoleForStrategy(strategy, role, types, addresses);
    }

    /**
     * @hide
     * Remove devices as role for the strategy
     * @param strategy the id of the strategy to configure
     * @param role the role of the devices
     * @param types all device types
     * @param addresses all device addresses
     * @return {@link #SUCCESS} if successfully removed
     */
    public static native int removeDevicesRoleForStrategy(
            int strategy, int role, @NonNull int[] types, @NonNull String[] addresses);

    /**
     * @hide
     * Remove all 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 removeDevicesRoleForStrategy(int strategy, int role);
    public static native int clearDevicesRoleForStrategy(int strategy, int role);

    /**
     * @hide
+18 −1
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import android.media.IPreferredMixerAttributesDispatcher;
import android.media.IRecordingConfigDispatcher;
import android.media.IRingtonePlayer;
import android.media.IStrategyPreferredDevicesDispatcher;
import android.media.IStrategyNonDefaultDevicesDispatcher;
import android.media.ISpatializerCallback;
import android.media.ISpatializerHeadTrackerAvailableCallback;
import android.media.ISpatializerHeadTrackingModeCallback;
@@ -330,7 +331,8 @@ interface IAudioService {

    boolean isCallScreeningModeSupported();

    int setPreferredDevicesForStrategy(in int strategy, in List<AudioDeviceAttributes> device);
    @EnforcePermission("MODIFY_AUDIO_ROUTING")
    int setPreferredDevicesForStrategy(in int strategy, in List<AudioDeviceAttributes> devices);

    @EnforcePermission("MODIFY_AUDIO_ROUTING")
    int removePreferredDevicesForStrategy(in int strategy);
@@ -338,6 +340,15 @@ interface IAudioService {
    @EnforcePermission("MODIFY_AUDIO_ROUTING")
    List<AudioDeviceAttributes> getPreferredDevicesForStrategy(in int strategy);

    @EnforcePermission("MODIFY_AUDIO_ROUTING")
    int setDeviceAsNonDefaultForStrategy(in int strategy, in AudioDeviceAttributes device);

    @EnforcePermission("MODIFY_AUDIO_ROUTING")
    int removeDeviceAsNonDefaultForStrategy(in int strategy, in AudioDeviceAttributes device);

    @EnforcePermission("MODIFY_AUDIO_ROUTING")
    List<AudioDeviceAttributes> getNonDefaultDevicesForStrategy(in int strategy);

    List<AudioDeviceAttributes> getDevicesForAttributes(in AudioAttributes attributes);

    List<AudioDeviceAttributes> getDevicesForAttributesUnprotected(in AudioAttributes attributes);
@@ -351,6 +362,12 @@ interface IAudioService {
    oneway void unregisterStrategyPreferredDevicesDispatcher(
            IStrategyPreferredDevicesDispatcher dispatcher);

    void registerStrategyNonDefaultDevicesDispatcher(
            IStrategyNonDefaultDevicesDispatcher dispatcher);

    oneway void unregisterStrategyNonDefaultDevicesDispatcher(
            IStrategyNonDefaultDevicesDispatcher dispatcher);

    oneway void setRttEnabled(in boolean rttEnabled);

    @EnforcePermission("MODIFY_AUDIO_ROUTING")
Loading