AudioPolicyConfig.java revision 08c7116ab9cd04ad6dd3c04aa1017237e7f409ac
1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.media.audiopolicy;
18
19import android.media.AudioFormat;
20import android.media.audiopolicy.AudioMixingRule.AttributeMatchCriterion;
21import android.os.Parcel;
22import android.os.Parcelable;
23import android.util.Log;
24
25import java.util.ArrayList;
26import java.util.Objects;
27
28/**
29 * @hide
30 * Internal storage class for AudioPolicy configuration.
31 */
32public class AudioPolicyConfig implements Parcelable {
33
34    private static final String TAG = "AudioPolicyConfig";
35
36    protected ArrayList<AudioMix> mMixes;
37    protected int mDuckingPolicy = AudioPolicy.FOCUS_POLICY_DUCKING_IN_APP;
38
39    private String mRegistrationId = null;
40
41    protected AudioPolicyConfig(AudioPolicyConfig conf) {
42        mMixes = conf.mMixes;
43    }
44
45    AudioPolicyConfig(ArrayList<AudioMix> mixes) {
46        mMixes = mixes;
47    }
48
49    /**
50     * Add an {@link AudioMix} to be part of the audio policy being built.
51     * @param mix a non-null {@link AudioMix} to be part of the audio policy.
52     * @return the same Builder instance.
53     * @throws IllegalArgumentException
54     */
55    public void addMix(AudioMix mix) throws IllegalArgumentException {
56        if (mix == null) {
57            throw new IllegalArgumentException("Illegal null AudioMix argument");
58        }
59        mMixes.add(mix);
60    }
61
62    @Override
63    public int hashCode() {
64        return Objects.hash(mMixes);
65    }
66
67    @Override
68    public int describeContents() {
69        return 0;
70    }
71
72    @Override
73    public void writeToParcel(Parcel dest, int flags) {
74        dest.writeInt(mMixes.size());
75        for (AudioMix mix : mMixes) {
76            // write mix route flags
77            dest.writeInt(mix.getRouteFlags());
78            // write mix format
79            dest.writeInt(mix.getFormat().getSampleRate());
80            dest.writeInt(mix.getFormat().getEncoding());
81            dest.writeInt(mix.getFormat().getChannelMask());
82            // write mix rules
83            final ArrayList<AttributeMatchCriterion> criteria = mix.getRule().getCriteria();
84            dest.writeInt(criteria.size());
85            for (AttributeMatchCriterion criterion : criteria) {
86                criterion.writeToParcel(dest);
87            }
88        }
89    }
90
91    private AudioPolicyConfig(Parcel in) {
92        mMixes = new ArrayList<AudioMix>();
93        int nbMixes = in.readInt();
94        for (int i = 0 ; i < nbMixes ; i++) {
95            final AudioMix.Builder mixBuilder = new AudioMix.Builder();
96            // read mix route flags
97            int routeFlags = in.readInt();
98            mixBuilder.setRouteFlags(routeFlags);
99            // read mix format
100            int sampleRate = in.readInt();
101            int encoding = in.readInt();
102            int channelMask = in.readInt();
103            final AudioFormat format = new AudioFormat.Builder().setSampleRate(sampleRate)
104                    .setChannelMask(channelMask).setEncoding(encoding).build();
105            mixBuilder.setFormat(format);
106            // read mix rules
107            int nbRules = in.readInt();
108            AudioMixingRule.Builder ruleBuilder = new AudioMixingRule.Builder();
109            for (int j = 0 ; j < nbRules ; j++) {
110                // read the matching rules
111                ruleBuilder.addRuleFromParcel(in);
112            }
113            mixBuilder.setMixingRule(ruleBuilder.build());
114            mMixes.add(mixBuilder.build());
115        }
116    }
117
118    public static final Parcelable.Creator<AudioPolicyConfig> CREATOR
119            = new Parcelable.Creator<AudioPolicyConfig>() {
120        /**
121         * Rebuilds an AudioPolicyConfig previously stored with writeToParcel().
122         * @param p Parcel object to read the AudioPolicyConfig from
123         * @return a new AudioPolicyConfig created from the data in the parcel
124         */
125        public AudioPolicyConfig createFromParcel(Parcel p) {
126            return new AudioPolicyConfig(p);
127        }
128        public AudioPolicyConfig[] newArray(int size) {
129            return new AudioPolicyConfig[size];
130        }
131    };
132
133    public String toLogFriendlyString () {
134        String textDump = new String("android.media.audiopolicy.AudioPolicyConfig:\n");
135        textDump += mMixes.size() + " AudioMix: "+ mRegistrationId + "\n";
136        for(AudioMix mix : mMixes) {
137            // write mix route flags
138            textDump += "* route flags=0x" + Integer.toHexString(mix.getRouteFlags()) + "\n";
139            // write mix format
140            textDump += "  rate=" + mix.getFormat().getSampleRate() + "Hz\n";
141            textDump += "  encoding=" + mix.getFormat().getEncoding() + "\n";
142            textDump += "  channels=0x";
143            textDump += Integer.toHexString(mix.getFormat().getChannelMask()).toUpperCase() +"\n";
144            // write mix rules
145            final ArrayList<AttributeMatchCriterion> criteria = mix.getRule().getCriteria();
146            for (AttributeMatchCriterion criterion : criteria) {
147                switch(criterion.mRule) {
148                    case AudioMixingRule.RULE_EXCLUDE_ATTRIBUTE_USAGE:
149                        textDump += "  exclude usage ";
150                        textDump += criterion.mAttr.usageToString();
151                        break;
152                    case AudioMixingRule.RULE_MATCH_ATTRIBUTE_USAGE:
153                        textDump += "  match usage ";
154                        textDump += criterion.mAttr.usageToString();
155                        break;
156                    case AudioMixingRule.RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET:
157                        textDump += "  exclude capture preset ";
158                        textDump += criterion.mAttr.getCapturePreset();
159                        break;
160                    case AudioMixingRule.RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
161                        textDump += "  match capture preset ";
162                        textDump += criterion.mAttr.getCapturePreset();
163                        break;
164                    default:
165                        textDump += "invalid rule!";
166                }
167                textDump += "\n";
168            }
169        }
170        return textDump;
171    }
172
173    protected void setRegistration(String regId) {
174        final boolean currentRegNull = (mRegistrationId == null) || mRegistrationId.isEmpty();
175        final boolean newRegNull = (regId == null) || regId.isEmpty();
176        if (!currentRegNull && !newRegNull && !mRegistrationId.equals(regId)) {
177            Log.e(TAG, "Invalid registration transition from " + mRegistrationId + " to " + regId);
178            return;
179        }
180        mRegistrationId = regId == null ? "" : regId;
181        int mixIndex = 0;
182        for (AudioMix mix : mMixes) {
183            if (!mRegistrationId.isEmpty()) {
184                mix.setRegistration(mRegistrationId + "mix" + mixTypeId(mix.getMixType()) + ":"
185                        + mixIndex++);
186            } else {
187                mix.setRegistration("");
188            }
189        }
190    }
191
192    private static String mixTypeId(int type) {
193        if (type == AudioMix.MIX_TYPE_PLAYERS) return "p";
194        else if (type == AudioMix.MIX_TYPE_RECORDERS) return "r";
195        else return "i";
196    }
197
198    protected String getRegistration() {
199        return mRegistrationId;
200    }
201}
202