Merge "AudioManager: set/get audio device volume behavior" into rvc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
e9ffff37d4
@@ -99,11 +99,11 @@ public final class AudioDeviceAttributes implements Parcelable {
|
||||
if (role != ROLE_OUTPUT && role != ROLE_INPUT) {
|
||||
throw new IllegalArgumentException("Invalid role " + role);
|
||||
}
|
||||
if (role == ROLE_OUTPUT && !AudioDeviceInfo.isValidAudioDeviceTypeOut(type)) {
|
||||
throw new IllegalArgumentException("Invalid output device type " + type);
|
||||
if (role == ROLE_OUTPUT) {
|
||||
AudioDeviceInfo.enforceValidAudioDeviceTypeOut(type);
|
||||
}
|
||||
if (role == ROLE_INPUT && !AudioDeviceInfo.isValidAudioDeviceTypeIn(type)) {
|
||||
throw new IllegalArgumentException("Invalid input device type " + type);
|
||||
if (role == ROLE_INPUT) {
|
||||
AudioDeviceInfo.enforceValidAudioDeviceTypeIn(type);
|
||||
}
|
||||
|
||||
mRole = role;
|
||||
|
||||
@@ -280,6 +280,28 @@ public final class AudioDeviceInfo {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* Throws IAE on an invalid output device type
|
||||
* @param type
|
||||
*/
|
||||
public static void enforceValidAudioDeviceTypeOut(int type) {
|
||||
if (!isValidAudioDeviceTypeOut(type)) {
|
||||
throw new IllegalArgumentException("Illegal output device type " + type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* Throws IAE on an invalid input device type
|
||||
* @param type
|
||||
*/
|
||||
public static void enforceValidAudioDeviceTypeIn(int type) {
|
||||
if (!isValidAudioDeviceTypeIn(type)) {
|
||||
throw new IllegalArgumentException("Illegal input device type " + type);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
||||
@@ -4571,6 +4571,150 @@ public class AudioManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* Volume behavior for an audio device where a software attenuation is applied
|
||||
* @see #setDeviceVolumeBehavior(int, String, int)
|
||||
*/
|
||||
public static final int DEVICE_VOLUME_BEHAVIOR_VARIABLE = 0;
|
||||
/**
|
||||
* @hide
|
||||
* Volume behavior for an audio device where the volume is always set to provide no attenuation
|
||||
* nor gain (e.g. unit gain).
|
||||
* @see #setDeviceVolumeBehavior(int, String, int)
|
||||
*/
|
||||
public static final int DEVICE_VOLUME_BEHAVIOR_FULL = 1;
|
||||
/**
|
||||
* @hide
|
||||
* Volume behavior for an audio device where the volume is either set to muted, or to provide
|
||||
* no attenuation nor gain (e.g. unit gain).
|
||||
* @see #setDeviceVolumeBehavior(int, String, int)
|
||||
*/
|
||||
public static final int DEVICE_VOLUME_BEHAVIOR_FIXED = 2;
|
||||
/**
|
||||
* @hide
|
||||
* Volume behavior for an audio device where no software attenuation is applied, and
|
||||
* the volume is kept synchronized between the host and the device itself through a
|
||||
* device-specific protocol such as BT AVRCP.
|
||||
* @see #setDeviceVolumeBehavior(int, String, int)
|
||||
*/
|
||||
public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE = 3;
|
||||
/**
|
||||
* @hide
|
||||
* Volume behavior for an audio device where no software attenuation is applied, and
|
||||
* the volume is kept synchronized between the host and the device itself through a
|
||||
* device-specific protocol (such as for hearing aids), based on the audio mode (e.g.
|
||||
* normal vs in phone call).
|
||||
* @see #setMode(int)
|
||||
* @see #setDeviceVolumeBehavior(int, String, int)
|
||||
*/
|
||||
public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE = 4;
|
||||
|
||||
/** @hide */
|
||||
@IntDef({
|
||||
DEVICE_VOLUME_BEHAVIOR_VARIABLE,
|
||||
DEVICE_VOLUME_BEHAVIOR_FULL,
|
||||
DEVICE_VOLUME_BEHAVIOR_FIXED,
|
||||
DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
|
||||
DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface DeviceVolumeBehavior {}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* Throws IAE on an invalid volume behavior value
|
||||
* @param volumeBehavior behavior value to check
|
||||
*/
|
||||
public static void enforceValidVolumeBehavior(int volumeBehavior) {
|
||||
switch (volumeBehavior) {
|
||||
case DEVICE_VOLUME_BEHAVIOR_VARIABLE:
|
||||
case DEVICE_VOLUME_BEHAVIOR_FULL:
|
||||
case DEVICE_VOLUME_BEHAVIOR_FIXED:
|
||||
case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE:
|
||||
case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE:
|
||||
return;
|
||||
default:
|
||||
throw new IllegalArgumentException("Illegal volume behavior " + volumeBehavior);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* Sets the volume behavior for an audio output device.
|
||||
* @param deviceType the type of audio device to be affected. Currently only supports
|
||||
* {@link AudioDeviceInfo#TYPE_HDMI}, {@link AudioDeviceInfo#TYPE_HDMI_ARC},
|
||||
* {@link AudioDeviceInfo#TYPE_LINE_DIGITAL} and {@link AudioDeviceInfo#TYPE_AUX_LINE}
|
||||
* @param deviceAddress the address of the device, if any
|
||||
* @param deviceVolumeBehavior one of the device behaviors
|
||||
*/
|
||||
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
|
||||
public void setDeviceVolumeBehavior(int deviceType, @Nullable String deviceAddress,
|
||||
@DeviceVolumeBehavior int deviceVolumeBehavior) {
|
||||
setDeviceVolumeBehavior(new AudioDeviceAttributes(AudioDeviceAttributes.ROLE_OUTPUT,
|
||||
deviceType, deviceAddress), deviceVolumeBehavior);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* Sets the volume behavior for an audio output device.
|
||||
* @param device the device to be affected. Currently only supports devices of type
|
||||
* {@link AudioDeviceInfo#TYPE_HDMI}, {@link AudioDeviceInfo#TYPE_HDMI_ARC},
|
||||
* {@link AudioDeviceInfo#TYPE_LINE_DIGITAL} and {@link AudioDeviceInfo#TYPE_AUX_LINE}
|
||||
* @param deviceVolumeBehavior one of the device behaviors
|
||||
*/
|
||||
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
|
||||
public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device,
|
||||
@DeviceVolumeBehavior int deviceVolumeBehavior) {
|
||||
// verify arguments (validity of device type is enforced in server)
|
||||
Objects.requireNonNull(device);
|
||||
enforceValidVolumeBehavior(deviceVolumeBehavior);
|
||||
// communicate with service
|
||||
final IAudioService service = getService();
|
||||
try {
|
||||
service.setDeviceVolumeBehavior(device, deviceVolumeBehavior,
|
||||
mApplicationContext.getOpPackageName());
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* Returns the volume device behavior for the given device type and address
|
||||
* @param deviceType an audio output device type, as defined in {@link AudioDeviceInfo}
|
||||
* @param deviceAddress the address of the audio device, if any.
|
||||
* @return the volume behavior for the device
|
||||
*/
|
||||
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
|
||||
public @DeviceVolumeBehavior int getDeviceVolumeBehavior(int deviceType,
|
||||
@Nullable String deviceAddress) {
|
||||
// verify arguments
|
||||
AudioDeviceInfo.enforceValidAudioDeviceTypeOut(deviceType);
|
||||
return getDeviceVolumeBehavior(new AudioDeviceAttributes(AudioDeviceAttributes.ROLE_OUTPUT,
|
||||
deviceType, deviceAddress));
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* Returns the volume device behavior for the given audio device
|
||||
* @param device the audio device
|
||||
* @return the volume behavior for the device
|
||||
*/
|
||||
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
|
||||
public @DeviceVolumeBehavior int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device)
|
||||
{
|
||||
// verify arguments (validity of device type is enforced in server)
|
||||
Objects.requireNonNull(device);
|
||||
// communicate with service
|
||||
final IAudioService service = getService();
|
||||
try {
|
||||
return service.getDeviceVolumeBehavior(device);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate wired accessory connection state change.
|
||||
* @param device type of device connected/disconnected (AudioManager.DEVICE_OUT_xxx)
|
||||
|
||||
@@ -294,6 +294,11 @@ interface IAudioService {
|
||||
|
||||
oneway void setRttEnabled(in boolean rttEnabled);
|
||||
|
||||
void setDeviceVolumeBehavior(in AudioDeviceAttributes device,
|
||||
in int deviceVolumeBehavior, in String pkgName);
|
||||
|
||||
int getDeviceVolumeBehavior(in AudioDeviceAttributes device);
|
||||
|
||||
// WARNING: read warning at top of file, new methods that need to be used by native
|
||||
// code via IAudioManager.h need to be added to the top section.
|
||||
}
|
||||
|
||||
@@ -2332,8 +2332,7 @@ public class AudioService extends IAudioService.Stub
|
||||
}
|
||||
|
||||
private void enforceModifyAudioRoutingPermission() {
|
||||
if (mContext.checkCallingOrSelfPermission(
|
||||
android.Manifest.permission.MODIFY_AUDIO_ROUTING)
|
||||
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
throw new SecurityException("Missing MODIFY_AUDIO_ROUTING permission");
|
||||
}
|
||||
@@ -4610,6 +4609,117 @@ public class AudioService extends IAudioService.Stub
|
||||
observeDevicesForStreams(-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see AudioManager#setDeviceVolumeBehavior(AudioDeviceAttributes, int)
|
||||
* @param device the audio device to be affected
|
||||
* @param deviceVolumeBehavior one of the device behaviors
|
||||
*/
|
||||
public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device,
|
||||
@AudioManager.DeviceVolumeBehavior int deviceVolumeBehavior, @Nullable String pkgName) {
|
||||
// verify permissions
|
||||
enforceModifyAudioRoutingPermission();
|
||||
// verify arguments
|
||||
Objects.requireNonNull(device);
|
||||
AudioManager.enforceValidVolumeBehavior(deviceVolumeBehavior);
|
||||
if (pkgName == null) {
|
||||
pkgName = "";
|
||||
}
|
||||
// translate Java device type to native device type (for the devices masks for full / fixed)
|
||||
final int type;
|
||||
switch (device.getType()) {
|
||||
case AudioDeviceInfo.TYPE_HDMI:
|
||||
type = AudioSystem.DEVICE_OUT_HDMI;
|
||||
break;
|
||||
case AudioDeviceInfo.TYPE_HDMI_ARC:
|
||||
type = AudioSystem.DEVICE_OUT_HDMI_ARC;
|
||||
break;
|
||||
case AudioDeviceInfo.TYPE_LINE_DIGITAL:
|
||||
type = AudioSystem.DEVICE_OUT_SPDIF;
|
||||
break;
|
||||
case AudioDeviceInfo.TYPE_AUX_LINE:
|
||||
type = AudioSystem.DEVICE_OUT_LINE;
|
||||
break;
|
||||
default:
|
||||
// unsupported for now
|
||||
throw new IllegalArgumentException("Unsupported device type " + device.getType());
|
||||
}
|
||||
// update device masks based on volume behavior
|
||||
switch (deviceVolumeBehavior) {
|
||||
case AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE:
|
||||
mFullVolumeDevices.remove(type);
|
||||
mFixedVolumeDevices.remove(type);
|
||||
break;
|
||||
case AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED:
|
||||
mFullVolumeDevices.remove(type);
|
||||
mFixedVolumeDevices.add(type);
|
||||
break;
|
||||
case AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL:
|
||||
mFullVolumeDevices.add(type);
|
||||
mFixedVolumeDevices.remove(type);
|
||||
break;
|
||||
case AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE:
|
||||
case AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE:
|
||||
throw new IllegalArgumentException("Absolute volume unsupported for now");
|
||||
}
|
||||
// log event and caller
|
||||
sDeviceLogger.log(new AudioEventLogger.StringEvent(
|
||||
"Volume behavior " + deviceVolumeBehavior
|
||||
+ " for dev=0x" + Integer.toHexString(type) + " by pkg:" + pkgName));
|
||||
// make sure we have a volume entry for this device, and that volume is updated according
|
||||
// to volume behavior
|
||||
checkAddAllFixedVolumeDevices(type, "setDeviceVolumeBehavior:" + pkgName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see AudioManager#getDeviceVolumeBehavior(AudioDeviceAttributes)
|
||||
* @param device the audio output device type
|
||||
* @return the volume behavior for the device
|
||||
*/
|
||||
public @AudioManager.DeviceVolumeBehavior int getDeviceVolumeBehavior(
|
||||
@NonNull AudioDeviceAttributes device) {
|
||||
// verify permissions
|
||||
enforceModifyAudioRoutingPermission();
|
||||
// translate Java device type to native device type (for the devices masks for full / fixed)
|
||||
final int type;
|
||||
switch (device.getType()) {
|
||||
case AudioDeviceInfo.TYPE_HEARING_AID:
|
||||
type = AudioSystem.DEVICE_OUT_HEARING_AID;
|
||||
break;
|
||||
case AudioDeviceInfo.TYPE_BLUETOOTH_A2DP:
|
||||
type = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
|
||||
break;
|
||||
case AudioDeviceInfo.TYPE_HDMI:
|
||||
type = AudioSystem.DEVICE_OUT_HDMI;
|
||||
break;
|
||||
case AudioDeviceInfo.TYPE_HDMI_ARC:
|
||||
type = AudioSystem.DEVICE_OUT_HDMI_ARC;
|
||||
break;
|
||||
case AudioDeviceInfo.TYPE_LINE_DIGITAL:
|
||||
type = AudioSystem.DEVICE_OUT_SPDIF;
|
||||
break;
|
||||
case AudioDeviceInfo.TYPE_AUX_LINE:
|
||||
type = AudioSystem.DEVICE_OUT_LINE;
|
||||
break;
|
||||
default:
|
||||
// unsupported for now
|
||||
throw new IllegalArgumentException("Unsupported device type " + device.getType());
|
||||
}
|
||||
if ((mFullVolumeDevices.contains(type))) {
|
||||
return AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL;
|
||||
}
|
||||
if ((mFixedVolumeDevices.contains(type))) {
|
||||
return AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED;
|
||||
}
|
||||
if ((mAbsVolumeMultiModeCaseDevices.contains(type))) {
|
||||
return AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE;
|
||||
}
|
||||
if (type == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP
|
||||
&& mDeviceBroker.isAvrcpAbsoluteVolumeSupported()) {
|
||||
return AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE;
|
||||
}
|
||||
return AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE;
|
||||
}
|
||||
|
||||
/*package*/ static final int CONNECTION_STATE_DISCONNECTED = 0;
|
||||
/*package*/ static final int CONNECTION_STATE_CONNECTED = 1;
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user