Merge "Dynamic audio policies: allow device passing for RENDER mixes" into nyc-dev

This commit is contained in:
Jean-Michel Trivi
2016-03-12 01:09:10 +00:00
committed by Android (Google) Code Review
3 changed files with 100 additions and 11 deletions

View File

@@ -23829,6 +23829,7 @@ package android.media.audiopolicy {
public static class AudioMix.Builder {
ctor public AudioMix.Builder(android.media.audiopolicy.AudioMixingRule) throws java.lang.IllegalArgumentException;
method public android.media.audiopolicy.AudioMix build() throws java.lang.IllegalArgumentException;
method public android.media.audiopolicy.AudioMix.Builder setDevice(android.media.AudioDeviceInfo) throws java.lang.IllegalArgumentException;
method public android.media.audiopolicy.AudioMix.Builder setFormat(android.media.AudioFormat) throws java.lang.IllegalArgumentException;
method public android.media.audiopolicy.AudioMix.Builder setRouteFlags(int) throws java.lang.IllegalArgumentException;
}

View File

@@ -17,7 +17,9 @@
package android.media.audiopolicy;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.media.AudioDeviceInfo;
import android.media.AudioFormat;
import android.media.AudioSystem;
@@ -36,19 +38,28 @@ public class AudioMix {
private int mRouteFlags;
private String mRegistrationId;
private int mMixType = MIX_TYPE_INVALID;
// written by AudioPolicy
int mMixState = MIX_STATE_DISABLED;
int mCallbackFlags;
// initialized in constructor, read by AudioPolicyConfig
final int mDeviceId;
final String mDeviceAddress;
/**
* All parameters are guaranteed valid through the Builder.
*/
private AudioMix(AudioMixingRule rule, AudioFormat format, int routeFlags, int callbackFlags) {
private AudioMix(AudioMixingRule rule, AudioFormat format, int routeFlags, int callbackFlags,
int deviceId, String deviceAddress) {
mRule = rule;
mFormat = format;
mRouteFlags = routeFlags;
mRegistrationId = null;
mMixType = rule.getTargetMixType();
mCallbackFlags = callbackFlags;
mDeviceId = deviceId;
mDeviceAddress = deviceAddress;
}
// CALLBACK_FLAG_* values: keep in sync with AudioMix::kCbFlag* values defined
@@ -74,6 +85,8 @@ public class AudioMix {
@SystemApi
public static final int ROUTE_FLAG_LOOP_BACK = 0x1 << 1;
private static final int ROUTE_FLAG_SUPPORTED = ROUTE_FLAG_RENDER | ROUTE_FLAG_LOOP_BACK;
// MIX_TYPE_* values to keep in sync with frameworks/av/include/media/AudioPolicy.h
/**
* @hide
@@ -172,6 +185,8 @@ public class AudioMix {
private AudioFormat mFormat = null;
private int mRouteFlags = 0;
private int mCallbackFlags = 0;
private int mDeviceId = -1;
private String mDeviceAddress = null;
/**
* @hide
@@ -200,7 +215,7 @@ public class AudioMix {
* @return the same Builder instance.
* @throws IllegalArgumentException
*/
public Builder setMixingRule(AudioMixingRule rule)
Builder setMixingRule(AudioMixingRule rule)
throws IllegalArgumentException {
if (rule == null) {
throw new IllegalArgumentException("Illegal null AudioMixingRule argument");
@@ -216,7 +231,7 @@ public class AudioMix {
* @return the same Builder instance.
* @throws IllegalArgumentException
*/
public Builder setCallbackFlags(int flags) throws IllegalArgumentException {
Builder setCallbackFlags(int flags) throws IllegalArgumentException {
if ((flags != 0) && ((flags & CALLBACK_FLAGS_ALL) == 0)) {
throw new IllegalArgumentException("Illegal callback flags 0x"
+ Integer.toHexString(flags).toUpperCase());
@@ -225,6 +240,19 @@ public class AudioMix {
return this;
}
/**
* @hide
* Only used by AudioPolicyConfig, not a public API.
* @param deviceId
* @param address
* @return the same Builder instance.
*/
Builder setDevice(int deviceId, String address) {
mDeviceId = deviceId;
mDeviceAddress = address;
return this;
}
/**
* Sets the {@link AudioFormat} for the mix.
* @param format a non-null {@link AudioFormat} instance.
@@ -242,7 +270,8 @@ public class AudioMix {
}
/**
* Sets the routing behavior for the mix.
* Sets the routing behavior for the mix. If not set, routing behavior will default to
* {@link AudioMix#ROUTE_FLAG_LOOP_BACK}.
* @param routeFlags one of {@link AudioMix#ROUTE_FLAG_LOOP_BACK},
* {@link AudioMix#ROUTE_FLAG_RENDER}
* @return the same Builder instance.
@@ -254,14 +283,40 @@ public class AudioMix {
if (routeFlags == 0) {
throw new IllegalArgumentException("Illegal empty route flags");
}
if ((routeFlags & (ROUTE_FLAG_LOOP_BACK | ROUTE_FLAG_RENDER)) == 0) {
if ((routeFlags & ROUTE_FLAG_SUPPORTED) == 0) {
throw new IllegalArgumentException("Invalid route flags 0x"
+ Integer.toHexString(routeFlags) + "when creating an AudioMix");
+ Integer.toHexString(routeFlags) + "when configuring an AudioMix");
}
if ((routeFlags & ~ROUTE_FLAG_SUPPORTED) != 0) {
throw new IllegalArgumentException("Unknown route flags 0x"
+ Integer.toHexString(routeFlags) + "when configuring an AudioMix");
}
mRouteFlags = routeFlags;
return this;
}
/**
* Sets the audio device used for playback. Cannot be used in the context of an audio
* policy used to inject audio to be recorded, or in a mix whose route flags doesn't
* specify {@link AudioMix#ROUTE_FLAG_RENDER}.
* @param device a non-null AudioDeviceInfo describing the audio device to play the output
* of this mix.
* @return the same Builder instance
* @throws IllegalArgumentException
*/
@SystemApi
public Builder setDevice(@NonNull AudioDeviceInfo device) throws IllegalArgumentException {
if (device == null) {
throw new IllegalArgumentException("Illegal null AudioDeviceInfo argument");
}
if (!device.isSink()) {
throw new IllegalArgumentException("Unsupported device type on mix, not a sink");
}
mDeviceId = device.getId();
mDeviceAddress = device.getAddress();
return this;
}
/**
* Combines all of the settings and return a new {@link AudioMix} object.
* @return a new {@link AudioMix} object
@@ -273,8 +328,13 @@ public class AudioMix {
throw new IllegalArgumentException("Illegal null AudioMixingRule");
}
if (mRouteFlags == 0) {
// no route flags set, use default
mRouteFlags = ROUTE_FLAG_RENDER;
// no route flags set, use default as described in Builder.setRouteFlags(int)
mRouteFlags = ROUTE_FLAG_LOOP_BACK;
}
// can't do loop back AND render at same time in this implementation
if (mRouteFlags == (ROUTE_FLAG_RENDER | ROUTE_FLAG_LOOP_BACK)) {
throw new IllegalArgumentException("Unsupported route behavior combination 0x" +
Integer.toHexString(mRouteFlags));
}
if (mFormat == null) {
// FIXME Can we eliminate this? Will AudioMix work with an unspecified sample rate?
@@ -284,7 +344,22 @@ public class AudioMix {
}
mFormat = new AudioFormat.Builder().setSampleRate(rate).build();
}
return new AudioMix(mRule, mFormat, mRouteFlags, mCallbackFlags);
if (mDeviceId != -1) {
if ((mRouteFlags & ROUTE_FLAG_RENDER) == 0) {
throw new IllegalArgumentException(
"Can't have audio device without flag ROUTE_FLAG_RENDER");
}
if (mRule.getTargetMixType() != AudioMix.MIX_TYPE_PLAYERS) {
throw new IllegalArgumentException("Unsupported device on non-playback mix");
}
} else {
if ((mRouteFlags & ROUTE_FLAG_RENDER) == ROUTE_FLAG_RENDER) {
throw new IllegalArgumentException(
"Can't have flag ROUTE_FLAG_RENDER without an audio device");
}
}
return new AudioMix(mRule, mFormat, mRouteFlags, mCallbackFlags, mDeviceId,
mDeviceAddress);
}
}
}

View File

@@ -17,6 +17,8 @@
package android.media.audiopolicy;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioPatch;
import android.media.audiopolicy.AudioMixingRule.AudioMixMatchCriterion;
import android.os.Parcel;
import android.os.Parcelable;
@@ -81,6 +83,9 @@ public class AudioPolicyConfig implements Parcelable {
dest.writeInt(mix.getRouteFlags());
// write callback flags
dest.writeInt(mix.mCallbackFlags);
// write device information
dest.writeInt(mix.mDeviceId);
dest.writeString(mix.mDeviceAddress);
// write mix format
dest.writeInt(mix.getFormat().getSampleRate());
dest.writeInt(mix.getFormat().getEncoding());
@@ -104,6 +109,8 @@ public class AudioPolicyConfig implements Parcelable {
mixBuilder.setRouteFlags(routeFlags);
// read callback flags
mixBuilder.setCallbackFlags(in.readInt());
// read device information
mixBuilder.setDevice(in.readInt(), in.readString());
// read mix format
int sampleRate = in.readInt();
int encoding = in.readInt();
@@ -197,8 +204,14 @@ public class AudioPolicyConfig implements Parcelable {
int mixIndex = 0;
for (AudioMix mix : mMixes) {
if (!mRegistrationId.isEmpty()) {
mix.setRegistration(mRegistrationId + "mix" + mixTypeId(mix.getMixType()) + ":"
+ mixIndex++);
if ((mix.getRouteFlags() & AudioMix.ROUTE_FLAG_LOOP_BACK) ==
AudioMix.ROUTE_FLAG_LOOP_BACK) {
mix.setRegistration(mRegistrationId + "mix" + mixTypeId(mix.getMixType()) + ":"
+ mixIndex++);
} else if ((mix.getRouteFlags() & AudioMix.ROUTE_FLAG_RENDER) ==
AudioMix.ROUTE_FLAG_RENDER) {
mix.setRegistration(mix.mDeviceAddress);
}
} else {
mix.setRegistration("");
}