Home | History | Annotate | Download | only in audiopolicy
      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 
     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     public ArrayList<AudioMix> getMixes() {
     63         return mMixes;
     64     }
     65 
     66     @Override
     67     public int hashCode() {
     68         return Objects.hash(mMixes);
     69     }
     70 
     71     @Override
     72     public int describeContents() {
     73         return 0;
     74     }
     75 
     76     @Override
     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 
     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 
    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 
    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 
    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 
    206     protected String getRegistration() {
    207         return mRegistrationId;
    208     }
    209 }
    210