/* * Copyright (C) 2014 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.audiopolicy; import android.annotation.NonNull; import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; import android.media.AudioAttributes; import android.os.Build; import android.os.Parcel; import android.util.Log; import java.util.ArrayList; import java.util.Iterator; import java.util.Objects; /** * @hide * * Here's an example of creating a mixing rule for all media playback: *
* AudioAttributes mediaAttr = new AudioAttributes.Builder() * .setUsage(AudioAttributes.USAGE_MEDIA) * .build(); * AudioMixingRule mediaRule = new AudioMixingRule.Builder() * .addRule(mediaAttr, AudioMixingRule.RULE_MATCH_ATTRIBUTE_USAGE) * .build(); **/ @SystemApi public class AudioMixingRule { private AudioMixingRule(int mixType, ArrayList
* AudioAttributes mediaAttr = new AudioAttributes.Builder() * .setUsage(AudioAttributes.USAGE_MEDIA) * .build(); * AudioMixingRule noMediaRule = new AudioMixingRule.Builder() * .excludeRule(mediaAttr, AudioMixingRule.RULE_MATCH_ATTRIBUTE_USAGE) * .build(); **
* AudioAttributes mediaAttr = new AudioAttributes.Builder() * .setUsage(AudioAttributes.USAGE_MEDIA) * .build(); * AudioMixingRule noMediaRule = new AudioMixingRule.Builder() * .addMixRule(AudioMixingRule.RULE_MATCH_ATTRIBUTE_USAGE, mediaAttr) * .excludeMixRule(AudioMixingRule.RULE_MATCH_UID, new Integer(uidToExclude) * .build(); **
true
, MUST abide to the restriction listed in
* {@link ALLOW_CAPTURE_BY_SYSTEM}, including but not limited to the captured audio
* can not leave the capturing app, and the quality is limited to 16k mono.
*
* The permission {@link CAPTURE_AUDIO_OUTPUT} or {@link CAPTURE_MEDIA_OUTPUT} is needed
* to ignore the opt-out.
*
* Only affects LOOPBACK|RENDER mix.
*
* @return the same Builder instance.
*/
public @NonNull Builder allowPrivilegedPlaybackCapture(boolean allow) {
mAllowPrivilegedMediaPlaybackCapture = allow;
return this;
}
/**
* Set if the caller of the rule is able to capture voice communication output.
* A system app can capture voice communication output only if it is granted with the.
* CAPTURE_VOICE_COMMUNICATION_OUTPUT permission.
*
* Note that this method is for internal use only and should not be called by the app that
* creates the rule.
*
* @return the same Builder instance.
*
* @hide
*/
public @NonNull Builder voiceCommunicationCaptureAllowed(boolean allowed) {
mVoiceCommunicationCaptureAllowed = allowed;
return this;
}
/**
* Set target mix type of the mixing rule.
*
* Note: If the mix type was not specified, it will be decided automatically by mixing
* rule. For {@link #RULE_MATCH_UID}, the default type is {@link AudioMix#MIX_TYPE_PLAYERS}.
*
* @param mixType {@link AudioMix#MIX_TYPE_PLAYERS} or {@link AudioMix#MIX_TYPE_RECORDERS}
* @return the same Builder instance.
*
* @hide
*/
public @NonNull Builder setTargetMixType(int mixType) {
mTargetMixType = mixType;
Log.i("AudioMixingRule", "Builder setTargetMixType " + mixType);
return this;
}
/**
* Add or exclude a rule for the selection of which streams are mixed together.
* Does error checking on the parameters.
* @param rule
* @param property
* @return the same Builder instance.
* @throws IllegalArgumentException
*/
private Builder checkAddRuleObjInternal(int rule, Object property)
throws IllegalArgumentException {
if (property == null) {
throw new IllegalArgumentException("Illegal null argument for mixing rule");
}
if (!isValidRule(rule)) {
throw new IllegalArgumentException("Illegal rule value " + rule);
}
final int match_rule = rule & ~RULE_EXCLUSION_MASK;
if (isAudioAttributeRule(match_rule)) {
if (!(property instanceof AudioAttributes)) {
throw new IllegalArgumentException("Invalid AudioAttributes argument");
}
return addRuleInternal((AudioAttributes) property, null, rule);
} else {
// implies integer match rule
if (!(property instanceof Integer)) {
throw new IllegalArgumentException("Invalid Integer argument");
}
return addRuleInternal(null, (Integer) property, rule);
}
}
/**
* Add or exclude a rule on AudioAttributes or integer property for the selection of which
* streams are mixed together.
* No rule-to-parameter type check, all done in {@link #checkAddRuleObjInternal(int, Object)}.
* Exceptions are thrown only when incompatible rules are added.
* @param attrToMatch a non-null AudioAttributes instance for which a contradictory
* rule hasn't been set yet, null if not used.
* @param intProp an integer property to match or exclude, null if not used.
* @param rule one of {@link AudioMixingRule#RULE_EXCLUDE_ATTRIBUTE_USAGE},
* {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_USAGE},
* {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET} or
* {@link AudioMixingRule#RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET},
* {@link AudioMixingRule#RULE_MATCH_UID}, {@link AudioMixingRule#RULE_EXCLUDE_UID}.
* {@link AudioMixingRule#RULE_MATCH_USERID},
* {@link AudioMixingRule#RULE_EXCLUDE_USERID}.
* @return the same Builder instance.
* @throws IllegalArgumentException
*/
private Builder addRuleInternal(AudioAttributes attrToMatch, Integer intProp, int rule)
throws IllegalArgumentException {
// as rules are added to the Builder, we verify they are consistent with the type
// of mix being built. When adding the first rule, the mix type is MIX_TYPE_INVALID.
if (mTargetMixType == AudioMix.MIX_TYPE_INVALID) {
if (isPlayerRule(rule)) {
mTargetMixType = AudioMix.MIX_TYPE_PLAYERS;
} else if (isRecorderRule(rule)) {
mTargetMixType = AudioMix.MIX_TYPE_RECORDERS;
} else {
// For rules which are not player or recorder specific (e.g. RULE_MATCH_UID),
// the default mix type is MIX_TYPE_PLAYERS.
mTargetMixType = AudioMix.MIX_TYPE_PLAYERS;
}
} else if ((isPlayerRule(rule) && (mTargetMixType != AudioMix.MIX_TYPE_PLAYERS))
|| (isRecorderRule(rule)) && (mTargetMixType != AudioMix.MIX_TYPE_RECORDERS))
{
throw new IllegalArgumentException("Incompatible rule for mix");
}
synchronized (mCriteria) {
Iterator