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