/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.car.audio;
import static android.car.builtin.media.AudioManagerHelper.addTagToAudioAttributes;
import static android.car.builtin.media.AudioManagerHelper.getTags;
import static android.car.builtin.media.AudioManagerHelper.usageToXsdString;
import android.hardware.audio.common.PlaybackTrackMetadata;
import android.hardware.automotive.audiocontrol.DuckingInfo;
import android.media.AudioAttributes;
import android.media.audio.common.AudioChannelLayout;
import android.media.audio.common.AudioDevice;
import android.media.audio.common.AudioDeviceAddress;
import android.media.audio.common.AudioDeviceDescription;
import com.android.car.audio.CarAudioContext.AudioAttributesWrapper;
import com.android.car.internal.annotation.AttributeUsage;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
/** Car HAL audio Utils */
public final class CarHalAudioUtils {
private CarHalAudioUtils() {}
/**
* Creates {@link DuckingInfo} instance from contents of {@link CarDuckingInfo}.
*
*
Converts usages to XSD strings as part of this process.
*/
public static DuckingInfo generateDuckingInfo(CarDuckingInfo carDuckingInfo) {
Objects.requireNonNull(carDuckingInfo, "Car Ducking Info can not be null");
DuckingInfo duckingInfo = new DuckingInfo();
duckingInfo.zoneId = carDuckingInfo.getZoneId();
duckingInfo.deviceAddressesToDuck =
carDuckingInfo.getAddressesToDuck().toArray(new String[0]);
duckingInfo.deviceAddressesToUnduck =
carDuckingInfo.getAddressesToUnduck().toArray(new String[0]);
List playbackTrackMetadataList =
carDuckingInfo.getPlaybackMetaDataHoldingFocus();
duckingInfo.playbackMetaDataHoldingFocus =
playbackTrackMetadataList.toArray(PlaybackTrackMetadata[]::new);
duckingInfo.usagesHoldingFocus = metadatasToUsageStrings(playbackTrackMetadataList);
return duckingInfo;
}
/**
* Converts the {@link AttributeUsage} into a metadata for a particular
* audio zone.
*
*/
public static PlaybackTrackMetadata audioAttributeToMetadata(
AudioAttributes audioAttributes, CarAudioZone zone) {
Objects.requireNonNull(zone, "Car audio zone can not be null");
int carAudioContextId = zone.getCarAudioContext()
.getContextForAudioAttribute(audioAttributes);
String address = zone.getAddressForContext(carAudioContextId);
return audioAttributeToMetadata(audioAttributes, address);
}
public static PlaybackTrackMetadata audioAttributeToMetadata(AudioAttributes audioAttributes) {
return audioAttributeToMetadata(audioAttributes, /* deviceAddress= */ "");
}
private static PlaybackTrackMetadata audioAttributeToMetadata(
AudioAttributes audioAttributes, String deviceAddress) {
Objects.requireNonNull(audioAttributes, "Audio Attributes can not be null");
Objects.requireNonNull(deviceAddress, "Device Address can not be null");
PlaybackTrackMetadata playbackTrackMetadata = new PlaybackTrackMetadata();
playbackTrackMetadata.usage = audioAttributes.getSystemUsage();
playbackTrackMetadata.contentType = audioAttributes.getContentType();
Set tags = getTags(audioAttributes);
String[] tagsArray = new String[tags.size()];
playbackTrackMetadata.tags = tags.toArray(tagsArray);
playbackTrackMetadata.channelMask = AudioChannelLayout.none(0);
AudioDeviceDescription audioDeviceDescription = new AudioDeviceDescription();
audioDeviceDescription.connection = "";
AudioDevice audioDevice = new AudioDevice();
audioDevice.type = audioDeviceDescription;
audioDevice.address = AudioDeviceAddress.id(deviceAddress);
playbackTrackMetadata.sourceDevice = audioDevice;
return playbackTrackMetadata;
}
public static PlaybackTrackMetadata usageToMetadata(
@AttributeUsage int usage, CarAudioZone zone) {
Objects.requireNonNull(zone, "Car audio zone can not be null");
AudioAttributes attributes = CarAudioContext.getAudioAttributeFromUsage(usage);
return audioAttributeToMetadata(attributes, zone);
}
public static PlaybackTrackMetadata usageToMetadata(@AttributeUsage int usage) {
AudioAttributes attributes = CarAudioContext.getAudioAttributeFromUsage(usage);
return audioAttributeToMetadata(attributes);
}
public static PlaybackTrackMetadata audioAttributesWrapperToMetadata(
AudioAttributesWrapper audioAttributesWrapper) {
Objects.requireNonNull(audioAttributesWrapper, "Audio Attributes Wrapper can not be null");
return audioAttributeToMetadata(audioAttributesWrapper.getAudioAttributes());
}
/**
* Converts the list of {@link AttributeUsage} usages into
* Playback metadata for a particular zone.
*
*/
public static List audioAttributesToMetadatas(
List audioAttributes, CarAudioZone zone) {
Objects.requireNonNull(zone, "Car audio zone can not be null");
List playbackTrackMetadataList =
new ArrayList<>(audioAttributes.size());
for (int index = 0; index < audioAttributes.size(); index++) {
playbackTrackMetadataList.add(audioAttributeToMetadata(audioAttributes.get(index),
zone));
}
return playbackTrackMetadataList;
}
public static List audioAttributesToMetadatas(
List audioAttributes) {
List metadataList = new ArrayList<>(audioAttributes.size());
for (int index = 0; index < audioAttributes.size(); index++) {
metadataList.add(audioAttributeToMetadata(audioAttributes.get(index)));
}
return metadataList;
}
/**
* Converts a playback track metadata into the corresponding audio attribute
*
*/
public static AudioAttributes metadataToAudioAttribute(PlaybackTrackMetadata metadata) {
AudioAttributes.Builder builder = new AudioAttributes.Builder();
if (AudioAttributes.isSystemUsage(metadata.usage)) {
builder.setSystemUsage(metadata.usage);
} else {
builder.setUsage(metadata.usage);
}
builder.setContentType(metadata.contentType);
if (metadata.tags != null) {
for (int i = 0; i < metadata.tags.length; i++) {
addTagToAudioAttributes(builder, metadata.tags[i]);
}
}
return builder.build();
}
/**
* Converts a list playback track metadata into list of audio attributes
*
*/
public static List metadataToAudioAttributes(
List playbackTrackMetadataList) {
List audioAttributesForMetadata =
new ArrayList<>(playbackTrackMetadataList.size());
for (int index = 0; index < playbackTrackMetadataList.size(); index++) {
audioAttributesForMetadata.add(
metadataToAudioAttribute(playbackTrackMetadataList.get(index)));
}
return audioAttributesForMetadata;
}
/**
* Converts a list of playback track metadata into an array of
* audio usages in string representation.
*/
public static String[] metadatasToUsageStrings(
List playbackTrackMetadataList) {
String[] usageLiteralsForMetadata = new String[playbackTrackMetadataList.size()];
for (int index = 0; index < playbackTrackMetadataList.size(); index++) {
PlaybackTrackMetadata playbackTrackMetadata = playbackTrackMetadataList.get(index);
usageLiteralsForMetadata[index] = usageToXsdString(playbackTrackMetadata.usage);
}
return usageLiteralsForMetadata;
}
}