Merge "Support set/clear/get preferred device for capture preset." am: 617d14954d
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1534430 MUST ONLY BE SUBMITTED BY AUTOMERGER Change-Id: Ie13b9835abef801bbf845a2b3748cfe76ac4c346
This commit is contained in:
@@ -4146,8 +4146,10 @@ package android.media {
|
|||||||
public class AudioManager {
|
public class AudioManager {
|
||||||
method @Deprecated public int abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes);
|
method @Deprecated public int abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes);
|
||||||
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 @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDeviceForStrategyChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDeviceForStrategyChangedListener) throws java.lang.SecurityException;
|
||||||
|
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDevicesForCapturePresetChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDevicesForCapturePresetChangedListener) throws java.lang.SecurityException;
|
||||||
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDevicesForStrategyChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDevicesForStrategyChangedListener) throws java.lang.SecurityException;
|
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 public void clearAudioServerStateCallback();
|
||||||
|
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean clearPreferredDevicesForCapturePreset(int);
|
||||||
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int dispatchAudioFocusChange(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy);
|
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);
|
method @IntRange(from=0) public long getAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo);
|
||||||
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioProductStrategy> getAudioProductStrategies();
|
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioProductStrategy> getAudioProductStrategies();
|
||||||
@@ -4157,6 +4159,7 @@ package android.media {
|
|||||||
method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMaxVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
|
method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMaxVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
|
||||||
method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMinVolumeIndexForAttributes(@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 @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.media.AudioDeviceAttributes getPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy);
|
||||||
|
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioDeviceAttributes> getPreferredDevicesForCapturePreset(int);
|
||||||
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioDeviceAttributes> getPreferredDevicesForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy);
|
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 @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 @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
|
||||||
@@ -4165,6 +4168,7 @@ package android.media {
|
|||||||
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int registerAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy);
|
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 public void registerVolumeGroupCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.VolumeGroupCallback);
|
||||||
method @Deprecated @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 removeOnPreferredDevicesForCapturePresetChangedListener(@NonNull android.media.AudioManager.OnPreferredDevicesForCapturePresetChangedListener);
|
||||||
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 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_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 @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, @NonNull android.media.AudioAttributes, int, int) throws java.lang.IllegalArgumentException;
|
||||||
@@ -4173,6 +4177,7 @@ package android.media {
|
|||||||
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo, @IntRange(from=0) long);
|
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo, @IntRange(from=0) long);
|
||||||
method public void setAudioServerStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioServerStateCallback);
|
method 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 void setFocusRequestResult(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy);
|
||||||
|
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDeviceForCapturePreset(int, @NonNull android.media.AudioDeviceAttributes);
|
||||||
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 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 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 setSupportedSystemUsages(@NonNull int[]);
|
||||||
@@ -4197,6 +4202,10 @@ package android.media {
|
|||||||
method @Deprecated public void onPreferredDeviceForStrategyChanged(@NonNull android.media.audiopolicy.AudioProductStrategy, @Nullable android.media.AudioDeviceAttributes);
|
method @Deprecated public void onPreferredDeviceForStrategyChanged(@NonNull android.media.audiopolicy.AudioProductStrategy, @Nullable android.media.AudioDeviceAttributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static interface AudioManager.OnPreferredDevicesForCapturePresetChangedListener {
|
||||||
|
method public void onPreferredDevicesForCapturePresetChanged(int, @NonNull java.util.List<android.media.AudioDeviceAttributes>);
|
||||||
|
}
|
||||||
|
|
||||||
public static interface AudioManager.OnPreferredDevicesForStrategyChangedListener {
|
public static interface AudioManager.OnPreferredDevicesForStrategyChangedListener {
|
||||||
method public void onPreferredDevicesForStrategyChanged(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull java.util.List<android.media.AudioDeviceAttributes>);
|
method public void onPreferredDevicesForStrategyChanged(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull java.util.List<android.media.AudioDeviceAttributes>);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2408,6 +2408,79 @@ static jint android_media_AudioSystem_getDevicesForRoleAndStrategy(JNIEnv *env,
|
|||||||
return AUDIO_JAVA_SUCCESS;
|
return AUDIO_JAVA_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static jint android_media_AudioSystem_setDevicesRoleForCapturePreset(
|
||||||
|
JNIEnv *env, jobject thiz, jint capturePreset, 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::setDevicesRoleForCapturePreset((audio_source_t)capturePreset,
|
||||||
|
(device_role_t)role, nDevices));
|
||||||
|
return (jint)status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static jint android_media_AudioSystem_addDevicesRoleForCapturePreset(
|
||||||
|
JNIEnv *env, jobject thiz, jint capturePreset, 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::addDevicesRoleForCapturePreset((audio_source_t)capturePreset,
|
||||||
|
(device_role_t)role, nDevices));
|
||||||
|
return (jint)status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static jint android_media_AudioSystem_removeDevicesRoleForCapturePreset(
|
||||||
|
JNIEnv *env, jobject thiz, jint capturePreset, 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::removeDevicesRoleForCapturePreset((audio_source_t)capturePreset,
|
||||||
|
(device_role_t)role, nDevices));
|
||||||
|
return (jint)status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static jint android_media_AudioSystem_clearDevicesRoleForCapturePreset(JNIEnv *env, jobject thiz,
|
||||||
|
jint capturePreset,
|
||||||
|
jint role) {
|
||||||
|
return (jint)check_AudioSystem_Command(
|
||||||
|
AudioSystem::clearDevicesRoleForCapturePreset((audio_source_t)capturePreset,
|
||||||
|
(device_role_t)role));
|
||||||
|
}
|
||||||
|
|
||||||
|
static jint android_media_AudioSystem_getDevicesForRoleAndCapturePreset(JNIEnv *env, jobject thiz,
|
||||||
|
jint capturePreset,
|
||||||
|
jint role,
|
||||||
|
jobject jDevices) {
|
||||||
|
AudioDeviceTypeAddrVector nDevices;
|
||||||
|
status_t status = check_AudioSystem_Command(
|
||||||
|
AudioSystem::getDevicesForRoleAndCapturePreset((audio_source_t)capturePreset,
|
||||||
|
(device_role_t)role, nDevices));
|
||||||
|
if (status != NO_ERROR) {
|
||||||
|
return (jint)status;
|
||||||
|
}
|
||||||
|
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 AUDIO_JAVA_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static jint
|
static jint
|
||||||
android_media_AudioSystem_getDevicesForAttributes(JNIEnv *env, jobject thiz,
|
android_media_AudioSystem_getDevicesForAttributes(JNIEnv *env, jobject thiz,
|
||||||
jobject jaa, jobjectArray jDeviceArray)
|
jobject jaa, jobjectArray jDeviceArray)
|
||||||
@@ -2559,6 +2632,16 @@ static const JNINativeMethod gMethods[] =
|
|||||||
(void *)android_media_AudioSystem_removeDevicesRoleForStrategy},
|
(void *)android_media_AudioSystem_removeDevicesRoleForStrategy},
|
||||||
{"getDevicesForRoleAndStrategy", "(IILjava/util/List;)I",
|
{"getDevicesForRoleAndStrategy", "(IILjava/util/List;)I",
|
||||||
(void *)android_media_AudioSystem_getDevicesForRoleAndStrategy},
|
(void *)android_media_AudioSystem_getDevicesForRoleAndStrategy},
|
||||||
|
{"setDevicesRoleForCapturePreset", "(II[I[Ljava/lang/String;)I",
|
||||||
|
(void *)android_media_AudioSystem_setDevicesRoleForCapturePreset},
|
||||||
|
{"addDevicesRoleForCapturePreset", "(II[I[Ljava/lang/String;)I",
|
||||||
|
(void *)android_media_AudioSystem_addDevicesRoleForCapturePreset},
|
||||||
|
{"removeDevicesRoleForCapturePreset", "(II[I[Ljava/lang/String;)I",
|
||||||
|
(void *)android_media_AudioSystem_removeDevicesRoleForCapturePreset},
|
||||||
|
{"clearDevicesRoleForCapturePreset", "(II)I",
|
||||||
|
(void *)android_media_AudioSystem_clearDevicesRoleForCapturePreset},
|
||||||
|
{"getDevicesForRoleAndCapturePreset", "(IILjava/util/List;)I",
|
||||||
|
(void *)android_media_AudioSystem_getDevicesForRoleAndCapturePreset},
|
||||||
{"getDevicesForAttributes",
|
{"getDevicesForAttributes",
|
||||||
"(Landroid/media/AudioAttributes;[Landroid/media/AudioDeviceAttributes;)I",
|
"(Landroid/media/AudioAttributes;[Landroid/media/AudioDeviceAttributes;)I",
|
||||||
(void *)android_media_AudioSystem_getDevicesForAttributes},
|
(void *)android_media_AudioSystem_getDevicesForAttributes},
|
||||||
|
|||||||
@@ -71,6 +71,11 @@ public final class AudioDeviceAttributes implements Parcelable {
|
|||||||
*/
|
*/
|
||||||
private final @Role int mRole;
|
private final @Role int mRole;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The internal audio device type
|
||||||
|
*/
|
||||||
|
private final int mNativeType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @hide
|
* @hide
|
||||||
* Constructor from a valid {@link AudioDeviceInfo}
|
* Constructor from a valid {@link AudioDeviceInfo}
|
||||||
@@ -83,6 +88,7 @@ public final class AudioDeviceAttributes implements Parcelable {
|
|||||||
mRole = deviceInfo.isSink() ? ROLE_OUTPUT : ROLE_INPUT;
|
mRole = deviceInfo.isSink() ? ROLE_OUTPUT : ROLE_INPUT;
|
||||||
mType = deviceInfo.getType();
|
mType = deviceInfo.getType();
|
||||||
mAddress = deviceInfo.getAddress();
|
mAddress = deviceInfo.getAddress();
|
||||||
|
mNativeType = deviceInfo.getInternalType();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -101,9 +107,12 @@ public final class AudioDeviceAttributes implements Parcelable {
|
|||||||
}
|
}
|
||||||
if (role == ROLE_OUTPUT) {
|
if (role == ROLE_OUTPUT) {
|
||||||
AudioDeviceInfo.enforceValidAudioDeviceTypeOut(type);
|
AudioDeviceInfo.enforceValidAudioDeviceTypeOut(type);
|
||||||
}
|
mNativeType = AudioDeviceInfo.convertDeviceTypeToInternalDevice(type);
|
||||||
if (role == ROLE_INPUT) {
|
} else if (role == ROLE_INPUT) {
|
||||||
AudioDeviceInfo.enforceValidAudioDeviceTypeIn(type);
|
AudioDeviceInfo.enforceValidAudioDeviceTypeIn(type);
|
||||||
|
mNativeType = AudioDeviceInfo.convertDeviceTypeToInternalInputDevice(type);
|
||||||
|
} else {
|
||||||
|
mNativeType = AudioSystem.DEVICE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
mRole = role;
|
mRole = role;
|
||||||
@@ -115,6 +124,7 @@ public final class AudioDeviceAttributes implements Parcelable {
|
|||||||
mRole = (nativeType & AudioSystem.DEVICE_BIT_IN) != 0 ? ROLE_INPUT : ROLE_OUTPUT;
|
mRole = (nativeType & AudioSystem.DEVICE_BIT_IN) != 0 ? ROLE_INPUT : ROLE_OUTPUT;
|
||||||
mType = AudioDeviceInfo.convertInternalDeviceToDeviceType(nativeType);
|
mType = AudioDeviceInfo.convertInternalDeviceToDeviceType(nativeType);
|
||||||
mAddress = address;
|
mAddress = address;
|
||||||
|
mNativeType = nativeType;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -147,6 +157,15 @@ public final class AudioDeviceAttributes implements Parcelable {
|
|||||||
return mAddress;
|
return mAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
* Returns the internal device type of a device
|
||||||
|
* @return the internal device type
|
||||||
|
*/
|
||||||
|
public int getInternalType() {
|
||||||
|
return mNativeType;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(mRole, mType, mAddress);
|
return Objects.hash(mRole, mType, mAddress);
|
||||||
@@ -189,12 +208,14 @@ public final class AudioDeviceAttributes implements Parcelable {
|
|||||||
dest.writeInt(mRole);
|
dest.writeInt(mRole);
|
||||||
dest.writeInt(mType);
|
dest.writeInt(mType);
|
||||||
dest.writeString(mAddress);
|
dest.writeString(mAddress);
|
||||||
|
dest.writeInt(mNativeType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private AudioDeviceAttributes(@NonNull Parcel in) {
|
private AudioDeviceAttributes(@NonNull Parcel in) {
|
||||||
mRole = in.readInt();
|
mRole = in.readInt();
|
||||||
mType = in.readInt();
|
mType = in.readInt();
|
||||||
mAddress = in.readString();
|
mAddress = in.readString();
|
||||||
|
mNativeType = in.readInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final @NonNull Parcelable.Creator<AudioDeviceAttributes> CREATOR =
|
public static final @NonNull Parcelable.Creator<AudioDeviceAttributes> CREATOR =
|
||||||
|
|||||||
@@ -349,6 +349,14 @@ public final class AudioDeviceInfo {
|
|||||||
return mPort;
|
return mPort;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
* @return the internal device tyoe
|
||||||
|
*/
|
||||||
|
public int getInternalType() {
|
||||||
|
return mPort.type();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The internal device ID.
|
* @return The internal device ID.
|
||||||
*/
|
*/
|
||||||
@@ -512,10 +520,21 @@ public final class AudioDeviceInfo {
|
|||||||
return INT_TO_EXT_DEVICE_MAPPING.get(intDevice, TYPE_UNKNOWN);
|
return INT_TO_EXT_DEVICE_MAPPING.get(intDevice, TYPE_UNKNOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @hide */
|
||||||
|
public static int convertDeviceTypeToInternalInputDevice(int deviceType) {
|
||||||
|
return EXT_TO_INT_INPUT_DEVICE_MAPPING.get(deviceType, AudioSystem.DEVICE_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
private static final SparseIntArray INT_TO_EXT_DEVICE_MAPPING;
|
private static final SparseIntArray INT_TO_EXT_DEVICE_MAPPING;
|
||||||
|
|
||||||
private static final SparseIntArray EXT_TO_INT_DEVICE_MAPPING;
|
private static final SparseIntArray EXT_TO_INT_DEVICE_MAPPING;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EXT_TO_INT_INPUT_DEVICE_MAPPING aims at mapping external device type to internal input device
|
||||||
|
* type.
|
||||||
|
*/
|
||||||
|
private static final SparseIntArray EXT_TO_INT_INPUT_DEVICE_MAPPING;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
INT_TO_EXT_DEVICE_MAPPING = new SparseIntArray();
|
INT_TO_EXT_DEVICE_MAPPING = new SparseIntArray();
|
||||||
INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_EARPIECE, TYPE_BUILTIN_EARPIECE);
|
INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_EARPIECE, TYPE_BUILTIN_EARPIECE);
|
||||||
@@ -600,6 +619,32 @@ public final class AudioDeviceInfo {
|
|||||||
EXT_TO_INT_DEVICE_MAPPING.put(TYPE_REMOTE_SUBMIX, AudioSystem.DEVICE_OUT_REMOTE_SUBMIX);
|
EXT_TO_INT_DEVICE_MAPPING.put(TYPE_REMOTE_SUBMIX, AudioSystem.DEVICE_OUT_REMOTE_SUBMIX);
|
||||||
EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BLE_HEADSET, AudioSystem.DEVICE_OUT_BLE_HEADSET);
|
EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BLE_HEADSET, AudioSystem.DEVICE_OUT_BLE_HEADSET);
|
||||||
EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BLE_SPEAKER, AudioSystem.DEVICE_OUT_BLE_SPEAKER);
|
EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BLE_SPEAKER, AudioSystem.DEVICE_OUT_BLE_SPEAKER);
|
||||||
|
|
||||||
|
// privileges mapping to input device
|
||||||
|
EXT_TO_INT_INPUT_DEVICE_MAPPING = new SparseIntArray();
|
||||||
|
EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_BUILTIN_MIC, AudioSystem.DEVICE_IN_BUILTIN_MIC);
|
||||||
|
EXT_TO_INT_INPUT_DEVICE_MAPPING.put(
|
||||||
|
TYPE_BLUETOOTH_SCO, AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET);
|
||||||
|
EXT_TO_INT_INPUT_DEVICE_MAPPING.put(
|
||||||
|
TYPE_WIRED_HEADSET, AudioSystem.DEVICE_IN_WIRED_HEADSET);
|
||||||
|
EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_HDMI, AudioSystem.DEVICE_IN_HDMI);
|
||||||
|
EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_TELEPHONY, AudioSystem.DEVICE_IN_TELEPHONY_RX);
|
||||||
|
EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_DOCK, AudioSystem.DEVICE_IN_ANLG_DOCK_HEADSET);
|
||||||
|
EXT_TO_INT_INPUT_DEVICE_MAPPING.put(
|
||||||
|
TYPE_USB_ACCESSORY, AudioSystem.DEVICE_IN_USB_ACCESSORY);
|
||||||
|
EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_USB_DEVICE, AudioSystem.DEVICE_IN_USB_DEVICE);
|
||||||
|
EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_USB_HEADSET, AudioSystem.DEVICE_IN_USB_HEADSET);
|
||||||
|
EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_FM_TUNER, AudioSystem.DEVICE_IN_FM_TUNER);
|
||||||
|
EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_TV_TUNER, AudioSystem.DEVICE_IN_TV_TUNER);
|
||||||
|
EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_LINE_ANALOG, AudioSystem.DEVICE_IN_LINE);
|
||||||
|
EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_LINE_DIGITAL, AudioSystem.DEVICE_IN_SPDIF);
|
||||||
|
EXT_TO_INT_INPUT_DEVICE_MAPPING.put(
|
||||||
|
TYPE_BLUETOOTH_A2DP, AudioSystem.DEVICE_IN_BLUETOOTH_A2DP);
|
||||||
|
EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_IP, AudioSystem.DEVICE_IN_IP);
|
||||||
|
EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_BUS, AudioSystem.DEVICE_IN_BUS);
|
||||||
|
EXT_TO_INT_INPUT_DEVICE_MAPPING.put(
|
||||||
|
TYPE_REMOTE_SUBMIX, AudioSystem.DEVICE_IN_REMOTE_SUBMIX);
|
||||||
|
EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_BLE_HEADSET, AudioSystem.DEVICE_IN_BLE_HEADSET);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1947,6 +1947,349 @@ public class AudioManager {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//====================================================================
|
||||||
|
// Audio Capture Preset routing
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
* Set the preferred device for a given capture preset, i.e. the audio routing to be used by
|
||||||
|
* this capture preset. Note that the device may not be available at the time the preferred
|
||||||
|
* device is set, but it will be used once made available.
|
||||||
|
* <p>Use {@link #clearPreferredDevicesForCapturePreset(int)} to cancel setting this preference
|
||||||
|
* for this capture preset.</p>
|
||||||
|
* @param capturePreset the audio capture preset whose routing will be affected
|
||||||
|
* @param device the audio device to route to when available
|
||||||
|
* @return true if the operation was successful, false otherwise
|
||||||
|
*/
|
||||||
|
@SystemApi
|
||||||
|
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
|
||||||
|
public boolean setPreferredDeviceForCapturePreset(int capturePreset,
|
||||||
|
@NonNull AudioDeviceAttributes device) {
|
||||||
|
return setPreferredDevicesForCapturePreset(capturePreset, Arrays.asList(device));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
* Remove all the preferred audio devices previously set
|
||||||
|
* @param capturePreset the audio capture preset whose routing will be affected
|
||||||
|
* @return true if the operation was successful, false otherwise (invalid capture preset, or no
|
||||||
|
* device set for example)
|
||||||
|
*/
|
||||||
|
@SystemApi
|
||||||
|
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
|
||||||
|
public boolean clearPreferredDevicesForCapturePreset(int capturePreset) {
|
||||||
|
if (!MediaRecorder.isValidAudioSource(capturePreset)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
final int status = getService().clearPreferredDevicesForCapturePreset(capturePreset);
|
||||||
|
return status == AudioSystem.SUCCESS;
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw e.rethrowFromSystemServer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
* Return the preferred devices for an audio capture preset, previously set with
|
||||||
|
* {@link #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)}
|
||||||
|
* @param capturePreset the capture preset to query
|
||||||
|
* @return a list that contains preferred devices for that capture preset.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
@SystemApi
|
||||||
|
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
|
||||||
|
public List<AudioDeviceAttributes> getPreferredDevicesForCapturePreset(int capturePreset) {
|
||||||
|
if (!MediaRecorder.isValidAudioSource(capturePreset)) {
|
||||||
|
return new ArrayList<AudioDeviceAttributes>();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return getService().getPreferredDevicesForCapturePreset(capturePreset);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw e.rethrowFromSystemServer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean setPreferredDevicesForCapturePreset(
|
||||||
|
int capturePreset, @NonNull List<AudioDeviceAttributes> devices) {
|
||||||
|
Objects.requireNonNull(devices);
|
||||||
|
if (!MediaRecorder.isValidAudioSource(capturePreset)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (devices.size() != 1) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Only support setting one preferred devices for capture preset");
|
||||||
|
}
|
||||||
|
for (AudioDeviceAttributes device : devices) {
|
||||||
|
Objects.requireNonNull(device);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
final int status =
|
||||||
|
getService().setPreferredDevicesForCapturePreset(capturePreset, devices);
|
||||||
|
return status == AudioSystem.SUCCESS;
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw e.rethrowFromSystemServer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
* Interface to be notified of changes in the preferred audio devices set for a given capture
|
||||||
|
* preset.
|
||||||
|
* <p>Note that this listener will only be invoked whenever
|
||||||
|
* {@link #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)} or
|
||||||
|
* {@link #clearPreferredDevicesForCapturePreset(int)} causes a change in
|
||||||
|
* preferred device. It will not be invoked directly after registration with
|
||||||
|
* {@link #addOnPreferredDevicesForCapturePresetChangedListener(
|
||||||
|
* Executor, OnPreferredDevicesForCapturePresetChangedListener)}
|
||||||
|
* to indicate which strategies had preferred devices at the time of registration.</p>
|
||||||
|
* @see #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)
|
||||||
|
* @see #clearPreferredDevicesForCapturePreset(int)
|
||||||
|
* @see #getPreferredDevicesForCapturePreset(int)
|
||||||
|
*/
|
||||||
|
@SystemApi
|
||||||
|
public interface OnPreferredDevicesForCapturePresetChangedListener {
|
||||||
|
/**
|
||||||
|
* Called on the listener to indicate that the preferred audio devices for the given
|
||||||
|
* capture preset has changed.
|
||||||
|
* @param capturePreset the capture preset whose preferred device changed
|
||||||
|
* @param devices a list of newly set preferred audio devices
|
||||||
|
*/
|
||||||
|
void onPreferredDevicesForCapturePresetChanged(
|
||||||
|
int capturePreset, @NonNull List<AudioDeviceAttributes> devices);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
* Adds a listener for being notified of changes to the capture-preset-preferred audio device.
|
||||||
|
* @param executor
|
||||||
|
* @param listener
|
||||||
|
* @throws SecurityException if the caller doesn't hold the required permission
|
||||||
|
*/
|
||||||
|
@SystemApi
|
||||||
|
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
|
||||||
|
public void addOnPreferredDevicesForCapturePresetChangedListener(
|
||||||
|
@NonNull @CallbackExecutor Executor executor,
|
||||||
|
@NonNull OnPreferredDevicesForCapturePresetChangedListener listener)
|
||||||
|
throws SecurityException {
|
||||||
|
Objects.requireNonNull(executor);
|
||||||
|
Objects.requireNonNull(listener);
|
||||||
|
int status = addOnDevRoleForCapturePresetChangedListener(
|
||||||
|
executor, listener, AudioSystem.DEVICE_ROLE_PREFERRED);
|
||||||
|
if (status == AudioSystem.ERROR) {
|
||||||
|
// This must not happen
|
||||||
|
throw new RuntimeException("Unknown error happened");
|
||||||
|
}
|
||||||
|
if (status == AudioSystem.BAD_VALUE) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"attempt to call addOnPreferredDevicesForCapturePresetChangedListener() "
|
||||||
|
+ "on a previously registered listener");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
* Removes a previously added listener of changes to the capture-preset-preferred audio device.
|
||||||
|
* @param listener
|
||||||
|
*/
|
||||||
|
@SystemApi
|
||||||
|
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
|
||||||
|
public void removeOnPreferredDevicesForCapturePresetChangedListener(
|
||||||
|
@NonNull OnPreferredDevicesForCapturePresetChangedListener listener) {
|
||||||
|
Objects.requireNonNull(listener);
|
||||||
|
int status = removeOnDevRoleForCapturePresetChangedListener(
|
||||||
|
listener, AudioSystem.DEVICE_ROLE_PREFERRED);
|
||||||
|
if (status == AudioSystem.ERROR) {
|
||||||
|
// This must not happen
|
||||||
|
throw new RuntimeException("Unknown error happened");
|
||||||
|
}
|
||||||
|
if (status == AudioSystem.BAD_VALUE) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"attempt to call removeOnPreferredDevicesForCapturePresetChangedListener() "
|
||||||
|
+ "on an unregistered listener");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> int addOnDevRoleForCapturePresetChangedListener(
|
||||||
|
@NonNull @CallbackExecutor Executor executor,
|
||||||
|
@NonNull T listener, int deviceRole) {
|
||||||
|
Objects.requireNonNull(executor);
|
||||||
|
Objects.requireNonNull(listener);
|
||||||
|
DevRoleListeners<T> devRoleListeners =
|
||||||
|
(DevRoleListeners<T>) mDevRoleForCapturePresetListeners.get(deviceRole);
|
||||||
|
if (devRoleListeners == null) {
|
||||||
|
return AudioSystem.ERROR;
|
||||||
|
}
|
||||||
|
synchronized (devRoleListeners.mDevRoleListenersLock) {
|
||||||
|
if (devRoleListeners.hasDevRoleListener(listener)) {
|
||||||
|
return AudioSystem.BAD_VALUE;
|
||||||
|
}
|
||||||
|
// lazy initialization of the list of device role listener
|
||||||
|
if (devRoleListeners.mListenerInfos == null) {
|
||||||
|
devRoleListeners.mListenerInfos = new ArrayList<>();
|
||||||
|
}
|
||||||
|
final int oldCbCount = devRoleListeners.mListenerInfos.size();
|
||||||
|
devRoleListeners.mListenerInfos.add(new DevRoleListenerInfo<T>(executor, listener));
|
||||||
|
if (oldCbCount == 0 && devRoleListeners.mListenerInfos.size() > 0) {
|
||||||
|
// register binder for callbacks
|
||||||
|
synchronized (mDevRoleForCapturePresetListenersLock) {
|
||||||
|
int deviceRoleListenerStatus = mDeviceRoleListenersStatus;
|
||||||
|
mDeviceRoleListenersStatus |= (1 << deviceRole);
|
||||||
|
if (deviceRoleListenerStatus != 0) {
|
||||||
|
// There are already device role changed listeners active.
|
||||||
|
return AudioSystem.SUCCESS;
|
||||||
|
}
|
||||||
|
if (mDevicesRoleForCapturePresetDispatcherStub == null) {
|
||||||
|
mDevicesRoleForCapturePresetDispatcherStub =
|
||||||
|
new CapturePresetDevicesRoleDispatcherStub();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
getService().registerCapturePresetDevicesRoleDispatcher(
|
||||||
|
mDevicesRoleForCapturePresetDispatcherStub);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw e.rethrowFromSystemServer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return AudioSystem.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> int removeOnDevRoleForCapturePresetChangedListener(
|
||||||
|
@NonNull T listener, int deviceRole) {
|
||||||
|
Objects.requireNonNull(listener);
|
||||||
|
DevRoleListeners<T> devRoleListeners =
|
||||||
|
(DevRoleListeners<T>) mDevRoleForCapturePresetListeners.get(deviceRole);
|
||||||
|
if (devRoleListeners == null) {
|
||||||
|
return AudioSystem.ERROR;
|
||||||
|
}
|
||||||
|
synchronized (devRoleListeners.mDevRoleListenersLock) {
|
||||||
|
if (!devRoleListeners.removeDevRoleListener(listener)) {
|
||||||
|
return AudioSystem.BAD_VALUE;
|
||||||
|
}
|
||||||
|
if (devRoleListeners.mListenerInfos.size() == 0) {
|
||||||
|
// unregister binder for callbacks
|
||||||
|
synchronized (mDevRoleForCapturePresetListenersLock) {
|
||||||
|
mDeviceRoleListenersStatus ^= (1 << deviceRole);
|
||||||
|
if (mDeviceRoleListenersStatus != 0) {
|
||||||
|
// There are some other device role changed listeners active.
|
||||||
|
return AudioSystem.SUCCESS;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
getService().unregisterCapturePresetDevicesRoleDispatcher(
|
||||||
|
mDevicesRoleForCapturePresetDispatcherStub);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw e.rethrowFromSystemServer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return AudioSystem.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Map<Integer, Object> mDevRoleForCapturePresetListeners = new HashMap<>(){{
|
||||||
|
put(AudioSystem.DEVICE_ROLE_PREFERRED,
|
||||||
|
new DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>());
|
||||||
|
}};
|
||||||
|
|
||||||
|
private class DevRoleListenerInfo<T> {
|
||||||
|
final @NonNull Executor mExecutor;
|
||||||
|
final @NonNull T mListener;
|
||||||
|
DevRoleListenerInfo(Executor executor, T listener) {
|
||||||
|
mExecutor = executor;
|
||||||
|
mListener = listener;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DevRoleListeners<T> {
|
||||||
|
private final Object mDevRoleListenersLock = new Object();
|
||||||
|
@GuardedBy("mDevRoleListenersLock")
|
||||||
|
private @Nullable ArrayList<DevRoleListenerInfo<T>> mListenerInfos;
|
||||||
|
|
||||||
|
@GuardedBy("mDevRoleListenersLock")
|
||||||
|
private @Nullable DevRoleListenerInfo<T> getDevRoleListenerInfo(T listener) {
|
||||||
|
if (mListenerInfos == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (DevRoleListenerInfo<T> listenerInfo : mListenerInfos) {
|
||||||
|
if (listenerInfo.mListener == listener) {
|
||||||
|
return listenerInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GuardedBy("mDevRoleListenersLock")
|
||||||
|
private boolean hasDevRoleListener(T listener) {
|
||||||
|
return getDevRoleListenerInfo(listener) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GuardedBy("mDevRoleListenersLock")
|
||||||
|
private boolean removeDevRoleListener(T listener) {
|
||||||
|
final DevRoleListenerInfo<T> infoToRemove = getDevRoleListenerInfo(listener);
|
||||||
|
if (infoToRemove != null) {
|
||||||
|
mListenerInfos.remove(infoToRemove);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Object mDevRoleForCapturePresetListenersLock = new Object();
|
||||||
|
/**
|
||||||
|
* Record if there is a listener added for device role change. If there is a listener added for
|
||||||
|
* a specified device role change, the bit at position `1 << device_role` is set.
|
||||||
|
*/
|
||||||
|
@GuardedBy("mDevRoleForCapturePresetListenersLock")
|
||||||
|
private int mDeviceRoleListenersStatus = 0;
|
||||||
|
@GuardedBy("mDevRoleForCapturePresetListenersLock")
|
||||||
|
private CapturePresetDevicesRoleDispatcherStub mDevicesRoleForCapturePresetDispatcherStub;
|
||||||
|
|
||||||
|
private final class CapturePresetDevicesRoleDispatcherStub
|
||||||
|
extends ICapturePresetDevicesRoleDispatcher.Stub {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dispatchDevicesRoleChanged(
|
||||||
|
int capturePreset, int role, List<AudioDeviceAttributes> devices) {
|
||||||
|
final Object listenersObj = mDevRoleForCapturePresetListeners.get(role);
|
||||||
|
if (listenersObj == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (role) {
|
||||||
|
case AudioSystem.DEVICE_ROLE_PREFERRED: {
|
||||||
|
final DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>
|
||||||
|
listeners =
|
||||||
|
(DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>)
|
||||||
|
listenersObj;
|
||||||
|
final ArrayList<DevRoleListenerInfo<
|
||||||
|
OnPreferredDevicesForCapturePresetChangedListener>> prefDevListeners;
|
||||||
|
synchronized (listeners.mDevRoleListenersLock) {
|
||||||
|
if (listeners.mListenerInfos.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
prefDevListeners = (ArrayList<DevRoleListenerInfo<
|
||||||
|
OnPreferredDevicesForCapturePresetChangedListener>>)
|
||||||
|
listeners.mListenerInfos.clone();
|
||||||
|
}
|
||||||
|
final long ident = Binder.clearCallingIdentity();
|
||||||
|
try {
|
||||||
|
for (DevRoleListenerInfo<
|
||||||
|
OnPreferredDevicesForCapturePresetChangedListener> info :
|
||||||
|
prefDevListeners) {
|
||||||
|
info.mExecutor.execute(() ->
|
||||||
|
info.mListener.onPreferredDevicesForCapturePresetChanged(
|
||||||
|
capturePreset, devices));
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
Binder.restoreCallingIdentity(ident);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//====================================================================
|
//====================================================================
|
||||||
// Offload query
|
// Offload query
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import android.media.audiopolicy.AudioMix;
|
|||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.telephony.TelephonyManager;
|
import android.telephony.TelephonyManager;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
@@ -1750,6 +1751,134 @@ public class AudioSystem
|
|||||||
public static native int getDevicesForRoleAndStrategy(
|
public static native int getDevicesForRoleAndStrategy(
|
||||||
int strategy, int role, @NonNull List<AudioDeviceAttributes> devices);
|
int strategy, int role, @NonNull List<AudioDeviceAttributes> devices);
|
||||||
|
|
||||||
|
// use case routing by capture preset
|
||||||
|
|
||||||
|
private static Pair<int[], String[]> populateInputDevicesTypeAndAddress(
|
||||||
|
@NonNull List<AudioDeviceAttributes> devices) {
|
||||||
|
int[] types = new int[devices.size()];
|
||||||
|
String[] addresses = new String[devices.size()];
|
||||||
|
for (int i = 0; i < devices.size(); ++i) {
|
||||||
|
types[i] = devices.get(i).getInternalType();
|
||||||
|
if (types[i] == AudioSystem.DEVICE_NONE) {
|
||||||
|
types[i] = AudioDeviceInfo.convertDeviceTypeToInternalInputDevice(
|
||||||
|
devices.get(i).getType());
|
||||||
|
}
|
||||||
|
addresses[i] = devices.get(i).getAddress();
|
||||||
|
}
|
||||||
|
return new Pair<int[], String[]>(types, addresses);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
* Set devices as role for capture preset.
|
||||||
|
* @param capturePreset the capture preset to configure
|
||||||
|
* @param role the role of the devices
|
||||||
|
* @param devices the list of devices to be set as role for the given capture preset
|
||||||
|
* @return {@link #SUCCESS} if successfully set
|
||||||
|
*/
|
||||||
|
public static int setDevicesRoleForCapturePreset(
|
||||||
|
int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devices) {
|
||||||
|
if (devices.isEmpty()) {
|
||||||
|
return BAD_VALUE;
|
||||||
|
}
|
||||||
|
Pair<int[], String[]> typeAddresses = populateInputDevicesTypeAndAddress(devices);
|
||||||
|
return setDevicesRoleForCapturePreset(
|
||||||
|
capturePreset, role, typeAddresses.first, typeAddresses.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
* Set devices as role for capture preset.
|
||||||
|
* @param capturePreset the capture preset 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 setDevicesRoleForCapturePreset(
|
||||||
|
int capturePreset, int role, @NonNull int[] types, @NonNull String[] addresses);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
* Add devices as role for capture preset.
|
||||||
|
* @param capturePreset the capture preset to configure
|
||||||
|
* @param role the role of the devices
|
||||||
|
* @param devices the list of devices to be added as role for the given capture preset
|
||||||
|
* @return {@link #SUCCESS} if successfully add
|
||||||
|
*/
|
||||||
|
public static int addDevicesRoleForCapturePreset(
|
||||||
|
int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devices) {
|
||||||
|
if (devices.isEmpty()) {
|
||||||
|
return BAD_VALUE;
|
||||||
|
}
|
||||||
|
Pair<int[], String[]> typeAddresses = populateInputDevicesTypeAndAddress(devices);
|
||||||
|
return addDevicesRoleForCapturePreset(
|
||||||
|
capturePreset, role, typeAddresses.first, typeAddresses.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
* Add devices as role for capture preset.
|
||||||
|
* @param capturePreset the capture preset 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 addDevicesRoleForCapturePreset(
|
||||||
|
int capturePreset, int role, @NonNull int[] types, @NonNull String[] addresses);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
* Remove devices as role for the capture preset
|
||||||
|
* @param capturePreset the capture preset to configure
|
||||||
|
* @param role the role of the devices
|
||||||
|
* @param devices the devices to be removed
|
||||||
|
* @return {@link #SUCCESS} if successfully removed
|
||||||
|
*/
|
||||||
|
public static int removeDevicesRoleForCapturePreset(
|
||||||
|
int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devices) {
|
||||||
|
if (devices.isEmpty()) {
|
||||||
|
return BAD_VALUE;
|
||||||
|
}
|
||||||
|
Pair<int[], String[]> typeAddresses = populateInputDevicesTypeAndAddress(devices);
|
||||||
|
return removeDevicesRoleForCapturePreset(
|
||||||
|
capturePreset, role, typeAddresses.first, typeAddresses.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
* Remove devices as role for capture preset.
|
||||||
|
* @param capturePreset the capture preset 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 removeDevicesRoleForCapturePreset(
|
||||||
|
int capturePreset, int role, @NonNull int[] types, @NonNull String[] addresses);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
* Remove all devices as role for the capture preset
|
||||||
|
* @param capturePreset the capture preset to configure
|
||||||
|
* @param role the role of the devices
|
||||||
|
* @return {@link #SUCCESS} if successfully removed
|
||||||
|
*/
|
||||||
|
public static native int clearDevicesRoleForCapturePreset(int capturePreset, int role);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
* Query previously set devices as role for a capture preset
|
||||||
|
* @param capturePreset the capture preset to query for
|
||||||
|
* @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 getDevicesForRoleAndCapturePreset(
|
||||||
|
int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devices);
|
||||||
|
|
||||||
// Items shared with audio service
|
// Items shared with audio service
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import android.media.AudioRoutesInfo;
|
|||||||
import android.media.IAudioFocusDispatcher;
|
import android.media.IAudioFocusDispatcher;
|
||||||
import android.media.IAudioRoutesObserver;
|
import android.media.IAudioRoutesObserver;
|
||||||
import android.media.IAudioServerStateDispatcher;
|
import android.media.IAudioServerStateDispatcher;
|
||||||
|
import android.media.ICapturePresetDevicesRoleDispatcher;
|
||||||
import android.media.IPlaybackConfigDispatcher;
|
import android.media.IPlaybackConfigDispatcher;
|
||||||
import android.media.IRecordingConfigDispatcher;
|
import android.media.IRecordingConfigDispatcher;
|
||||||
import android.media.IRingtonePlayer;
|
import android.media.IRingtonePlayer;
|
||||||
@@ -307,4 +308,16 @@ interface IAudioService {
|
|||||||
// code via IAudioManager.h need to be added to the top section.
|
// code via IAudioManager.h need to be added to the top section.
|
||||||
|
|
||||||
oneway void setMultiAudioFocusEnabled(in boolean enabled);
|
oneway void setMultiAudioFocusEnabled(in boolean enabled);
|
||||||
|
|
||||||
|
int setPreferredDevicesForCapturePreset(
|
||||||
|
in int capturePreset, in List<AudioDeviceAttributes> devices);
|
||||||
|
|
||||||
|
int clearPreferredDevicesForCapturePreset(in int capturePreset);
|
||||||
|
|
||||||
|
List<AudioDeviceAttributes> getPreferredDevicesForCapturePreset(in int capturePreset);
|
||||||
|
|
||||||
|
void registerCapturePresetDevicesRoleDispatcher(ICapturePresetDevicesRoleDispatcher dispatcher);
|
||||||
|
|
||||||
|
oneway void unregisterCapturePresetDevicesRoleDispatcher(
|
||||||
|
ICapturePresetDevicesRoleDispatcher dispatcher);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package android.media;
|
||||||
|
|
||||||
|
import android.media.AudioDeviceAttributes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AIDL for AudioService to signal devices role for capture preset updates.
|
||||||
|
*
|
||||||
|
* {@hide}
|
||||||
|
*/
|
||||||
|
oneway interface ICapturePresetDevicesRoleDispatcher {
|
||||||
|
|
||||||
|
void dispatchDevicesRoleChanged(
|
||||||
|
int capturePreset, int role, in List<AudioDeviceAttributes> devices);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -404,6 +404,32 @@ public class MediaRecorder implements AudioRouting,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
* @param source An audio source to test
|
||||||
|
* @return true if the source is a valid one
|
||||||
|
*/
|
||||||
|
public static boolean isValidAudioSource(int source) {
|
||||||
|
switch(source) {
|
||||||
|
case AudioSource.MIC:
|
||||||
|
case AudioSource.VOICE_UPLINK:
|
||||||
|
case AudioSource.VOICE_DOWNLINK:
|
||||||
|
case AudioSource.VOICE_CALL:
|
||||||
|
case AudioSource.CAMCORDER:
|
||||||
|
case AudioSource.VOICE_RECOGNITION:
|
||||||
|
case AudioSource.VOICE_COMMUNICATION:
|
||||||
|
case AudioSource.REMOTE_SUBMIX:
|
||||||
|
case AudioSource.UNPROCESSED:
|
||||||
|
case AudioSource.VOICE_PERFORMANCE:
|
||||||
|
case AudioSource.ECHO_REFERENCE:
|
||||||
|
case AudioSource.RADIO_TUNER:
|
||||||
|
case AudioSource.HOTWORD:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** @hide */
|
/** @hide */
|
||||||
public static final String toLogFriendlyAudioSource(int source) {
|
public static final String toLogFriendlyAudioSource(int source) {
|
||||||
switch(source) {
|
switch(source) {
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import android.media.AudioDeviceAttributes;
|
|||||||
import android.media.AudioRoutesInfo;
|
import android.media.AudioRoutesInfo;
|
||||||
import android.media.AudioSystem;
|
import android.media.AudioSystem;
|
||||||
import android.media.IAudioRoutesObserver;
|
import android.media.IAudioRoutesObserver;
|
||||||
|
import android.media.ICapturePresetDevicesRoleDispatcher;
|
||||||
import android.media.IStrategyPreferredDevicesDispatcher;
|
import android.media.IStrategyPreferredDevicesDispatcher;
|
||||||
import android.media.MediaMetrics;
|
import android.media.MediaMetrics;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
@@ -546,6 +547,25 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
mDeviceInventory.unregisterStrategyPreferredDevicesDispatcher(dispatcher);
|
mDeviceInventory.unregisterStrategyPreferredDevicesDispatcher(dispatcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*package*/ int setPreferredDevicesForCapturePresetSync(int capturePreset,
|
||||||
|
@NonNull List<AudioDeviceAttributes> devices) {
|
||||||
|
return mDeviceInventory.setPreferredDevicesForCapturePresetSync(capturePreset, devices);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*package*/ int clearPreferredDevicesForCapturePresetSync(int capturePreset) {
|
||||||
|
return mDeviceInventory.clearPreferredDevicesForCapturePresetSync(capturePreset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*package*/ void registerCapturePresetDevicesRoleDispatcher(
|
||||||
|
@NonNull ICapturePresetDevicesRoleDispatcher dispatcher) {
|
||||||
|
mDeviceInventory.registerCapturePresetDevicesRoleDispatcher(dispatcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*package*/ void unregisterCapturePresetDevicesRoleDispatcher(
|
||||||
|
@NonNull ICapturePresetDevicesRoleDispatcher dispatcher) {
|
||||||
|
mDeviceInventory.unregisterCapturePresetDevicesRoleDispatcher(dispatcher);
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
||||||
// Communication with (to) AudioService
|
// Communication with (to) AudioService
|
||||||
//TODO check whether the AudioService methods are candidates to move here
|
//TODO check whether the AudioService methods are candidates to move here
|
||||||
@@ -694,6 +714,17 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
sendIMsgNoDelay(MSG_I_SAVE_REMOVE_PREF_DEVICES_FOR_STRATEGY, SENDMSG_QUEUE, strategy);
|
sendIMsgNoDelay(MSG_I_SAVE_REMOVE_PREF_DEVICES_FOR_STRATEGY, SENDMSG_QUEUE, strategy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*package*/ void postSaveSetPreferredDevicesForCapturePreset(
|
||||||
|
int capturePreset, List<AudioDeviceAttributes> devices) {
|
||||||
|
sendILMsgNoDelay(
|
||||||
|
MSG_IL_SAVE_PREF_DEVICES_FOR_CAPTURE_PRESET, SENDMSG_QUEUE, capturePreset, devices);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*package*/ void postSaveClearPreferredDevicesForCapturePreset(int capturePreset) {
|
||||||
|
sendIMsgNoDelay(
|
||||||
|
MSG_I_SAVE_CLEAR_PREF_DEVICES_FOR_CAPTURE_PRESET, SENDMSG_QUEUE, capturePreset);
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
||||||
// Method forwarding between the helper classes (BtHelper, AudioDeviceInventory)
|
// Method forwarding between the helper classes (BtHelper, AudioDeviceInventory)
|
||||||
// only call from a "handle"* method or "on"* method
|
// only call from a "handle"* method or "on"* method
|
||||||
@@ -1098,6 +1129,17 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
case MSG_CHECK_MUTE_MUSIC:
|
case MSG_CHECK_MUTE_MUSIC:
|
||||||
checkMessagesMuteMusic(0);
|
checkMessagesMuteMusic(0);
|
||||||
break;
|
break;
|
||||||
|
case MSG_IL_SAVE_PREF_DEVICES_FOR_CAPTURE_PRESET: {
|
||||||
|
final int capturePreset = msg.arg1;
|
||||||
|
final List<AudioDeviceAttributes> devices =
|
||||||
|
(List<AudioDeviceAttributes>) msg.obj;
|
||||||
|
mDeviceInventory.onSaveSetPreferredDevicesForCapturePreset(
|
||||||
|
capturePreset, devices);
|
||||||
|
} break;
|
||||||
|
case MSG_I_SAVE_CLEAR_PREF_DEVICES_FOR_CAPTURE_PRESET: {
|
||||||
|
final int capturePreset = msg.arg1;
|
||||||
|
mDeviceInventory.onSaveClearPreferredDevicesForCapturePreset(capturePreset);
|
||||||
|
} break;
|
||||||
default:
|
default:
|
||||||
Log.wtf(TAG, "Invalid message " + msg.what);
|
Log.wtf(TAG, "Invalid message " + msg.what);
|
||||||
}
|
}
|
||||||
@@ -1174,6 +1216,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
private static final int MSG_CHECK_MUTE_MUSIC = 36;
|
private static final int MSG_CHECK_MUTE_MUSIC = 36;
|
||||||
private static final int MSG_REPORT_NEW_ROUTES_A2DP = 37;
|
private static final int MSG_REPORT_NEW_ROUTES_A2DP = 37;
|
||||||
|
|
||||||
|
private static final int MSG_IL_SAVE_PREF_DEVICES_FOR_CAPTURE_PRESET = 38;
|
||||||
|
private static final int MSG_I_SAVE_CLEAR_PREF_DEVICES_FOR_CAPTURE_PRESET = 39;
|
||||||
|
|
||||||
|
|
||||||
private static boolean isMessageHandledUnderWakelock(int msgId) {
|
private static boolean isMessageHandledUnderWakelock(int msgId) {
|
||||||
switch(msgId) {
|
switch(msgId) {
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import android.media.AudioPort;
|
|||||||
import android.media.AudioRoutesInfo;
|
import android.media.AudioRoutesInfo;
|
||||||
import android.media.AudioSystem;
|
import android.media.AudioSystem;
|
||||||
import android.media.IAudioRoutesObserver;
|
import android.media.IAudioRoutesObserver;
|
||||||
|
import android.media.ICapturePresetDevicesRoleDispatcher;
|
||||||
import android.media.IStrategyPreferredDevicesDispatcher;
|
import android.media.IStrategyPreferredDevicesDispatcher;
|
||||||
import android.media.MediaMetrics;
|
import android.media.MediaMetrics;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
@@ -140,6 +141,10 @@ public class AudioDeviceInventory {
|
|||||||
private final ArrayMap<Integer, List<AudioDeviceAttributes>> mPreferredDevices =
|
private final ArrayMap<Integer, List<AudioDeviceAttributes>> mPreferredDevices =
|
||||||
new ArrayMap<>();
|
new ArrayMap<>();
|
||||||
|
|
||||||
|
// List of preferred devices of capture preset
|
||||||
|
private final ArrayMap<Integer, List<AudioDeviceAttributes>> mPreferredDevicesForCapturePreset =
|
||||||
|
new ArrayMap<>();
|
||||||
|
|
||||||
// the wrapper for AudioSystem static methods, allows us to spy AudioSystem
|
// the wrapper for AudioSystem static methods, allows us to spy AudioSystem
|
||||||
private final @NonNull AudioSystemAdapter mAudioSystem;
|
private final @NonNull AudioSystemAdapter mAudioSystem;
|
||||||
|
|
||||||
@@ -154,6 +159,10 @@ public class AudioDeviceInventory {
|
|||||||
final RemoteCallbackList<IStrategyPreferredDevicesDispatcher> mPrefDevDispatchers =
|
final RemoteCallbackList<IStrategyPreferredDevicesDispatcher> mPrefDevDispatchers =
|
||||||
new RemoteCallbackList<IStrategyPreferredDevicesDispatcher>();
|
new RemoteCallbackList<IStrategyPreferredDevicesDispatcher>();
|
||||||
|
|
||||||
|
// Monitoring of devices for role and capture preset
|
||||||
|
final RemoteCallbackList<ICapturePresetDevicesRoleDispatcher> mDevRoleCapturePresetDispatchers =
|
||||||
|
new RemoteCallbackList<ICapturePresetDevicesRoleDispatcher>();
|
||||||
|
|
||||||
/*package*/ AudioDeviceInventory(@NonNull AudioDeviceBroker broker) {
|
/*package*/ AudioDeviceInventory(@NonNull AudioDeviceBroker broker) {
|
||||||
mDeviceBroker = broker;
|
mDeviceBroker = broker;
|
||||||
mAudioSystem = AudioSystemAdapter.getDefaultAdapter();
|
mAudioSystem = AudioSystemAdapter.getDefaultAdapter();
|
||||||
@@ -243,6 +252,9 @@ public class AudioDeviceInventory {
|
|||||||
pw.println(" " + prefix + " type:0x" + Integer.toHexString(keyType)
|
pw.println(" " + prefix + " type:0x" + Integer.toHexString(keyType)
|
||||||
+ " (" + AudioSystem.getDeviceName(keyType)
|
+ " (" + AudioSystem.getDeviceName(keyType)
|
||||||
+ ") addr:" + valueAddress); });
|
+ ") addr:" + valueAddress); });
|
||||||
|
mPreferredDevicesForCapturePreset.forEach((capturePreset, devices) -> {
|
||||||
|
pw.println(" " + prefix + "capturePreset:" + capturePreset
|
||||||
|
+ " devices:" + devices); });
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------
|
//------------------------------------------------------------
|
||||||
@@ -270,6 +282,9 @@ public class AudioDeviceInventory {
|
|||||||
mAudioSystem.setDevicesRoleForStrategy(
|
mAudioSystem.setDevicesRoleForStrategy(
|
||||||
strategy, AudioSystem.DEVICE_ROLE_PREFERRED, devices); });
|
strategy, AudioSystem.DEVICE_ROLE_PREFERRED, devices); });
|
||||||
}
|
}
|
||||||
|
synchronized (mPreferredDevicesForCapturePreset) {
|
||||||
|
// TODO: call audiosystem to restore
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// only public for mocking/spying
|
// only public for mocking/spying
|
||||||
@@ -613,6 +628,20 @@ public class AudioDeviceInventory {
|
|||||||
dispatchPreferredDevice(strategy, new ArrayList<AudioDeviceAttributes>());
|
dispatchPreferredDevice(strategy, new ArrayList<AudioDeviceAttributes>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*package*/ void onSaveSetPreferredDevicesForCapturePreset(
|
||||||
|
int capturePreset, @NonNull List<AudioDeviceAttributes> devices) {
|
||||||
|
mPreferredDevicesForCapturePreset.put(capturePreset, devices);
|
||||||
|
dispatchDevicesRoleForCapturePreset(
|
||||||
|
capturePreset, AudioSystem.DEVICE_ROLE_PREFERRED, devices);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*package*/ void onSaveClearPreferredDevicesForCapturePreset(int capturePreset) {
|
||||||
|
mPreferredDevicesForCapturePreset.remove(capturePreset);
|
||||||
|
dispatchDevicesRoleForCapturePreset(
|
||||||
|
capturePreset, AudioSystem.DEVICE_ROLE_PREFERRED,
|
||||||
|
new ArrayList<AudioDeviceAttributes>());
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------
|
//------------------------------------------------------------
|
||||||
//
|
//
|
||||||
|
|
||||||
@@ -651,6 +680,41 @@ public class AudioDeviceInventory {
|
|||||||
mPrefDevDispatchers.unregister(dispatcher);
|
mPrefDevDispatchers.unregister(dispatcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*package*/ int setPreferredDevicesForCapturePresetSync(
|
||||||
|
int capturePreset, @NonNull List<AudioDeviceAttributes> devices) {
|
||||||
|
final long identity = Binder.clearCallingIdentity();
|
||||||
|
final int status = mAudioSystem.setDevicesRoleForCapturePreset(
|
||||||
|
capturePreset, AudioSystem.DEVICE_ROLE_PREFERRED, devices);
|
||||||
|
Binder.restoreCallingIdentity(identity);
|
||||||
|
|
||||||
|
if (status == AudioSystem.SUCCESS) {
|
||||||
|
mDeviceBroker.postSaveSetPreferredDevicesForCapturePreset(capturePreset, devices);
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*package*/ int clearPreferredDevicesForCapturePresetSync(int capturePreset) {
|
||||||
|
final long identity = Binder.clearCallingIdentity();
|
||||||
|
final int status = mAudioSystem.clearDevicesRoleForCapturePreset(
|
||||||
|
capturePreset, AudioSystem.DEVICE_ROLE_PREFERRED);
|
||||||
|
Binder.restoreCallingIdentity(identity);
|
||||||
|
|
||||||
|
if (status == AudioSystem.SUCCESS) {
|
||||||
|
mDeviceBroker.postSaveClearPreferredDevicesForCapturePreset(capturePreset);
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*package*/ void registerCapturePresetDevicesRoleDispatcher(
|
||||||
|
@NonNull ICapturePresetDevicesRoleDispatcher dispatcher) {
|
||||||
|
mDevRoleCapturePresetDispatchers.register(dispatcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*package*/ void unregisterCapturePresetDevicesRoleDispatcher(
|
||||||
|
@NonNull ICapturePresetDevicesRoleDispatcher dispatcher) {
|
||||||
|
mDevRoleCapturePresetDispatchers.unregister(dispatcher);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements the communication with AudioSystem to (dis)connect a device in the native layers
|
* Implements the communication with AudioSystem to (dis)connect a device in the native layers
|
||||||
* @param connect true if connection
|
* @param connect true if connection
|
||||||
@@ -1306,6 +1370,19 @@ public class AudioDeviceInventory {
|
|||||||
mPrefDevDispatchers.finishBroadcast();
|
mPrefDevDispatchers.finishBroadcast();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void dispatchDevicesRoleForCapturePreset(
|
||||||
|
int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devices) {
|
||||||
|
final int nbDispatchers = mDevRoleCapturePresetDispatchers.beginBroadcast();
|
||||||
|
for (int i = 0; i < nbDispatchers; ++i) {
|
||||||
|
try {
|
||||||
|
mDevRoleCapturePresetDispatchers.getBroadcastItem(i).dispatchDevicesRoleChanged(
|
||||||
|
capturePreset, role, devices);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mDevRoleCapturePresetDispatchers.finishBroadcast();
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------
|
//----------------------------------------------------------
|
||||||
// For tests only
|
// For tests only
|
||||||
|
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ import android.media.IAudioFocusDispatcher;
|
|||||||
import android.media.IAudioRoutesObserver;
|
import android.media.IAudioRoutesObserver;
|
||||||
import android.media.IAudioServerStateDispatcher;
|
import android.media.IAudioServerStateDispatcher;
|
||||||
import android.media.IAudioService;
|
import android.media.IAudioService;
|
||||||
|
import android.media.ICapturePresetDevicesRoleDispatcher;
|
||||||
import android.media.IPlaybackConfigDispatcher;
|
import android.media.IPlaybackConfigDispatcher;
|
||||||
import android.media.IRecordingConfigDispatcher;
|
import android.media.IRecordingConfigDispatcher;
|
||||||
import android.media.IRingtonePlayer;
|
import android.media.IRingtonePlayer;
|
||||||
@@ -1938,6 +1939,94 @@ public class AudioService extends IAudioService.Stub
|
|||||||
mDeviceBroker.unregisterStrategyPreferredDevicesDispatcher(dispatcher);
|
mDeviceBroker.unregisterStrategyPreferredDevicesDispatcher(dispatcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see AudioManager#setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)
|
||||||
|
*/
|
||||||
|
public int setPreferredDevicesForCapturePreset(
|
||||||
|
int capturePreset, List<AudioDeviceAttributes> devices) {
|
||||||
|
if (devices == null) {
|
||||||
|
return AudioSystem.ERROR;
|
||||||
|
}
|
||||||
|
enforceModifyAudioRoutingPermission();
|
||||||
|
final String logString = String.format(
|
||||||
|
"setPreferredDevicesForCapturePreset u/pid:%d/%d source:%d dev:%s",
|
||||||
|
Binder.getCallingUid(), Binder.getCallingPid(), capturePreset,
|
||||||
|
devices.stream().map(e -> e.toString()).collect(Collectors.joining(",")));
|
||||||
|
sDeviceLogger.log(new AudioEventLogger.StringEvent(logString).printLog(TAG));
|
||||||
|
if (devices.stream().anyMatch(device ->
|
||||||
|
device.getRole() == AudioDeviceAttributes.ROLE_OUTPUT)) {
|
||||||
|
Log.e(TAG, "Unsupported output routing in " + logString);
|
||||||
|
return AudioSystem.ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int status = mDeviceBroker.setPreferredDevicesForCapturePresetSync(
|
||||||
|
capturePreset, devices);
|
||||||
|
if (status != AudioSystem.SUCCESS) {
|
||||||
|
Log.e(TAG, String.format("Error %d in %s)", status, logString));
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @see AudioManager#clearPreferredDevicesForCapturePreset(int) */
|
||||||
|
public int clearPreferredDevicesForCapturePreset(int capturePreset) {
|
||||||
|
enforceModifyAudioRoutingPermission();
|
||||||
|
final String logString = String.format(
|
||||||
|
"removePreferredDeviceForCapturePreset source:%d", capturePreset);
|
||||||
|
sDeviceLogger.log(new AudioEventLogger.StringEvent(logString).printLog(TAG));
|
||||||
|
|
||||||
|
final int status = mDeviceBroker.clearPreferredDevicesForCapturePresetSync(capturePreset);
|
||||||
|
if (status != AudioSystem.SUCCESS) {
|
||||||
|
Log.e(TAG, String.format("Error %d in %s", status, logString));
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see AudioManager#getPreferredDevicesForCapturePreset(int)
|
||||||
|
*/
|
||||||
|
public List<AudioDeviceAttributes> getPreferredDevicesForCapturePreset(int capturePreset) {
|
||||||
|
enforceModifyAudioRoutingPermission();
|
||||||
|
List<AudioDeviceAttributes> devices = new ArrayList<>();
|
||||||
|
final long identity = Binder.clearCallingIdentity();
|
||||||
|
final int status = AudioSystem.getDevicesForRoleAndCapturePreset(
|
||||||
|
capturePreset, AudioSystem.DEVICE_ROLE_PREFERRED, devices);
|
||||||
|
Binder.restoreCallingIdentity(identity);
|
||||||
|
if (status != AudioSystem.SUCCESS) {
|
||||||
|
Log.e(TAG, String.format("Error %d in getPreferredDeviceForCapturePreset(%d)",
|
||||||
|
status, capturePreset));
|
||||||
|
return new ArrayList<AudioDeviceAttributes>();
|
||||||
|
} else {
|
||||||
|
return devices;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see AudioManager#addOnPreferredDevicesForCapturePresetChangedListener(
|
||||||
|
* Executor, OnPreferredDevicesForCapturePresetChangedListener)
|
||||||
|
*/
|
||||||
|
public void registerCapturePresetDevicesRoleDispatcher(
|
||||||
|
@Nullable ICapturePresetDevicesRoleDispatcher dispatcher) {
|
||||||
|
if (dispatcher == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
enforceModifyAudioRoutingPermission();
|
||||||
|
mDeviceBroker.registerCapturePresetDevicesRoleDispatcher(dispatcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see AudioManager#removeOnPreferredDevicesForCapturePresetChangedListener(
|
||||||
|
* AudioManager.OnPreferredDevicesForCapturePresetChangedListener)
|
||||||
|
*/
|
||||||
|
public void unregisterCapturePresetDevicesRoleDispatcher(
|
||||||
|
@Nullable ICapturePresetDevicesRoleDispatcher dispatcher) {
|
||||||
|
if (dispatcher == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
enforceModifyAudioRoutingPermission();
|
||||||
|
mDeviceBroker.unregisterCapturePresetDevicesRoleDispatcher(dispatcher);
|
||||||
|
}
|
||||||
|
|
||||||
/** @see AudioManager#getDevicesForAttributes(AudioAttributes) */
|
/** @see AudioManager#getDevicesForAttributes(AudioAttributes) */
|
||||||
public @NonNull ArrayList<AudioDeviceAttributes> getDevicesForAttributes(
|
public @NonNull ArrayList<AudioDeviceAttributes> getDevicesForAttributes(
|
||||||
@NonNull AudioAttributes attributes) {
|
@NonNull AudioAttributes attributes) {
|
||||||
|
|||||||
@@ -100,6 +100,40 @@ public class AudioSystemAdapter {
|
|||||||
return AudioSystem.removeDevicesRoleForStrategy(strategy, role);
|
return AudioSystem.removeDevicesRoleForStrategy(strategy, role);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as (@link AudioSystem#setDevicesRoleForCapturePreset(int, List))
|
||||||
|
* @param capturePreset
|
||||||
|
* @param role
|
||||||
|
* @param devices
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int setDevicesRoleForCapturePreset(int capturePreset, int role,
|
||||||
|
@NonNull List<AudioDeviceAttributes> devices) {
|
||||||
|
return AudioSystem.setDevicesRoleForCapturePreset(capturePreset, role, devices);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as {@link AudioSystem#removeDevicesRoleForCapturePreset(int, int)}
|
||||||
|
* @param capturePreset
|
||||||
|
* @param role
|
||||||
|
* @param devicesToRemove
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int removeDevicesRoleForCapturePreset(
|
||||||
|
int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devicesToRemove) {
|
||||||
|
return AudioSystem.removeDevicesRoleForCapturePreset(capturePreset, role, devicesToRemove);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as {@link AudioSystem#}
|
||||||
|
* @param capturePreset
|
||||||
|
* @param role
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int clearDevicesRoleForCapturePreset(int capturePreset, int role) {
|
||||||
|
return AudioSystem.clearDevicesRoleForCapturePreset(capturePreset, role);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Same as {@link AudioSystem#setParameters(String)}
|
* Same as {@link AudioSystem#setParameters(String)}
|
||||||
* @param keyValuePairs
|
* @param keyValuePairs
|
||||||
|
|||||||
@@ -78,6 +78,23 @@ public class NoOpAudioSystemAdapter extends AudioSystemAdapter {
|
|||||||
return AudioSystem.AUDIO_STATUS_OK;
|
return AudioSystem.AUDIO_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int setDevicesRoleForCapturePreset(int capturePreset, int role,
|
||||||
|
@NonNull List<AudioDeviceAttributes> devices) {
|
||||||
|
return AudioSystem.AUDIO_STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int removeDevicesRoleForCapturePreset(
|
||||||
|
int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devicesToRemove) {
|
||||||
|
return AudioSystem.AUDIO_STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int clearDevicesRoleForCapturePreset(int capturePreset, int role) {
|
||||||
|
return AudioSystem.AUDIO_STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int setParameters(String keyValuePairs) {
|
public int setParameters(String keyValuePairs) {
|
||||||
return AudioSystem.AUDIO_STATUS_OK;
|
return AudioSystem.AUDIO_STATUS_OK;
|
||||||
|
|||||||
Reference in New Issue
Block a user