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