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.AudioAttributes;
     20 import android.media.AudioFormat;
     21 import android.media.AudioManager;
     22 import android.media.audiopolicy.AudioMixingRule.AttributeMatchCriterion;
     23 import android.os.Binder;
     24 import android.os.IBinder;
     25 import android.os.Parcel;
     26 import android.os.Parcelable;
     27 import android.util.Log;
     28 
     29 import java.util.ArrayList;
     30 import java.util.Objects;
     31 
     32 /**
     33  * @hide
     34  * Internal storage class for AudioPolicy configuration.
     35  */
     36 public class AudioPolicyConfig implements Parcelable {
     37 
     38     private static final String TAG = "AudioPolicyConfig";
     39 
     40     protected ArrayList<AudioMix> mMixes;
     41     protected int mDuckingPolicy = AudioPolicy.FOCUS_POLICY_DUCKING_IN_APP;
     42 
     43     private String mRegistrationId = null;
     44 
     45     protected AudioPolicyConfig(AudioPolicyConfig conf) {
     46         mMixes = conf.mMixes;
     47     }
     48 
     49     AudioPolicyConfig(ArrayList<AudioMix> mixes) {
     50         mMixes = mixes;
     51     }
     52 
     53     /**
     54      * Add an {@link AudioMix} to be part of the audio policy being built.
     55      * @param mix a non-null {@link AudioMix} to be part of the audio policy.
     56      * @return the same Builder instance.
     57      * @throws IllegalArgumentException
     58      */
     59     public void addMix(AudioMix mix) throws IllegalArgumentException {
     60         if (mix == null) {
     61             throw new IllegalArgumentException("Illegal null AudioMix argument");
     62         }
     63         mMixes.add(mix);
     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 mix format
     83             dest.writeInt(mix.getFormat().getSampleRate());
     84             dest.writeInt(mix.getFormat().getEncoding());
     85             dest.writeInt(mix.getFormat().getChannelMask());
     86             // write mix rules
     87             final ArrayList<AttributeMatchCriterion> criteria = mix.getRule().getCriteria();
     88             dest.writeInt(criteria.size());
     89             for (AttributeMatchCriterion criterion : criteria) {
     90                 criterion.writeToParcel(dest);
     91             }
     92         }
     93     }
     94 
     95     private AudioPolicyConfig(Parcel in) {
     96         mMixes = new ArrayList<AudioMix>();
     97         int nbMixes = in.readInt();
     98         for (int i = 0 ; i < nbMixes ; i++) {
     99             final AudioMix.Builder mixBuilder = new AudioMix.Builder();
    100             // read mix route flags
    101             int routeFlags = in.readInt();
    102             mixBuilder.setRouteFlags(routeFlags);
    103             // read mix format
    104             int sampleRate = in.readInt();
    105             int encoding = in.readInt();
    106             int channelMask = in.readInt();
    107             final AudioFormat format = new AudioFormat.Builder().setSampleRate(sampleRate)
    108                     .setChannelMask(channelMask).setEncoding(encoding).build();
    109             mixBuilder.setFormat(format);
    110             // read mix rules
    111             int nbRules = in.readInt();
    112             AudioMixingRule.Builder ruleBuilder = new AudioMixingRule.Builder();
    113             for (int j = 0 ; j < nbRules ; j++) {
    114                 // read the matching rules
    115                 ruleBuilder.addRuleFromParcel(in);
    116             }
    117             mixBuilder.setMixingRule(ruleBuilder.build());
    118             mMixes.add(mixBuilder.build());
    119         }
    120     }
    121 
    122     public static final Parcelable.Creator<AudioPolicyConfig> CREATOR
    123             = new Parcelable.Creator<AudioPolicyConfig>() {
    124         /**
    125          * Rebuilds an AudioPolicyConfig previously stored with writeToParcel().
    126          * @param p Parcel object to read the AudioPolicyConfig from
    127          * @return a new AudioPolicyConfig created from the data in the parcel
    128          */
    129         public AudioPolicyConfig createFromParcel(Parcel p) {
    130             return new AudioPolicyConfig(p);
    131         }
    132         public AudioPolicyConfig[] newArray(int size) {
    133             return new AudioPolicyConfig[size];
    134         }
    135     };
    136 
    137     public String toLogFriendlyString () {
    138         String textDump = new String("android.media.audiopolicy.AudioPolicyConfig:\n");
    139         textDump += mMixes.size() + " AudioMix: "+ mRegistrationId + "\n";
    140         for(AudioMix mix : mMixes) {
    141             // write mix route flags
    142             textDump += "* route flags=0x" + Integer.toHexString(mix.getRouteFlags()) + "\n";
    143             // write mix format
    144             textDump += "  rate=" + mix.getFormat().getSampleRate() + "Hz\n";
    145             textDump += "  encoding=" + mix.getFormat().getEncoding() + "\n";
    146             textDump += "  channels=0x";
    147             textDump += Integer.toHexString(mix.getFormat().getChannelMask()).toUpperCase() +"\n";
    148             // write mix rules
    149             final ArrayList<AttributeMatchCriterion> criteria = mix.getRule().getCriteria();
    150             for (AttributeMatchCriterion criterion : criteria) {
    151                 switch(criterion.mRule) {
    152                     case AudioMixingRule.RULE_EXCLUDE_ATTRIBUTE_USAGE:
    153                         textDump += "  exclude usage ";
    154                         textDump += criterion.mAttr.usageToString();
    155                         break;
    156                     case AudioMixingRule.RULE_MATCH_ATTRIBUTE_USAGE:
    157                         textDump += "  match usage ";
    158                         textDump += criterion.mAttr.usageToString();
    159                         break;
    160                     case AudioMixingRule.RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET:
    161                         textDump += "  exclude capture preset ";
    162                         textDump += criterion.mAttr.getCapturePreset();
    163                         break;
    164                     case AudioMixingRule.RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
    165                         textDump += "  match capture preset ";
    166                         textDump += criterion.mAttr.getCapturePreset();
    167                         break;
    168                     default:
    169                         textDump += "invalid rule!";
    170                 }
    171                 textDump += "\n";
    172             }
    173         }
    174         return textDump;
    175     }
    176 
    177     protected void setRegistration(String regId) {
    178         final boolean currentRegNull = (mRegistrationId == null) || mRegistrationId.isEmpty();
    179         final boolean newRegNull = (regId == null) || regId.isEmpty();
    180         if (!currentRegNull && !newRegNull && !mRegistrationId.equals(regId)) {
    181             Log.e(TAG, "Invalid registration transition from " + mRegistrationId + " to " + regId);
    182             return;
    183         }
    184         mRegistrationId = regId == null ? "" : regId;
    185         int mixIndex = 0;
    186         for (AudioMix mix : mMixes) {
    187             if (!mRegistrationId.isEmpty()) {
    188                 mix.setRegistration(mRegistrationId + "mix" + mixTypeId(mix.getMixType()) + ":"
    189                         + mixIndex++);
    190             } else {
    191                 mix.setRegistration("");
    192             }
    193         }
    194     }
    195 
    196     private static String mixTypeId(int type) {
    197         if (type == AudioMix.MIX_TYPE_PLAYERS) return "p";
    198         else if (type == AudioMix.MIX_TYPE_RECORDERS) return "r";
    199         else return "i";
    200     }
    201 
    202     protected String getRegistration() {
    203         return mRegistrationId;
    204     }
    205 }
    206