Merge "Introduce device(s) role for strategy." am: 7f73ba815a

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1534429

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: I02c0c5535e42c5a26ee94c3bde86920b5cb22b69
This commit is contained in:
Eric Laurent
2020-12-22 17:18:54 +00:00
committed by Automerger Merge Worker
15 changed files with 376 additions and 195 deletions

View File

@@ -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

View File

@@ -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 {

View File

@@ -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
}

View File

@@ -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());

View File

@@ -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));

View File

@@ -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,21 +1599,14 @@ public class AudioManager {
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
public boolean setPreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy,
@NonNull AudioDeviceAttributes device) {
Objects.requireNonNull(strategy);
Objects.requireNonNull(device);
try {
final int status =
getService().setPreferredDeviceForStrategy(strategy.getId(), device);
return status == AudioSystem.SUCCESS;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
return setPreferredDevicesForStrategy(strategy, Arrays.asList(device));
}
/**
* @hide
* Removes the preferred audio device previously set with
* {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)}.
* 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)
@@ -1623,7 +1617,7 @@ public class AudioManager {
Objects.requireNonNull(strategy);
try {
final int status =
getService().removePreferredDeviceForStrategy(strategy.getId());
getService().removePreferredDevicesForStrategy(strategy.getId());
return status == AudioSystem.SUCCESS;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1633,18 +1627,74 @@ public class AudioManager {
/**
* @hide
* 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
* @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 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().setPreferredDevicesForStrategy(strategy.getId(), devices);
return status == AudioSystem.SUCCESS;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* @hide
* 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
@@ -1677,6 +1730,70 @@ public class AudioManager {
@Nullable AudioDeviceAttributes device);
}
/**
* @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.
@@ -1686,16 +1803,16 @@ public class AudioManager {
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
public void addOnPreferredDeviceForStrategyChangedListener(
public void addOnPreferredDevicesForStrategyChangedListener(
@NonNull @CallbackExecutor Executor executor,
@NonNull OnPreferredDeviceForStrategyChangedListener listener)
@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);

View File

@@ -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.
* @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
* @return {@link #SUCCESS} if successfully set
*/
private static native int setPreferredDeviceForStrategy(
int strategy, int deviceType, String deviceAddress);
/**
* @hide
* Remove preferred routing for the strategy
* Set device as role for product 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 set
*/
private static native int setDevicesRoleForStrategy(
int strategy, int role, @NonNull int[] types, @NonNull String[] 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
* @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

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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) {
}
}

View File

@@ -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) */

View File

@@ -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);
}
/**

View File

@@ -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;
}