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