1 /* 2 * Copyright (C) 2022 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 static com.google.common.collect.Sets.newHashSet; 22 23 import android.media.AudioAttributes; 24 import android.media.MediaRecorder; 25 import android.media.audiopolicy.AudioProductStrategy; 26 import android.media.audiopolicy.AudioVolumeGroup; 27 import android.os.Parcel; 28 29 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport; 30 31 import java.util.ArrayList; 32 import java.util.List; 33 34 @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE) 35 public final class CoreAudioRoutingUtils { 36 37 public static final int MUSIC_MIN_INDEX = 0; 38 public static final int MUSIC_MAX_INDEX = 40; 39 public static final int MUSIC_AM_INIT_INDEX = 8; 40 public static final int NAV_MIN_INDEX = 5; 41 public static final int NAV_MAX_INDEX = 35; 42 public static final int OEM_MIN_INDEX = 1; 43 public static final int OEM_MAX_INDEX = 15; 44 public static final int MUSIC_CAR_GROUP_ID = 0; 45 public static final int OEM_CAR_GROUP_ID = 2; 46 public static final int NAV_CAR_GROUP_ID = 1; 47 public static final String MUSIC_DEVICE_ADDRESS = "MUSIC_DEVICE_ADDRESS"; 48 public static final String NAV_DEVICE_ADDRESS = "NAV_DEVICE_ADDRESS"; 49 public static final String OEM_DEVICE_ADDRESS = "OEM_DEVICE_ADDRESS"; 50 public static final List<AudioVolumeGroup> VOLUME_GROUPS; 51 public static final List<AudioProductStrategy> PRODUCT_STRATEGIES; 52 53 public static final AudioAttributes MUSIC_ATTRIBUTES = new AudioAttributes.Builder() 54 .setUsage(AudioAttributes.USAGE_MEDIA) 55 .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) 56 .build(); 57 58 public static final AudioAttributes MOVIE_ATTRIBUTES = new AudioAttributes.Builder() 59 .setContentType(AudioAttributes.CONTENT_TYPE_MOVIE) 60 .build(); 61 public static final int MUSIC_STRATEGY_ID = 777; 62 public static final String MUSIC_CONTEXT_NAME = "MUSIC_CONTEXT"; 63 public static final int MUSIC_GROUP_ID = 666; 64 public static final String MUSIC_GROUP_NAME = "MUSIC_GROUP"; 65 public static final AudioProductStrategy MUSIC_STRATEGY; 66 public static final AudioVolumeGroup MUSIC_GROUP; 67 public static final CarAudioContextInfo MEDIA_CONTEXT_INFO; 68 69 public static final AudioAttributes NAV_ATTRIBUTES = new AudioAttributes.Builder() 70 .setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE) 71 .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) 72 .build(); 73 public static final int NAV_STRATEGY_ID = 99; 74 public static final String NAV_CONTEXT_NAME = "NAV_CONTEXT"; 75 public static final int NAV_GROUP_ID = 8; 76 public static final String NAV_GROUP_NAME = "NAV_GROUP"; 77 public static final AudioProductStrategy NAV_STRATEGY; 78 public static final AudioVolumeGroup NAV_GROUP; 79 public static final CarAudioContextInfo NAV_CONTEXT_INFO; 80 81 public static final AudioAttributes OEM_ATTRIBUTES; 82 public static final int OEM_STRATEGY_ID = 1979; 83 public static final String OEM_CONTEXT_NAME = "OEM_CONTEXT"; 84 public static final int OEM_GROUP_ID = 55; 85 public static final String OEM_GROUP_NAME = "OEM_GROUP"; 86 public static final String OEM_FORMATTED_TAGS = "oem=extension_1979"; 87 public static final AudioProductStrategy OEM_STRATEGY; 88 public static final AudioVolumeGroup OEM_GROUP; 89 public static final CarAudioContextInfo OEM_CONTEXT_INFO; 90 91 static final String INVALID_CONTEXT_NAME = "INVALID_CONTEXT"; 92 static final int INVALID_STRATEGY_ID = 999999; 93 static final int INVALID_GROUP_ID = 999999; 94 static final String INVALID_GROUP_NAME = "INVALID_GROUP"; 95 96 static final int INVALID_STRATEGY = -1; 97 98 static final AudioAttributes UNSUPPORTED_ATTRIBUTES = new AudioAttributes.Builder() 99 .setUsage(AudioAttributes.USAGE_GAME) 100 .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) 101 .build(); 102 103 static { 104 OEM_ATTRIBUTES = new AudioAttributes.Builder() 105 .setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE) 106 .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) 107 .replaceTags(newHashSet(OEM_FORMATTED_TAGS)) 108 .build(); 109 // Note: constructors are private, use marshalling public API to generate the mocks 110 Parcel parcel = Parcel.obtain(); 111 // marshall AudioProductStrategy data 112 parcel.writeString(MUSIC_CONTEXT_NAME); 113 parcel.writeInt(MUSIC_STRATEGY_ID); 114 115 // nb attributes groups 116 parcel.writeInt(1); 117 parcel.writeInt(MUSIC_GROUP_ID); 118 // stream type 119 parcel.writeInt(0); 120 // nb attributes 121 parcel.writeInt(2); 122 123 parcel.writeInt(AudioAttributes.USAGE_MEDIA); 124 parcel.writeInt(AudioAttributes.CONTENT_TYPE_MUSIC); 125 parcel.writeInt(MediaRecorder.AudioSource.AUDIO_SOURCE_INVALID); 126 parcel.writeInt(AudioAttributes.FLAG_MUTE_HAPTIC); 127 parcel.writeInt(AudioAttributes.FLATTEN_TAGS); 128 // mFormattedTags 129 parcel.writeString(""); 130 // ATTR_PARCEL_IS_NULL_BUNDLE 131 parcel.writeInt(-1977); 132 133 parcel.writeInt(AudioAttributes.USAGE_UNKNOWN); 134 parcel.writeInt(AudioAttributes.CONTENT_TYPE_UNKNOWN); 135 parcel.writeInt(MediaRecorder.AudioSource.AUDIO_SOURCE_INVALID); 136 parcel.writeInt(AudioAttributes.FLAG_MUTE_HAPTIC); 137 parcel.writeInt(AudioAttributes.FLATTEN_TAGS); 138 // mFormattedTags 139 parcel.writeString(""); 140 // ATTR_PARCEL_IS_NULL_BUNDLE 141 parcel.writeInt(-1977); 142 143 parcel.setDataPosition(0); 144 MUSIC_STRATEGY = AudioProductStrategy.CREATOR.createFromParcel(parcel); parcel.recycle()145 parcel.recycle(); 146 147 parcel = Parcel.obtain(); 148 // marshall AudioProductStrategy data 149 parcel.writeString(NAV_CONTEXT_NAME); 150 parcel.writeInt(NAV_STRATEGY_ID); 151 152 // nb attributes groups 153 parcel.writeInt(1); 154 parcel.writeInt(NAV_GROUP_ID); 155 // stream type 156 parcel.writeInt(0); 157 // nb attributes 158 parcel.writeInt(2); 159 160 parcel.writeInt(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE); 161 parcel.writeInt(AudioAttributes.CONTENT_TYPE_SPEECH); 162 parcel.writeInt(MediaRecorder.AudioSource.AUDIO_SOURCE_INVALID); 163 parcel.writeInt(AudioAttributes.FLAG_MUTE_HAPTIC); 164 parcel.writeInt(AudioAttributes.FLATTEN_TAGS); 165 // mFormattedTags 166 parcel.writeString(""); 167 // ATTR_PARCEL_IS_NULL_BUNDLE 168 parcel.writeInt(-1977); 169 170 parcel.writeInt(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE); 171 parcel.writeInt(AudioAttributes.CONTENT_TYPE_UNKNOWN); 172 parcel.writeInt(MediaRecorder.AudioSource.AUDIO_SOURCE_INVALID); 173 parcel.writeInt(AudioAttributes.FLAG_MUTE_HAPTIC); 174 parcel.writeInt(AudioAttributes.FLATTEN_TAGS); 175 // mFormattedTags 176 parcel.writeString(""); 177 // ATTR_PARCEL_IS_NULL_BUNDLE 178 parcel.writeInt(-1977); 179 180 parcel.setDataPosition(0); 181 NAV_STRATEGY = AudioProductStrategy.CREATOR.createFromParcel(parcel); parcel.recycle()182 parcel.recycle(); 183 184 parcel = Parcel.obtain(); 185 // marshall AudioProductStrategy data 186 parcel.writeString(OEM_CONTEXT_NAME); 187 parcel.writeInt(OEM_STRATEGY_ID); 188 189 // nb attributes groups 190 parcel.writeInt(1); 191 parcel.writeInt(OEM_GROUP_ID); 192 // stream type 193 parcel.writeInt(0); 194 // nb attributes 195 parcel.writeInt(1); 196 parcel.writeInt(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE); 197 parcel.writeInt(AudioAttributes.CONTENT_TYPE_SPEECH); 198 parcel.writeInt(MediaRecorder.AudioSource.AUDIO_SOURCE_INVALID); 199 parcel.writeInt(AudioAttributes.FLAG_MUTE_HAPTIC); 200 parcel.writeInt(AudioAttributes.FLATTEN_TAGS); 201 parcel.writeString(OEM_FORMATTED_TAGS); 202 // ATTR_PARCEL_IS_NULL_BUNDLE 203 parcel.writeInt(-1977); 204 205 parcel.setDataPosition(0); 206 OEM_STRATEGY = AudioProductStrategy.CREATOR.createFromParcel(parcel); parcel.recycle()207 parcel.recycle(); 208 209 // Order matters, put the default in the middle to check default strategy is not selected 210 // if not explicitly requested. 211 PRODUCT_STRATEGIES = List.of(OEM_STRATEGY, MUSIC_STRATEGY, NAV_STRATEGY); 212 213 parcel = Parcel.obtain(); 214 // marshall AudioVolumeGroup data 215 parcel.writeString(MUSIC_GROUP_NAME); 216 parcel.writeInt(MUSIC_GROUP_ID); 217 218 // nb attributes 219 parcel.writeInt(2); 220 parcel.writeInt(AudioAttributes.USAGE_MEDIA); 221 parcel.writeInt(AudioAttributes.CONTENT_TYPE_MUSIC); 222 parcel.writeInt(MediaRecorder.AudioSource.AUDIO_SOURCE_INVALID); 223 parcel.writeInt(AudioAttributes.FLAG_MUTE_HAPTIC); 224 parcel.writeInt(AudioAttributes.FLATTEN_TAGS); 225 // mFormattedTags 226 parcel.writeString(""); 227 // ATTR_PARCEL_IS_NULL_BUNDLE 228 parcel.writeInt(-1977); 229 230 parcel.writeInt(AudioAttributes.USAGE_UNKNOWN); 231 parcel.writeInt(AudioAttributes.CONTENT_TYPE_UNKNOWN); 232 parcel.writeInt(MediaRecorder.AudioSource.AUDIO_SOURCE_INVALID); 233 parcel.writeInt(AudioAttributes.FLAG_MUTE_HAPTIC); 234 parcel.writeInt(AudioAttributes.FLATTEN_TAGS); 235 // mFormattedTags 236 parcel.writeString(""); 237 // ATTR_PARCEL_IS_NULL_BUNDLE 238 parcel.writeInt(-1977); 239 240 // nb stream types 241 parcel.writeInt(0); 242 243 parcel.setDataPosition(0); 244 MUSIC_GROUP = AudioVolumeGroup.CREATOR.createFromParcel(parcel); parcel.recycle()245 parcel.recycle(); 246 247 parcel = Parcel.obtain(); 248 // marshall AudioProductStrategy data 249 parcel.writeString(NAV_GROUP_NAME); 250 parcel.writeInt(NAV_GROUP_ID); 251 252 // nb attributes 253 parcel.writeInt(1); 254 parcel.writeInt(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE); 255 parcel.writeInt(AudioAttributes.CONTENT_TYPE_SPEECH); 256 parcel.writeInt(MediaRecorder.AudioSource.AUDIO_SOURCE_INVALID); 257 parcel.writeInt(AudioAttributes.FLAG_MUTE_HAPTIC); 258 parcel.writeInt(AudioAttributes.FLATTEN_TAGS); 259 // mFormattedTags 260 parcel.writeString(""); 261 // ATTR_PARCEL_IS_NULL_BUNDLE 262 parcel.writeInt(-1977); 263 264 parcel.writeInt(/* nb stream types= */ 0); 265 266 parcel.setDataPosition(0); 267 NAV_GROUP = AudioVolumeGroup.CREATOR.createFromParcel(parcel); parcel.recycle()268 parcel.recycle(); 269 270 parcel = Parcel.obtain(); 271 // marshall AudioProductStrategy data 272 parcel.writeString(OEM_GROUP_NAME); 273 parcel.writeInt(OEM_GROUP_ID); 274 275 // nb attributes 276 parcel.writeInt(1); 277 parcel.writeInt(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE); 278 parcel.writeInt(AudioAttributes.CONTENT_TYPE_SPEECH); 279 parcel.writeInt(MediaRecorder.AudioSource.AUDIO_SOURCE_INVALID); 280 parcel.writeInt(AudioAttributes.FLAG_MUTE_HAPTIC); 281 parcel.writeInt(AudioAttributes.FLATTEN_TAGS); 282 // mFormattedTags 283 parcel.writeString("oem=extension_1979"); 284 // ATTR_PARCEL_IS_NULL_BUNDLE 285 parcel.writeInt(-1977); 286 287 // nb stream types 288 parcel.writeInt(0); 289 290 parcel.setDataPosition(0); 291 OEM_GROUP = AudioVolumeGroup.CREATOR.createFromParcel(parcel); parcel.recycle()292 parcel.recycle(); 293 294 VOLUME_GROUPS = List.of(MUSIC_GROUP, NAV_GROUP, OEM_GROUP); 295 296 AudioAttributes[] oemAttributesArray = { OEM_ATTRIBUTES }; 297 AudioAttributes[] musicAttributesArray = { MUSIC_ATTRIBUTES, MOVIE_ATTRIBUTES }; 298 AudioAttributes[] navAttributesArray = { NAV_ATTRIBUTES }; 299 300 MEDIA_CONTEXT_INFO = new CarAudioContextInfo(musicAttributesArray, MUSIC_CONTEXT_NAME, 301 MUSIC_STRATEGY_ID); 302 NAV_CONTEXT_INFO = new CarAudioContextInfo(navAttributesArray, NAV_CONTEXT_NAME, 303 NAV_STRATEGY_ID); 304 OEM_CONTEXT_INFO = new CarAudioContextInfo(oemAttributesArray, OEM_CONTEXT_NAME, 305 OEM_STRATEGY_ID); 306 } 307 CoreAudioRoutingUtils()308 private CoreAudioRoutingUtils() { 309 throw new UnsupportedOperationException("CoreAudioRoutingUtils class is non instantiable"); 310 } 311 getVolumeGroups()312 public static List<AudioVolumeGroup> getVolumeGroups() { 313 return VOLUME_GROUPS; 314 } 315 getProductStrategies()316 public static List<AudioProductStrategy> getProductStrategies() { 317 return PRODUCT_STRATEGIES; 318 } 319 getCarAudioContextInfos()320 public static List<CarAudioContextInfo> getCarAudioContextInfos() { 321 List<CarAudioContextInfo> carAudioContextInfos = new ArrayList<>(3); 322 323 carAudioContextInfos.add(MEDIA_CONTEXT_INFO); 324 carAudioContextInfos.add(NAV_CONTEXT_INFO); 325 carAudioContextInfos.add(OEM_CONTEXT_INFO); 326 327 return carAudioContextInfos; 328 } 329 } 330