1 /*
2  * Copyright (C) 2022 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 
17 package com.android.car.audio;
18 
19 import static android.car.builtin.media.AudioManagerHelper.addTagToAudioAttributes;
20 import static android.car.builtin.media.AudioManagerHelper.getTags;
21 import static android.car.builtin.media.AudioManagerHelper.usageToXsdString;
22 
23 import android.hardware.audio.common.PlaybackTrackMetadata;
24 import android.hardware.automotive.audiocontrol.DuckingInfo;
25 import android.media.AudioAttributes;
26 import android.media.audio.common.AudioChannelLayout;
27 import android.media.audio.common.AudioDevice;
28 import android.media.audio.common.AudioDeviceAddress;
29 import android.media.audio.common.AudioDeviceDescription;
30 
31 import com.android.car.audio.CarAudioContext.AudioAttributesWrapper;
32 import com.android.car.internal.annotation.AttributeUsage;
33 
34 import java.util.ArrayList;
35 import java.util.List;
36 import java.util.Objects;
37 import java.util.Set;
38 
39 /** Car HAL audio Utils */
40 public final class CarHalAudioUtils {
CarHalAudioUtils()41     private CarHalAudioUtils() {}
42 
43     /**
44      * Creates {@link DuckingInfo} instance from contents of {@link CarDuckingInfo}.
45      *
46      * <p>Converts usages to XSD strings as part of this process.
47      */
generateDuckingInfo(CarDuckingInfo carDuckingInfo)48     public static DuckingInfo generateDuckingInfo(CarDuckingInfo carDuckingInfo) {
49         Objects.requireNonNull(carDuckingInfo, "Car Ducking Info can not be null");
50         DuckingInfo duckingInfo = new DuckingInfo();
51         duckingInfo.zoneId = carDuckingInfo.getZoneId();
52         duckingInfo.deviceAddressesToDuck =
53                 carDuckingInfo.getAddressesToDuck().toArray(new String[0]);
54         duckingInfo.deviceAddressesToUnduck =
55                 carDuckingInfo.getAddressesToUnduck().toArray(new String[0]);
56         List<PlaybackTrackMetadata> playbackTrackMetadataList =
57                 carDuckingInfo.getPlaybackMetaDataHoldingFocus();
58         duckingInfo.playbackMetaDataHoldingFocus =
59                 playbackTrackMetadataList.toArray(PlaybackTrackMetadata[]::new);
60         duckingInfo.usagesHoldingFocus = metadatasToUsageStrings(playbackTrackMetadataList);
61         return duckingInfo;
62     }
63 
64     /**
65      * Converts the {@link AttributeUsage} into a metadata for a particular
66      * audio zone.
67      *
68      */
audioAttributeToMetadata( AudioAttributes audioAttributes, CarAudioZone zone)69     public static PlaybackTrackMetadata audioAttributeToMetadata(
70             AudioAttributes audioAttributes, CarAudioZone zone) {
71         Objects.requireNonNull(zone, "Car audio zone can not be null");
72         int carAudioContextId = zone.getCarAudioContext()
73                 .getContextForAudioAttribute(audioAttributes);
74         String address = zone.getAddressForContext(carAudioContextId);
75         return audioAttributeToMetadata(audioAttributes, address);
76     }
77 
audioAttributeToMetadata(AudioAttributes audioAttributes)78     public static PlaybackTrackMetadata audioAttributeToMetadata(AudioAttributes audioAttributes) {
79         return audioAttributeToMetadata(audioAttributes, /* deviceAddress= */ "");
80     }
81 
audioAttributeToMetadata( AudioAttributes audioAttributes, String deviceAddress)82     private static PlaybackTrackMetadata audioAttributeToMetadata(
83             AudioAttributes audioAttributes, String deviceAddress) {
84         Objects.requireNonNull(audioAttributes, "Audio Attributes can not be null");
85         Objects.requireNonNull(deviceAddress, "Device Address can not be null");
86 
87         PlaybackTrackMetadata playbackTrackMetadata = new PlaybackTrackMetadata();
88         playbackTrackMetadata.usage = audioAttributes.getSystemUsage();
89         playbackTrackMetadata.contentType = audioAttributes.getContentType();
90         Set<String> tags = getTags(audioAttributes);
91         String[] tagsArray = new String[tags.size()];
92         playbackTrackMetadata.tags = tags.toArray(tagsArray);
93         playbackTrackMetadata.channelMask = AudioChannelLayout.none(0);
94         AudioDeviceDescription audioDeviceDescription = new AudioDeviceDescription();
95         audioDeviceDescription.connection = "";
96         AudioDevice audioDevice = new AudioDevice();
97         audioDevice.type = audioDeviceDescription;
98         audioDevice.address = AudioDeviceAddress.id(deviceAddress);
99         playbackTrackMetadata.sourceDevice = audioDevice;
100         return playbackTrackMetadata;
101     }
102 
usageToMetadata( @ttributeUsage int usage, CarAudioZone zone)103     public static PlaybackTrackMetadata usageToMetadata(
104             @AttributeUsage int usage, CarAudioZone zone) {
105         Objects.requireNonNull(zone, "Car audio zone can not be null");
106         AudioAttributes attributes = CarAudioContext.getAudioAttributeFromUsage(usage);
107         return audioAttributeToMetadata(attributes, zone);
108     }
109 
usageToMetadata(@ttributeUsage int usage)110     public static PlaybackTrackMetadata usageToMetadata(@AttributeUsage int usage) {
111         AudioAttributes attributes = CarAudioContext.getAudioAttributeFromUsage(usage);
112         return audioAttributeToMetadata(attributes);
113     }
114 
audioAttributesWrapperToMetadata( AudioAttributesWrapper audioAttributesWrapper)115     public static PlaybackTrackMetadata audioAttributesWrapperToMetadata(
116             AudioAttributesWrapper audioAttributesWrapper) {
117         Objects.requireNonNull(audioAttributesWrapper, "Audio Attributes Wrapper can not be null");
118         return audioAttributeToMetadata(audioAttributesWrapper.getAudioAttributes());
119     }
120 
121     /**
122      * Converts the list of {@link AttributeUsage} usages into
123      * Playback metadata for a particular zone.
124      *
125      */
audioAttributesToMetadatas( List<AudioAttributes> audioAttributes, CarAudioZone zone)126     public static List<PlaybackTrackMetadata> audioAttributesToMetadatas(
127             List<AudioAttributes> audioAttributes, CarAudioZone zone) {
128         Objects.requireNonNull(zone, "Car audio zone can not be null");
129         List<PlaybackTrackMetadata> playbackTrackMetadataList =
130                 new ArrayList<>(audioAttributes.size());
131         for (int index = 0; index < audioAttributes.size(); index++) {
132             playbackTrackMetadataList.add(audioAttributeToMetadata(audioAttributes.get(index),
133                     zone));
134         }
135         return playbackTrackMetadataList;
136     }
137 
audioAttributesToMetadatas( List<AudioAttributes> audioAttributes)138     public static List<PlaybackTrackMetadata> audioAttributesToMetadatas(
139             List<AudioAttributes> audioAttributes) {
140         List<PlaybackTrackMetadata> metadataList = new ArrayList<>(audioAttributes.size());
141         for (int index = 0; index < audioAttributes.size(); index++) {
142             metadataList.add(audioAttributeToMetadata(audioAttributes.get(index)));
143         }
144         return metadataList;
145     }
146 
147     /**
148      * Converts a playback track metadata into the corresponding audio attribute
149      *
150      */
metadataToAudioAttribute(PlaybackTrackMetadata metadata)151     public static AudioAttributes metadataToAudioAttribute(PlaybackTrackMetadata metadata) {
152         AudioAttributes.Builder builder = new AudioAttributes.Builder();
153         if (AudioAttributes.isSystemUsage(metadata.usage)) {
154             builder.setSystemUsage(metadata.usage);
155         } else {
156             builder.setUsage(metadata.usage);
157         }
158         builder.setContentType(metadata.contentType);
159         if (metadata.tags != null) {
160             for (int i = 0; i < metadata.tags.length; i++) {
161                 addTagToAudioAttributes(builder, metadata.tags[i]);
162             }
163         }
164         return builder.build();
165     }
166 
167     /**
168      * Converts a list playback track metadata into list of audio attributes
169      *
170      */
metadataToAudioAttributes( List<PlaybackTrackMetadata> playbackTrackMetadataList)171     public static List<AudioAttributes> metadataToAudioAttributes(
172             List<PlaybackTrackMetadata> playbackTrackMetadataList) {
173         List<AudioAttributes> audioAttributesForMetadata =
174                 new ArrayList<>(playbackTrackMetadataList.size());
175         for (int index = 0; index < playbackTrackMetadataList.size(); index++) {
176             audioAttributesForMetadata.add(
177                     metadataToAudioAttribute(playbackTrackMetadataList.get(index)));
178         }
179         return audioAttributesForMetadata;
180     }
181 
182     /**
183      * Converts a list of playback track metadata into an array of
184      * audio usages in string representation.
185      */
metadatasToUsageStrings( List<PlaybackTrackMetadata> playbackTrackMetadataList)186     public static String[] metadatasToUsageStrings(
187             List<PlaybackTrackMetadata> playbackTrackMetadataList) {
188         String[] usageLiteralsForMetadata = new String[playbackTrackMetadataList.size()];
189         for (int index = 0; index < playbackTrackMetadataList.size(); index++) {
190             PlaybackTrackMetadata playbackTrackMetadata = playbackTrackMetadataList.get(index);
191             usageLiteralsForMetadata[index] = usageToXsdString(playbackTrackMetadata.usage);
192         }
193         return usageLiteralsForMetadata;
194     }
195 }
196