• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 com.android.car.audio;
18 
19 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
20 
21 import android.annotation.IntDef;
22 import android.media.AudioAttributes;
23 import android.media.AudioAttributes.AttributeUsage;
24 import android.util.SparseArray;
25 import android.util.SparseIntArray;
26 
27 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
28 import com.android.internal.util.Preconditions;
29 
30 import java.lang.annotation.Retention;
31 import java.lang.annotation.RetentionPolicy;
32 import java.util.Arrays;
33 import java.util.HashSet;
34 import java.util.Set;
35 
36 /**
37  * Groupings of {@link AttributeUsage}s to simplify configuration of car audio routing, volume
38  * groups, and focus interactions for similar usages.
39  */
40 public final class CarAudioContext {
41     /*
42      * Shouldn't be used
43      * ::android::hardware::automotive::audiocontrol::V1_0::ContextNumber.INVALID
44      */
45     static final int INVALID = 0;
46     /*
47      * Music playback
48      * ::android::hardware::automotive::audiocontrol::V1_0::ContextNumber.INVALID implicitly + 1
49      */
50     static final int MUSIC = 1;
51     /*
52      * Navigation directions
53      * ::android::hardware::automotive::audiocontrol::V1_0::ContextNumber.MUSIC implicitly + 1
54      */
55     static final int NAVIGATION = 2;
56     /*
57      * Voice command session
58      * ::android::hardware::automotive::audiocontrol::V1_0::ContextNumber.NAVIGATION implicitly + 1
59      */
60     static final int VOICE_COMMAND = 3;
61     /*
62      * Voice call ringing
63      * ::android::hardware::automotive::audiocontrol::V1_0::ContextNumber
64      *     .VOICE_COMMAND implicitly + 1
65      */
66     static final int CALL_RING = 4;
67     /*
68      * Voice call
69      * ::android::hardware::automotive::audiocontrol::V1_0::ContextNumber.CALL_RING implicitly + 1
70      */
71     static final int CALL = 5;
72     /*
73      * Alarm sound from Android
74      * ::android::hardware::automotive::audiocontrol::V1_0::ContextNumber.CALL implicitly + 1
75      */
76     static final int ALARM = 6;
77     /*
78      * Notifications
79      * ::android::hardware::automotive::audiocontrol::V1_0::ContextNumber.ALARM implicitly + 1
80      */
81     static final int NOTIFICATION = 7;
82     /*
83      * System sounds
84      * ::android::hardware::automotive::audiocontrol::V1_0::ContextNumber
85      *     .NOTIFICATION implicitly + 1
86      */
87     static final int SYSTEM_SOUND = 8;
88     /*
89      * Emergency related sounds such as collision warnings
90      */
91     static final int EMERGENCY = 9;
92     /*
93      * Safety sounds such as obstacle detection when backing up or when changing lanes
94      */
95     static final int SAFETY = 10;
96     /*
97      * Vehicle Status related sounds such as check engine light or seat belt chimes
98      */
99     static final int VEHICLE_STATUS = 11;
100     /*
101      * Announcement such as traffic announcements
102      */
103     static final int ANNOUNCEMENT = 12;
104 
105     static final int[] CONTEXTS = {
106             MUSIC,
107             NAVIGATION,
108             VOICE_COMMAND,
109             CALL_RING,
110             CALL,
111             ALARM,
112             NOTIFICATION,
113             SYSTEM_SOUND,
114             EMERGENCY,
115             SAFETY,
116             VEHICLE_STATUS,
117             ANNOUNCEMENT
118     };
119 
120     private static final SparseArray<String> CONTEXT_NAMES = new SparseArray<>(CONTEXTS.length + 1);
121     static {
CONTEXT_NAMES.append(INVALID, "INVALID")122         CONTEXT_NAMES.append(INVALID, "INVALID");
CONTEXT_NAMES.append(MUSIC, "MUSIC")123         CONTEXT_NAMES.append(MUSIC, "MUSIC");
CONTEXT_NAMES.append(NAVIGATION, "NAVIGATION")124         CONTEXT_NAMES.append(NAVIGATION, "NAVIGATION");
CONTEXT_NAMES.append(VOICE_COMMAND, "VOICE_COMMAND")125         CONTEXT_NAMES.append(VOICE_COMMAND, "VOICE_COMMAND");
CONTEXT_NAMES.append(CALL_RING, "CALL_RING")126         CONTEXT_NAMES.append(CALL_RING, "CALL_RING");
CONTEXT_NAMES.append(CALL, "CALL")127         CONTEXT_NAMES.append(CALL, "CALL");
CONTEXT_NAMES.append(ALARM, "ALARM")128         CONTEXT_NAMES.append(ALARM, "ALARM");
CONTEXT_NAMES.append(NOTIFICATION, "NOTIFICATION")129         CONTEXT_NAMES.append(NOTIFICATION, "NOTIFICATION");
CONTEXT_NAMES.append(SYSTEM_SOUND, "SYSTEM_SOUND")130         CONTEXT_NAMES.append(SYSTEM_SOUND, "SYSTEM_SOUND");
CONTEXT_NAMES.append(EMERGENCY, "EMERGENCY")131         CONTEXT_NAMES.append(EMERGENCY, "EMERGENCY");
CONTEXT_NAMES.append(SAFETY, "SAFETY")132         CONTEXT_NAMES.append(SAFETY, "SAFETY");
CONTEXT_NAMES.append(VEHICLE_STATUS, "VEHICLE_STATUS")133         CONTEXT_NAMES.append(VEHICLE_STATUS, "VEHICLE_STATUS");
CONTEXT_NAMES.append(ANNOUNCEMENT, "ANNOUNCEMENT")134         CONTEXT_NAMES.append(ANNOUNCEMENT, "ANNOUNCEMENT");
135     }
136 
137     private static final SparseArray<int[]> CONTEXT_TO_USAGES = new SparseArray<>();
138 
139     static {
CONTEXT_TO_USAGES.put(MUSIC, new int[]{ AudioAttributes.USAGE_UNKNOWN, AudioAttributes.USAGE_GAME, AudioAttributes.USAGE_MEDIA })140         CONTEXT_TO_USAGES.put(MUSIC,
141                 new int[]{
142                         AudioAttributes.USAGE_UNKNOWN,
143                         AudioAttributes.USAGE_GAME,
144                         AudioAttributes.USAGE_MEDIA
145                 });
146 
CONTEXT_TO_USAGES.put(NAVIGATION, new int[]{ AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE })147         CONTEXT_TO_USAGES.put(NAVIGATION,
148                 new int[]{
149                         AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE
150                 });
151 
CONTEXT_TO_USAGES.put(VOICE_COMMAND, new int[]{ AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY, AudioAttributes.USAGE_ASSISTANT })152         CONTEXT_TO_USAGES.put(VOICE_COMMAND,
153                 new int[]{
154                         AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY,
155                         AudioAttributes.USAGE_ASSISTANT
156                 });
157 
CONTEXT_TO_USAGES.put(CALL_RING, new int[]{ AudioAttributes.USAGE_NOTIFICATION_RINGTONE })158         CONTEXT_TO_USAGES.put(CALL_RING,
159                 new int[]{
160                         AudioAttributes.USAGE_NOTIFICATION_RINGTONE
161                 });
162 
CONTEXT_TO_USAGES.put(CALL, new int[]{ AudioAttributes.USAGE_VOICE_COMMUNICATION, AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING })163         CONTEXT_TO_USAGES.put(CALL,
164                 new int[]{
165                         AudioAttributes.USAGE_VOICE_COMMUNICATION,
166                         AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING
167                 });
168 
CONTEXT_TO_USAGES.put(ALARM, new int[]{ AudioAttributes.USAGE_ALARM })169         CONTEXT_TO_USAGES.put(ALARM,
170                 new int[]{
171                         AudioAttributes.USAGE_ALARM
172                 });
173 
CONTEXT_TO_USAGES.put(NOTIFICATION, new int[]{ AudioAttributes.USAGE_NOTIFICATION, AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST, AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT, AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED, AudioAttributes.USAGE_NOTIFICATION_EVENT })174         CONTEXT_TO_USAGES.put(NOTIFICATION,
175                 new int[]{
176                         AudioAttributes.USAGE_NOTIFICATION,
177                         AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST,
178                         AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT,
179                         AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED,
180                         AudioAttributes.USAGE_NOTIFICATION_EVENT
181                 });
182 
CONTEXT_TO_USAGES.put(SYSTEM_SOUND, new int[]{ AudioAttributes.USAGE_ASSISTANCE_SONIFICATION })183         CONTEXT_TO_USAGES.put(SYSTEM_SOUND,
184                 new int[]{
185                         AudioAttributes.USAGE_ASSISTANCE_SONIFICATION
186                 });
187 
CONTEXT_TO_USAGES.put(EMERGENCY, new int[]{ AudioAttributes.USAGE_EMERGENCY })188         CONTEXT_TO_USAGES.put(EMERGENCY,
189                 new int[]{
190                         AudioAttributes.USAGE_EMERGENCY
191                 });
192 
CONTEXT_TO_USAGES.put(SAFETY, new int[]{ AudioAttributes.USAGE_SAFETY })193         CONTEXT_TO_USAGES.put(SAFETY,
194                 new int[]{
195                         AudioAttributes.USAGE_SAFETY
196                 });
197 
CONTEXT_TO_USAGES.put(VEHICLE_STATUS, new int[]{ AudioAttributes.USAGE_VEHICLE_STATUS })198         CONTEXT_TO_USAGES.put(VEHICLE_STATUS,
199                 new int[]{
200                         AudioAttributes.USAGE_VEHICLE_STATUS
201                 });
202 
CONTEXT_TO_USAGES.put(ANNOUNCEMENT, new int[]{ AudioAttributes.USAGE_ANNOUNCEMENT })203         CONTEXT_TO_USAGES.put(ANNOUNCEMENT,
204                 new int[]{
205                         AudioAttributes.USAGE_ANNOUNCEMENT
206                 });
207 
CONTEXT_TO_USAGES.put(INVALID, new int[]{ AudioAttributes.USAGE_VIRTUAL_SOURCE })208         CONTEXT_TO_USAGES.put(INVALID,
209                 new int[]{
210                         AudioAttributes.USAGE_VIRTUAL_SOURCE
211                 });
212     }
213 
214     private static final SparseIntArray USAGE_TO_CONTEXT = new SparseIntArray();
215 
216     static {
217         for (int i = 0; i < CONTEXT_TO_USAGES.size(); i++) {
218             @AudioContext int audioContext = CONTEXT_TO_USAGES.keyAt(i);
219             @AttributeUsage int[] usages = CONTEXT_TO_USAGES.valueAt(i);
220             for (@AttributeUsage int usage : usages) {
USAGE_TO_CONTEXT.put(usage, audioContext)221                 USAGE_TO_CONTEXT.put(usage, audioContext);
222             }
223         }
224     }
225 
CarAudioContext()226     private CarAudioContext() {
227     }
228 
229     /**
230      * Checks if the audio context is within the valid range from MUSIC to SYSTEM_SOUND
231      */
preconditionCheckAudioContext(@udioContext int audioContext)232     static void preconditionCheckAudioContext(@AudioContext int audioContext) {
233         Preconditions.checkArgument(Arrays.binarySearch(CONTEXTS, audioContext) >= 0,
234                 "audioContext %d is invalid", audioContext);
235     }
236 
getUsagesForContext(@udioContext int carAudioContext)237     static @AttributeUsage int[] getUsagesForContext(@AudioContext int carAudioContext) {
238         preconditionCheckAudioContext(carAudioContext);
239         return CONTEXT_TO_USAGES.get(carAudioContext);
240     }
241 
getContextForAttributes(AudioAttributes attributes)242     static @AudioContext int getContextForAttributes(AudioAttributes attributes) {
243         return getContextForUsage(attributes.getSystemUsage());
244     }
245 
246     /**
247      * @return Context number for a given audio usage, {@code INVALID} if the given usage is
248      * unrecognized.
249      */
getContextForUsage(@ttributeUsage int audioUsage)250     static @AudioContext int getContextForUsage(@AttributeUsage int audioUsage) {
251         return USAGE_TO_CONTEXT.get(audioUsage, INVALID);
252     }
253 
getUniqueContextsForUsages(int[] usages)254     static Set<Integer> getUniqueContextsForUsages(int[] usages) {
255         Set<Integer> uniqueContexts = new HashSet<>();
256         for (int i = 0; i < usages.length; i++) {
257             uniqueContexts.add(getContextForUsage(usages[i]));
258         }
259 
260         return uniqueContexts;
261     }
262 
isCriticalAudioContext(@arAudioContext.AudioContext int audioContext)263     static boolean isCriticalAudioContext(@CarAudioContext.AudioContext int audioContext) {
264         return CarAudioContext.EMERGENCY == audioContext || CarAudioContext.SAFETY == audioContext;
265     }
266 
267     @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
toString(@udioContext int audioContext)268     static String toString(@AudioContext int audioContext) {
269         String name = CONTEXT_NAMES.get(audioContext);
270         if (name != null) {
271             return name;
272         }
273         return "Unsupported Context 0x" + Integer.toHexString(audioContext);
274     }
275 
276     @IntDef({
277             INVALID,
278             MUSIC,
279             NAVIGATION,
280             VOICE_COMMAND,
281             CALL_RING,
282             CALL,
283             ALARM,
284             NOTIFICATION,
285             SYSTEM_SOUND,
286             EMERGENCY,
287             SAFETY,
288             VEHICLE_STATUS,
289             ANNOUNCEMENT
290     })
291     @Retention(RetentionPolicy.SOURCE)
292     public @interface AudioContext {
293     }
294 };
295