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