diff options
| author | 2016-03-12 01:09:10 +0000 | |
|---|---|---|
| committer | 2016-03-12 01:09:11 +0000 | |
| commit | a40c017ba2d4241bbe96c929e58f3c9b8048a37b (patch) | |
| tree | 5e508b235e0cb1a25240f276a1dbdde8d8e6dfd5 | |
| parent | 102c51229f88bd3a4c57023207e1340e6b4d8b73 (diff) | |
| parent | e8924115f9a57d35149da89c2a1bd920fdd0fe39 (diff) | |
Merge "Dynamic audio policies: allow device passing for RENDER mixes" into nyc-dev
| -rw-r--r-- | api/system-current.txt | 1 | ||||
| -rw-r--r-- | media/java/android/media/audiopolicy/AudioMix.java | 93 | ||||
| -rw-r--r-- | media/java/android/media/audiopolicy/AudioPolicyConfig.java | 17 |
3 files changed, 100 insertions, 11 deletions
diff --git a/api/system-current.txt b/api/system-current.txt index c9176ecf03c3..0743b9154c38 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -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; } diff --git a/media/java/android/media/audiopolicy/AudioMix.java b/media/java/android/media/audiopolicy/AudioMix.java index 55fb82bbdcc5..56d3c9987bc1 100644 --- a/media/java/android/media/audiopolicy/AudioMix.java +++ b/media/java/android/media/audiopolicy/AudioMix.java @@ -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()); @@ -226,6 +241,19 @@ public class AudioMix { } /** + * @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. * @return the same Builder 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,15 +283,41 @@ 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 * @throws IllegalArgumentException if no {@link AudioMixingRule} has been set. @@ -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); } } } diff --git a/media/java/android/media/audiopolicy/AudioPolicyConfig.java b/media/java/android/media/audiopolicy/AudioPolicyConfig.java index 5d2bac02a5e0..3af3ae71a734 100644 --- a/media/java/android/media/audiopolicy/AudioPolicyConfig.java +++ b/media/java/android/media/audiopolicy/AudioPolicyConfig.java @@ -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(""); } |