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 17 package android.media.audiopolicy; 18 19 import android.media.AudioFormat; 20 import android.media.audiopolicy.AudioMixingRule.AttributeMatchCriterion; 21 import android.os.Parcel; 22 import android.os.Parcelable; 23 import android.util.Log; 24 25 import java.util.ArrayList; 26 import java.util.Objects; 27 28 /** 29 * @hide 30 * Internal storage class for AudioPolicy configuration. 31 */ 32 public 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 AudioPolicyConfig(AudioPolicyConfig conf)41 protected AudioPolicyConfig(AudioPolicyConfig conf) { 42 mMixes = conf.mMixes; 43 } 44 AudioPolicyConfig(ArrayList<AudioMix> mixes)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 */ addMix(AudioMix mix)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 getMixes()62 public ArrayList<AudioMix> getMixes() { 63 return mMixes; 64 } 65 66 @Override hashCode()67 public int hashCode() { 68 return Objects.hash(mMixes); 69 } 70 71 @Override describeContents()72 public int describeContents() { 73 return 0; 74 } 75 76 @Override writeToParcel(Parcel dest, int flags)77 public void writeToParcel(Parcel dest, int flags) { 78 dest.writeInt(mMixes.size()); 79 for (AudioMix mix : mMixes) { 80 // write mix route flags 81 dest.writeInt(mix.getRouteFlags()); 82 // write callback flags 83 dest.writeInt(mix.mCallbackFlags); 84 // write mix format 85 dest.writeInt(mix.getFormat().getSampleRate()); 86 dest.writeInt(mix.getFormat().getEncoding()); 87 dest.writeInt(mix.getFormat().getChannelMask()); 88 // write mix rules 89 final ArrayList<AttributeMatchCriterion> criteria = mix.getRule().getCriteria(); 90 dest.writeInt(criteria.size()); 91 for (AttributeMatchCriterion criterion : criteria) { 92 criterion.writeToParcel(dest); 93 } 94 } 95 } 96 AudioPolicyConfig(Parcel in)97 private AudioPolicyConfig(Parcel in) { 98 mMixes = new ArrayList<AudioMix>(); 99 int nbMixes = in.readInt(); 100 for (int i = 0 ; i < nbMixes ; i++) { 101 final AudioMix.Builder mixBuilder = new AudioMix.Builder(); 102 // read mix route flags 103 int routeFlags = in.readInt(); 104 mixBuilder.setRouteFlags(routeFlags); 105 // read callback flags 106 mixBuilder.setCallbackFlags(in.readInt()); 107 // read mix format 108 int sampleRate = in.readInt(); 109 int encoding = in.readInt(); 110 int channelMask = in.readInt(); 111 final AudioFormat format = new AudioFormat.Builder().setSampleRate(sampleRate) 112 .setChannelMask(channelMask).setEncoding(encoding).build(); 113 mixBuilder.setFormat(format); 114 // read mix rules 115 int nbRules = in.readInt(); 116 AudioMixingRule.Builder ruleBuilder = new AudioMixingRule.Builder(); 117 for (int j = 0 ; j < nbRules ; j++) { 118 // read the matching rules 119 ruleBuilder.addRuleFromParcel(in); 120 } 121 mixBuilder.setMixingRule(ruleBuilder.build()); 122 mMixes.add(mixBuilder.build()); 123 } 124 } 125 126 public static final Parcelable.Creator<AudioPolicyConfig> CREATOR 127 = new Parcelable.Creator<AudioPolicyConfig>() { 128 /** 129 * Rebuilds an AudioPolicyConfig previously stored with writeToParcel(). 130 * @param p Parcel object to read the AudioPolicyConfig from 131 * @return a new AudioPolicyConfig created from the data in the parcel 132 */ 133 public AudioPolicyConfig createFromParcel(Parcel p) { 134 return new AudioPolicyConfig(p); 135 } 136 public AudioPolicyConfig[] newArray(int size) { 137 return new AudioPolicyConfig[size]; 138 } 139 }; 140 toLogFriendlyString()141 public String toLogFriendlyString () { 142 String textDump = new String("android.media.audiopolicy.AudioPolicyConfig:\n"); 143 textDump += mMixes.size() + " AudioMix: "+ mRegistrationId + "\n"; 144 for(AudioMix mix : mMixes) { 145 // write mix route flags 146 textDump += "* route flags=0x" + Integer.toHexString(mix.getRouteFlags()) + "\n"; 147 // write mix format 148 textDump += " rate=" + mix.getFormat().getSampleRate() + "Hz\n"; 149 textDump += " encoding=" + mix.getFormat().getEncoding() + "\n"; 150 textDump += " channels=0x"; 151 textDump += Integer.toHexString(mix.getFormat().getChannelMask()).toUpperCase() +"\n"; 152 // write mix rules 153 final ArrayList<AttributeMatchCriterion> criteria = mix.getRule().getCriteria(); 154 for (AttributeMatchCriterion criterion : criteria) { 155 switch(criterion.mRule) { 156 case AudioMixingRule.RULE_EXCLUDE_ATTRIBUTE_USAGE: 157 textDump += " exclude usage "; 158 textDump += criterion.mAttr.usageToString(); 159 break; 160 case AudioMixingRule.RULE_MATCH_ATTRIBUTE_USAGE: 161 textDump += " match usage "; 162 textDump += criterion.mAttr.usageToString(); 163 break; 164 case AudioMixingRule.RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET: 165 textDump += " exclude capture preset "; 166 textDump += criterion.mAttr.getCapturePreset(); 167 break; 168 case AudioMixingRule.RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET: 169 textDump += " match capture preset "; 170 textDump += criterion.mAttr.getCapturePreset(); 171 break; 172 default: 173 textDump += "invalid rule!"; 174 } 175 textDump += "\n"; 176 } 177 } 178 return textDump; 179 } 180 setRegistration(String regId)181 protected void setRegistration(String regId) { 182 final boolean currentRegNull = (mRegistrationId == null) || mRegistrationId.isEmpty(); 183 final boolean newRegNull = (regId == null) || regId.isEmpty(); 184 if (!currentRegNull && !newRegNull && !mRegistrationId.equals(regId)) { 185 Log.e(TAG, "Invalid registration transition from " + mRegistrationId + " to " + regId); 186 return; 187 } 188 mRegistrationId = regId == null ? "" : regId; 189 int mixIndex = 0; 190 for (AudioMix mix : mMixes) { 191 if (!mRegistrationId.isEmpty()) { 192 mix.setRegistration(mRegistrationId + "mix" + mixTypeId(mix.getMixType()) + ":" 193 + mixIndex++); 194 } else { 195 mix.setRegistration(""); 196 } 197 } 198 } 199 mixTypeId(int type)200 private static String mixTypeId(int type) { 201 if (type == AudioMix.MIX_TYPE_PLAYERS) return "p"; 202 else if (type == AudioMix.MIX_TYPE_RECORDERS) return "r"; 203 else return "i"; 204 } 205 getRegistration()206 protected String getRegistration() { 207 return mRegistrationId; 208 } 209 } 210