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