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