1 /* 2 * Copyright (C) 2018 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.annotation.NonNull; 20 import android.annotation.SystemApi; 21 import android.media.AudioAttributes; 22 import android.media.AudioSystem; 23 import android.os.Parcel; 24 import android.os.Parcelable; 25 import android.util.Log; 26 27 import com.android.internal.annotations.GuardedBy; 28 import com.android.internal.util.Preconditions; 29 30 import java.util.ArrayList; 31 import java.util.Arrays; 32 import java.util.List; 33 34 /** 35 * A class to create the association between different playback attributes 36 * (e.g. media, mapping direction) to a single volume control. 37 * @hide 38 */ 39 @SystemApi 40 public final class AudioVolumeGroup implements Parcelable { 41 private static final String TAG = "AudioVolumeGroup"; 42 /** 43 * Volume group value to use when introspection API fails. 44 */ 45 public static final int DEFAULT_VOLUME_GROUP = -1; 46 47 /** 48 * Unique identifier of a volume group. 49 */ 50 private int mId; 51 /** 52 * human-readable name of this volume group. 53 */ 54 private final String mName; 55 56 private final AudioAttributes[] mAudioAttributes; 57 private int[] mLegacyStreamTypes; 58 59 private static final Object sLock = new Object(); 60 61 @GuardedBy("sLock") 62 private static List<AudioVolumeGroup> sAudioVolumeGroups; 63 64 /** 65 * @hide 66 * @return the List of AudioVolumeGroup discovered from platform configuration file. 67 */ 68 @NonNull getAudioVolumeGroups()69 public static List<AudioVolumeGroup> getAudioVolumeGroups() { 70 if (sAudioVolumeGroups == null) { 71 synchronized (sLock) { 72 if (sAudioVolumeGroups == null) { 73 sAudioVolumeGroups = initializeAudioVolumeGroups(); 74 } 75 } 76 } 77 return sAudioVolumeGroups; 78 } 79 initializeAudioVolumeGroups()80 private static List<AudioVolumeGroup> initializeAudioVolumeGroups() { 81 ArrayList<AudioVolumeGroup> avgList = new ArrayList<>(); 82 int status = native_list_audio_volume_groups(avgList); 83 if (status != AudioSystem.SUCCESS) { 84 Log.w(TAG, ": listAudioVolumeGroups failed"); 85 } 86 return avgList; 87 } 88 native_list_audio_volume_groups( ArrayList<AudioVolumeGroup> groups)89 private static native int native_list_audio_volume_groups( 90 ArrayList<AudioVolumeGroup> groups); 91 92 /** 93 * @param name of the volume group 94 * @param id of the volume group 95 * @param legacyStreamTypes of volume group 96 */ AudioVolumeGroup(@onNull String name, int id, @NonNull AudioAttributes[] audioAttributes, @NonNull int[] legacyStreamTypes)97 AudioVolumeGroup(@NonNull String name, int id, 98 @NonNull AudioAttributes[] audioAttributes, 99 @NonNull int[] legacyStreamTypes) { 100 Preconditions.checkNotNull(name, "name must not be null"); 101 Preconditions.checkNotNull(audioAttributes, "audioAttributes must not be null"); 102 Preconditions.checkNotNull(legacyStreamTypes, "legacyStreamTypes must not be null"); 103 mName = name; 104 mId = id; 105 mAudioAttributes = audioAttributes; 106 mLegacyStreamTypes = legacyStreamTypes; 107 } 108 109 @Override equals(@onNull Object o)110 public boolean equals(@NonNull Object o) { 111 if (this == o) return true; 112 if (o == null || getClass() != o.getClass()) return false; 113 114 AudioVolumeGroup thatAvg = (AudioVolumeGroup) o; 115 116 return mName == thatAvg.mName && mId == thatAvg.mId 117 && mAudioAttributes.equals(thatAvg.mAudioAttributes); 118 } 119 120 /** 121 * @return List of {@link AudioAttributes} involved in this {@link AudioVolumeGroup}. 122 */ getAudioAttributes()123 public @NonNull List<AudioAttributes> getAudioAttributes() { 124 return Arrays.asList(mAudioAttributes); 125 } 126 127 /** 128 * @return the stream types involved in this {@link AudioVolumeGroup}. 129 */ getLegacyStreamTypes()130 public @NonNull int[] getLegacyStreamTypes() { 131 return mLegacyStreamTypes; 132 } 133 134 /** 135 * @return human-readable name of this volume group. 136 */ name()137 public @NonNull String name() { 138 return mName; 139 } 140 141 /** 142 * @return the volume group unique identifier id. 143 */ getId()144 public int getId() { 145 return mId; 146 } 147 148 @Override describeContents()149 public int describeContents() { 150 return 0; 151 } 152 153 @Override writeToParcel(@onNull Parcel dest, int flags)154 public void writeToParcel(@NonNull Parcel dest, int flags) { 155 dest.writeString(mName); 156 dest.writeInt(mId); 157 dest.writeInt(mAudioAttributes.length); 158 for (AudioAttributes attributes : mAudioAttributes) { 159 attributes.writeToParcel(dest, flags | AudioAttributes.FLATTEN_TAGS/*flags*/); 160 } 161 dest.writeInt(mLegacyStreamTypes.length); 162 for (int streamType : mLegacyStreamTypes) { 163 dest.writeInt(streamType); 164 } 165 } 166 167 public static final Parcelable.Creator<AudioVolumeGroup> CREATOR = 168 new Parcelable.Creator<AudioVolumeGroup>() { 169 @Override 170 public @NonNull AudioVolumeGroup createFromParcel(@NonNull Parcel in) { 171 Preconditions.checkNotNull(in, "in Parcel must not be null"); 172 String name = in.readString(); 173 int id = in.readInt(); 174 int nbAttributes = in.readInt(); 175 AudioAttributes[] audioAttributes = new AudioAttributes[nbAttributes]; 176 for (int index = 0; index < nbAttributes; index++) { 177 audioAttributes[index] = AudioAttributes.CREATOR.createFromParcel(in); 178 } 179 int nbStreamTypes = in.readInt(); 180 int[] streamTypes = new int[nbStreamTypes]; 181 for (int index = 0; index < nbStreamTypes; index++) { 182 streamTypes[index] = in.readInt(); 183 } 184 return new AudioVolumeGroup(name, id, audioAttributes, streamTypes); 185 } 186 187 @Override 188 public @NonNull AudioVolumeGroup[] newArray(int size) { 189 return new AudioVolumeGroup[size]; 190 } 191 }; 192 193 @Override toString()194 public @NonNull String toString() { 195 StringBuilder s = new StringBuilder(); 196 s.append("\n Name: "); 197 s.append(mName); 198 s.append(" Id: "); 199 s.append(Integer.toString(mId)); 200 201 s.append("\n Supported Audio Attributes:"); 202 for (AudioAttributes attribute : mAudioAttributes) { 203 s.append("\n -"); 204 s.append(attribute.toString()); 205 } 206 s.append("\n Supported Legacy Stream Types: { "); 207 for (int legacyStreamType : mLegacyStreamTypes) { 208 s.append(Integer.toString(legacyStreamType)); 209 s.append(" "); 210 } 211 s.append("}"); 212 return s.toString(); 213 } 214 } 215