1 /* 2 * Copyright (C) 2015 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 package com.android.car; 17 18 import android.car.media.CarAudioManager; 19 import android.content.Context; 20 import android.content.res.Resources; 21 import android.media.AudioAttributes; 22 import android.util.Log; 23 24 import java.io.PrintWriter; 25 import java.util.Arrays; 26 27 /** 28 * Holds audio routing policy from config.xml. R.array.audioRoutingPolicy can contain 29 * multiple policies and VEHICLE_PROPERTY_AUDIO_HW_VARIANT decide which one to use. 30 */ 31 public class AudioRoutingPolicy { 32 33 private final int USAGE_TYPE_INVALID = -1; 34 35 /** Physical stream to logical streams mapping */ 36 private final int[][] mLogicalStreams; 37 /** Logical stream to physical stream mapping */ 38 private final int[] mPhysicalStreamForLogicalStream; 39 create(Context context, int policyNumber)40 public static AudioRoutingPolicy create(Context context, int policyNumber) { 41 final Resources res = context.getResources(); 42 String[] policies = res.getStringArray(R.array.audioRoutingPolicy); 43 return new AudioRoutingPolicy(policies[policyNumber]); 44 } 45 getStreamType(String str)46 private static int getStreamType(String str) { 47 // no radio here as radio routing is outside android (for external module) or same as music 48 // (for android internal module) 49 switch (str) { 50 case "call": 51 return CarAudioManager.CAR_AUDIO_USAGE_VOICE_CALL; 52 case "media": 53 return CarAudioManager.CAR_AUDIO_USAGE_MUSIC; 54 case "nav_guidance": 55 return CarAudioManager.CAR_AUDIO_USAGE_NAVIGATION_GUIDANCE; 56 case "voice_command": 57 return CarAudioManager.CAR_AUDIO_USAGE_VOICE_COMMAND; 58 case "alarm": 59 return CarAudioManager.CAR_AUDIO_USAGE_ALARM; 60 case "notification": 61 return CarAudioManager.CAR_AUDIO_USAGE_NOTIFICATION; 62 case "system": 63 return CarAudioManager.CAR_AUDIO_USAGE_SYSTEM_SOUND; 64 case "safety": 65 return CarAudioManager.CAR_AUDIO_USAGE_SYSTEM_SAFETY_ALERT; 66 case "unknown": 67 return CarAudioManager.CAR_AUDIO_USAGE_DEFAULT; 68 } 69 throw new IllegalArgumentException("Wrong audioRoutingPolicy config, unknown stream type:" + 70 str); 71 } 72 AudioRoutingPolicy(String policy)73 private AudioRoutingPolicy(String policy) { 74 String[] streamPolicies = policy.split("#"); 75 final int nPhysicalStreams = streamPolicies.length; 76 mLogicalStreams = new int[nPhysicalStreams][]; 77 mPhysicalStreamForLogicalStream = new int[CarAudioManager.CAR_AUDIO_USAGE_MAX + 1]; 78 for (int i = 0; i < mPhysicalStreamForLogicalStream.length; i++) { 79 mPhysicalStreamForLogicalStream[i] = USAGE_TYPE_INVALID; 80 } 81 int defaultStreamType = USAGE_TYPE_INVALID; 82 for (String streamPolicy : streamPolicies) { 83 String[] numberVsStreams = streamPolicy.split(":"); 84 int physicalStream = Integer.parseInt(numberVsStreams[0]); 85 String[] logicalStreams = numberVsStreams[1].split(","); 86 int[] logicalStreamsInt = new int[logicalStreams.length]; 87 for (int i = 0; i < logicalStreams.length; i++) { 88 int logicalStreamNumber = getStreamType(logicalStreams[i]); 89 if (logicalStreamNumber == CarAudioManager.CAR_AUDIO_USAGE_DEFAULT) { 90 defaultStreamType = physicalStream; 91 } 92 logicalStreamsInt[i] = logicalStreamNumber; 93 mPhysicalStreamForLogicalStream[logicalStreamNumber] = physicalStream; 94 } 95 Arrays.sort(logicalStreamsInt); 96 mLogicalStreams[physicalStream] = logicalStreamsInt; 97 } 98 if (defaultStreamType == USAGE_TYPE_INVALID) { 99 Log.e(CarLog.TAG_AUDIO, "Audio routing policy did not include unknown"); 100 defaultStreamType = 0; 101 } 102 for (int i = 0; i < mPhysicalStreamForLogicalStream.length; i++) { 103 if (mPhysicalStreamForLogicalStream[i] == USAGE_TYPE_INVALID) { 104 if (i == CarAudioManager.CAR_AUDIO_USAGE_RADIO) { 105 // set radio routing to be the same as music. For external radio, this does not 106 // matter. For internal one, it should be the same as music. 107 int musicPhysicalStream = 108 mPhysicalStreamForLogicalStream[CarAudioManager.CAR_AUDIO_USAGE_MUSIC]; 109 if (musicPhysicalStream == USAGE_TYPE_INVALID) { 110 musicPhysicalStream = defaultStreamType; 111 } 112 mPhysicalStreamForLogicalStream[i] = musicPhysicalStream; 113 } else { 114 Log.w(CarLog.TAG_AUDIO, "Audio routing policy did not cover logical stream " + 115 i); 116 mPhysicalStreamForLogicalStream[i] = defaultStreamType; 117 } 118 } 119 } 120 } 121 getPhysicalStreamsCount()122 public int getPhysicalStreamsCount() { 123 return mLogicalStreams.length; 124 } 125 getLogicalStreamsForPhysicalStream(int physicalStreamNumber)126 public int[] getLogicalStreamsForPhysicalStream(int physicalStreamNumber) { 127 return mLogicalStreams[physicalStreamNumber]; 128 } 129 getPhysicalStreamForLogicalStream(int logicalStream)130 public int getPhysicalStreamForLogicalStream(int logicalStream) { 131 return mPhysicalStreamForLogicalStream[logicalStream]; 132 } 133 dump(PrintWriter writer)134 public void dump(PrintWriter writer) { 135 writer.println("*AudioRoutingPolicy*"); 136 writer.println("**Logical Streams**"); 137 for (int i = 0; i < mLogicalStreams.length; i++) { 138 writer.print("physical stream " + i + ":"); 139 for (int logicalStream : mLogicalStreams[i]) { 140 writer.print(Integer.toString(logicalStream) + ","); 141 } 142 writer.println(""); 143 } 144 } 145 } 146