• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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.audio;
17 
18 import android.car.builtin.util.Slogf;
19 import android.media.AudioAttributes;
20 import android.media.AudioFormat;
21 import android.media.AudioManager;
22 import android.media.audiopolicy.AudioMix;
23 import android.media.audiopolicy.AudioMixingRule;
24 import android.media.audiopolicy.AudioPolicy;
25 import android.util.Log;
26 import android.util.SparseArray;
27 
28 import com.android.car.CarLog;
29 
30 import java.util.Arrays;
31 import java.util.List;
32 
33 /**
34  * Builds dynamic audio routing in a car from audio zone configuration.
35  */
36 final class CarAudioDynamicRouting {
37     // For legacy stream type based volume control.
38     // Values in STREAM_TYPES and STREAM_TYPE_USAGES should be aligned.
39     static final int[] STREAM_TYPES = new int[] {
40             AudioManager.STREAM_MUSIC,
41             AudioManager.STREAM_ALARM,
42             AudioManager.STREAM_RING
43     };
44     static final int[] STREAM_TYPE_USAGES = new int[] {
45             AudioAttributes.USAGE_MEDIA,
46             AudioAttributes.USAGE_ALARM,
47             AudioAttributes.USAGE_NOTIFICATION_RINGTONE
48     };
49 
setupAudioDynamicRouting(AudioPolicy.Builder builder, SparseArray<CarAudioZone> carAudioZones, CarAudioContext carAudioContext)50     static void setupAudioDynamicRouting(AudioPolicy.Builder builder,
51             SparseArray<CarAudioZone> carAudioZones, CarAudioContext carAudioContext) {
52         for (int i = 0; i < carAudioZones.size(); i++) {
53             CarAudioZone zone = carAudioZones.valueAt(i);
54             for (CarVolumeGroup group : zone.getVolumeGroups()) {
55                 setupAudioDynamicRoutingForGroup(group, builder, carAudioContext);
56             }
57         }
58     }
59 
60     /**
61      * Enumerates all physical buses in a given volume group and attach the mixing rules.
62      * @param group {@link CarVolumeGroup} instance to enumerate the buses with
63      * @param builder {@link AudioPolicy.Builder} to attach the mixing rules
64      * @param carAudioContext car audio context
65      */
setupAudioDynamicRoutingForGroup(CarVolumeGroup group, AudioPolicy.Builder builder, CarAudioContext carAudioContext)66     private static void setupAudioDynamicRoutingForGroup(CarVolumeGroup group,
67             AudioPolicy.Builder builder, CarAudioContext carAudioContext) {
68         // Note that one can not register audio mix for same bus more than once.
69         List<String> addresses = group.getAddresses();
70         for (int index = 0; index < addresses.size(); index++) {
71             String address = addresses.get(index);
72             boolean hasContext = false;
73             CarAudioDeviceInfo info = group.getCarAudioDeviceInfoForAddress(address);
74             AudioFormat mixFormat = new AudioFormat.Builder()
75                     .setSampleRate(info.getSampleRate())
76                     .setEncoding(info.getEncodingFormat())
77                     .setChannelMask(info.getChannelCount())
78                     .build();
79             AudioMixingRule.Builder mixingRuleBuilder = new AudioMixingRule.Builder();
80             List<Integer> contextIdsForAddress = group.getContextsForAddress(address);
81             for (int contextIndex = 0; contextIndex < contextIdsForAddress.size(); contextIndex++) {
82                 @CarAudioContext.AudioContext int contextId =
83                         contextIdsForAddress.get(contextIndex);
84                 hasContext = true;
85                 AudioAttributes[] allAudioAttributes =
86                         carAudioContext.getAudioAttributesForContext(contextId);
87                 for (int attrIndex = 0; attrIndex < allAudioAttributes.length; attrIndex++) {
88                     AudioAttributes attributes = allAudioAttributes[attrIndex];
89                     mixingRuleBuilder.addRule(attributes,
90                             AudioMixingRule.RULE_MATCH_ATTRIBUTE_USAGE);
91                 }
92                 if (Slogf.isLoggable(CarLog.TAG_AUDIO, Log.DEBUG)) {
93                     Slogf.d(CarLog.TAG_AUDIO, "Address: %s AudioContext: %s sampleRate: %d "
94                             + "channels: %d attributes: %s", address, carAudioContext,
95                             info.getSampleRate(), info.getChannelCount(),
96                             Arrays.toString(allAudioAttributes));
97                 }
98             }
99             if (hasContext) {
100                 // It's a valid case that an audio output address is defined in
101                 // audio_policy_configuration and no context is assigned to it.
102                 // In such case, do not build a policy mix with zero rules.
103                 AudioMix audioMix = new AudioMix.Builder(mixingRuleBuilder.build())
104                         .setFormat(mixFormat)
105                         .setDevice(info.getAudioDeviceInfo())
106                         .setRouteFlags(AudioMix.ROUTE_FLAG_RENDER)
107                         .build();
108                 builder.addMix(audioMix);
109             }
110         }
111     }
112 }
113