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:
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) */
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user