1a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi/*
2a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi * Copyright (C) 2014 The Android Open Source Project
3a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi *
4a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi * Licensed under the Apache License, Version 2.0 (the "License");
5a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi * you may not use this file except in compliance with the License.
6a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi * You may obtain a copy of the License at
7a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi *
8a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi *      http://www.apache.org/licenses/LICENSE-2.0
9a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi *
10a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi * Unless required by applicable law or agreed to in writing, software
11a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi * distributed under the License is distributed on an "AS IS" BASIS,
12a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi * See the License for the specific language governing permissions and
14a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi * limitations under the License.
15a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi */
16a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi
17a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivipackage android.media.audiopolicy;
18a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi
191b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Triviimport android.annotation.SystemApi;
20a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Triviimport android.media.AudioAttributes;
211b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Triviimport android.os.Parcel;
22a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi
23a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Triviimport java.util.ArrayList;
24a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Triviimport java.util.Iterator;
251b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Triviimport java.util.Objects;
26a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi
27a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi
28a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi/**
298fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi * @hide
30a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi *
31a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi * Here's an example of creating a mixing rule for all media playback:
32a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi * <pre>
33a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi * AudioAttributes mediaAttr = new AudioAttributes.Builder()
34a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi *         .setUsage(AudioAttributes.USAGE_MEDIA)
35a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi *         .build();
36a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi * AudioMixingRule mediaRule = new AudioMixingRule.Builder()
37a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi *         .addRule(mediaAttr, AudioMixingRule.RULE_MATCH_ATTRIBUTE_USAGE)
38a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi *         .build();
39a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi * </pre>
40a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi */
411b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi@SystemApi
42a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivipublic class AudioMixingRule {
43a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi
441b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi    private AudioMixingRule(int mixType, ArrayList<AttributeMatchCriterion> criteria) {
45a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        mCriteria = criteria;
461b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi        mTargetMixType = mixType;
47a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi    }
48a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi
49a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi    /**
501b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi     * A rule requiring the usage information of the {@link AudioAttributes} to match.
51a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi     */
521b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi    @SystemApi
53a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi    public static final int RULE_MATCH_ATTRIBUTE_USAGE = 0x1;
54a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi    /**
551b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi     * A rule requiring the capture preset information of the {@link AudioAttributes} to match.
56a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi     */
571b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi    @SystemApi
581b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi    public static final int RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET = 0x1 << 1;
591b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi
601b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi    private final static int RULE_EXCLUSION_MASK = 0x8000;
611b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi    /**
621b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi     * @hide
631b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi     * A rule requiring the usage information of the {@link AudioAttributes} to differ.
641b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi     */
651b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi    public static final int RULE_EXCLUDE_ATTRIBUTE_USAGE =
661b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            RULE_EXCLUSION_MASK | RULE_MATCH_ATTRIBUTE_USAGE;
671b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi    /**
681b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi     * @hide
691b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi     * A rule requiring the capture preset information of the {@link AudioAttributes} to differ.
701b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi     */
711b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi    public static final int RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET =
721b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            RULE_EXCLUSION_MASK | RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET;
73a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi
74a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi    static final class AttributeMatchCriterion {
75a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        AudioAttributes mAttr;
76a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        int mRule;
77a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi
781b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi        /** input parameters must be valid */
79a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        AttributeMatchCriterion(AudioAttributes attributes, int rule) {
80a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            mAttr = attributes;
81a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            mRule = rule;
82a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        }
831b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi
841b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi        @Override
851b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi        public int hashCode() {
861b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            return Objects.hash(mAttr, mRule);
871b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi        }
881b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi
891b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi        void writeToParcel(Parcel dest) {
901b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            dest.writeInt(mRule);
911b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            if ((mRule == RULE_MATCH_ATTRIBUTE_USAGE) || (mRule == RULE_EXCLUDE_ATTRIBUTE_USAGE)) {
921b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                dest.writeInt(mAttr.getUsage());
931b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            } else {
941b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                // capture preset rule
951b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                dest.writeInt(mAttr.getCapturePreset());
961b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            }
971b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi        }
98a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi    }
99a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi
1001b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi    private final int mTargetMixType;
1011b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi    int getTargetMixType() { return mTargetMixType; }
1021b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi    private final ArrayList<AttributeMatchCriterion> mCriteria;
103a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi    ArrayList<AttributeMatchCriterion> getCriteria() { return mCriteria; }
104a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi
1051b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi    @Override
1061b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi    public int hashCode() {
1071b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi        return Objects.hash(mTargetMixType, mCriteria);
1081b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi    }
1091b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi
1101b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi    private static boolean isValidSystemApiRule(int rule) {
1111b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi        switch(rule) {
1121b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            case RULE_MATCH_ATTRIBUTE_USAGE:
1131b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
1141b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                return true;
1151b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            default:
1161b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                return false;
1171b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi        }
1181b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi    }
1191b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi
1201b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi    private static boolean isValidIntRule(int rule) {
1211b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi        switch(rule) {
1221b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            case RULE_MATCH_ATTRIBUTE_USAGE:
1231b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            case RULE_EXCLUDE_ATTRIBUTE_USAGE:
1241b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
1251b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            case RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET:
1261b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                return true;
1271b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            default:
1281b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                return false;
1291b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi        }
1301b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi    }
1311b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi
1321b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi    private static boolean isPlayerRule(int rule) {
1331b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi        return ((rule == RULE_MATCH_ATTRIBUTE_USAGE)
1341b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                || (rule == RULE_EXCLUDE_ATTRIBUTE_USAGE));
1351b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi    }
1361b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi
137a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi    /**
138a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi     * Builder class for {@link AudioMixingRule} objects
139a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi     */
1401b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi    @SystemApi
141a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi    public static class Builder {
142a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        private ArrayList<AttributeMatchCriterion> mCriteria;
1431b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi        private int mTargetMixType = AudioMix.MIX_TYPE_INVALID;
144a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi
145a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        /**
146a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi         * Constructs a new Builder with no rules.
147a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi         */
1481b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi        @SystemApi
149a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        public Builder() {
150a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            mCriteria = new ArrayList<AttributeMatchCriterion>();
151a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        }
152a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi
153a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        /**
154a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi         * Add a rule for the selection of which streams are mixed together.
155a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi         * @param attrToMatch a non-null AudioAttributes instance for which a contradictory
156a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi         *     rule hasn't been set yet.
1571b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi         * @param rule {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_USAGE} or
1581b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi         *     {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET}.
159a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi         * @return the same Builder instance.
160a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi         * @throws IllegalArgumentException
161a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi         */
1621b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi        @SystemApi
163a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        public Builder addRule(AudioAttributes attrToMatch, int rule)
164a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                throws IllegalArgumentException {
1651b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            if (!isValidSystemApiRule(rule)) {
1661b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                throw new IllegalArgumentException("Illegal rule value " + rule);
1671b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            }
1681b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            return addRuleInt(attrToMatch, rule);
1691b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi        }
1701b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi
1711b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi        /**
1721b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi         * Add a rule by exclusion for the selection of which streams are mixed together.
1731b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi         * <br>For instance the following code
1741b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi         * <br><pre>
1751b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi         * AudioAttributes mediaAttr = new AudioAttributes.Builder()
1761b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi         *         .setUsage(AudioAttributes.USAGE_MEDIA)
1771b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi         *         .build();
1781b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi         * AudioMixingRule noMediaRule = new AudioMixingRule.Builder()
1791b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi         *         .excludeRule(mediaAttr, AudioMixingRule.RULE_MATCH_ATTRIBUTE_USAGE)
1801b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi         *         .build();
1811b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi         * </pre>
1821b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi         * <br>will create a rule which maps to any usage value, except USAGE_MEDIA.
1831b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi         * @param attrToMatch a non-null AudioAttributes instance for which a contradictory
1841b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi         *     rule hasn't been set yet.
1851b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi         * @param rule {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_USAGE} or
1861b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi         *     {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET}.
1871b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi         * @return the same Builder instance.
1881b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi         * @throws IllegalArgumentException
1891b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi         */
1901b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi        @SystemApi
1911b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi        public Builder excludeRule(AudioAttributes attrToMatch, int rule)
1921b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                throws IllegalArgumentException {
1931b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            if (!isValidSystemApiRule(rule)) {
1941b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                throw new IllegalArgumentException("Illegal rule value " + rule);
1951b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            }
1961b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            return addRuleInt(attrToMatch, rule | RULE_EXCLUSION_MASK);
1971b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi        }
1981b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi
1991b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi        /**
2001b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi         * Add or exclude a rule for the selection of which streams are mixed together.
2011b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi         * @param attrToMatch a non-null AudioAttributes instance for which a contradictory
2021b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi         *     rule hasn't been set yet.
2031b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi         * @param rule one of {@link AudioMixingRule#RULE_EXCLUDE_ATTRIBUTE_USAGE},
2041b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi         *     {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_USAGE},
2051b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi         *     {@link AudioMixingRule#RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET} or
2061b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi         *     {@link AudioMixingRule#RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET}.
2071b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi         * @return the same Builder instance.
2081b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi         * @throws IllegalArgumentException
2091b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi         */
2101b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi        Builder addRuleInt(AudioAttributes attrToMatch, int rule)
2111b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                throws IllegalArgumentException {
212a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            if (attrToMatch == null) {
213a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                throw new IllegalArgumentException("Illegal null AudioAttributes argument");
214a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            }
2151b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            if (!isValidIntRule(rule)) {
216a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                throw new IllegalArgumentException("Illegal rule value " + rule);
2171b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            } else {
2181b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                // as rules are added to the Builder, we verify they are consistent with the type
2191b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                // of mix being built. When adding the first rule, the mix type is MIX_TYPE_INVALID.
2201b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                if (mTargetMixType == AudioMix.MIX_TYPE_INVALID) {
2211b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                    if (isPlayerRule(rule)) {
2221b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                        mTargetMixType = AudioMix.MIX_TYPE_PLAYERS;
2231b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                    } else {
2241b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                        mTargetMixType = AudioMix.MIX_TYPE_RECORDERS;
2251b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                    }
2261b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                } else if (((mTargetMixType == AudioMix.MIX_TYPE_PLAYERS) && !isPlayerRule(rule))
2271b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                        || ((mTargetMixType == AudioMix.MIX_TYPE_RECORDERS) && isPlayerRule(rule)))
2281b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                {
2291b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                    throw new IllegalArgumentException("Incompatible rule for mix");
2301b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                }
231a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            }
232a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            synchronized (mCriteria) {
233a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                Iterator<AttributeMatchCriterion> crIterator = mCriteria.iterator();
234a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                while (crIterator.hasNext()) {
235a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                    final AttributeMatchCriterion criterion = crIterator.next();
236a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                    if ((rule == RULE_MATCH_ATTRIBUTE_USAGE)
237a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                            || (rule == RULE_EXCLUDE_ATTRIBUTE_USAGE)) {
238a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                        // "usage"-based rule
239a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                        if (criterion.mAttr.getUsage() == attrToMatch.getUsage()) {
240a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                            if (criterion.mRule == rule) {
241a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                                // rule already exists, we're done
242a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                                return this;
243a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                            } else {
244a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                                // criterion already exists with a another rule, it is incompatible
245a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                                throw new IllegalArgumentException("Contradictory rule exists for "
246a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                                        + attrToMatch);
247a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                            }
248a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                        }
2491b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                    } else if ((rule == RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET)
2501b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                            || (rule == RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET)) {
2511b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                        // "capture preset"-base rule
2521b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                        if (criterion.mAttr.getCapturePreset() == attrToMatch.getCapturePreset()) {
2531b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                            if (criterion.mRule == rule) {
2541b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                             // rule already exists, we're done
2551b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                                return this;
2561b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                            } else {
2571b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                                // criterion already exists with a another rule, it is incompatible
2581b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                                throw new IllegalArgumentException("Contradictory rule exists for "
2591b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                                        + attrToMatch);
2601b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                            }
2611b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                        }
262a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                    }
263a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                }
264a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                // rule didn't exist, add it
265a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                mCriteria.add(new AttributeMatchCriterion(attrToMatch, rule));
266a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            }
267a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            return this;
268a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        }
269a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi
2701b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi        Builder addRuleFromParcel(Parcel in) throws IllegalArgumentException {
2711b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            int rule = in.readInt();
2721b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            AudioAttributes attr;
2731b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            if ((rule == RULE_MATCH_ATTRIBUTE_USAGE) || (rule == RULE_EXCLUDE_ATTRIBUTE_USAGE)) {
2741b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                int usage = in.readInt();
2751b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                attr = new AudioAttributes.Builder()
2761b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                        .setUsage(usage).build();
2771b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            } else if ((rule == RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET)
2781b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                    || (rule == RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET)) {
2791b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                int preset = in.readInt();
2801b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                attr = new AudioAttributes.Builder()
2811b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                        .setInternalCapturePreset(preset).build();
2821b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            } else {
2831b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                in.readInt(); // assume there was in int value to read as for now they come in pair
2841b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                throw new IllegalArgumentException("Illegal rule value " + rule + " in parcel");
2851b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            }
2861b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            return addRuleInt(attr, rule);
2871b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi        }
2881b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi
289a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        /**
290a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi         * Combines all of the matching and exclusion rules that have been set and return a new
291a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi         * {@link AudioMixingRule} object.
292a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi         * @return a new {@link AudioMixingRule} object
293a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi         */
294a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        public AudioMixingRule build() {
2951b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            return new AudioMixingRule(mTargetMixType, mCriteria);
296a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        }
297a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi    }
298a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi}
299