1 /* 2 * Copyright (C) 2023 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.hal; 18 19 import static android.media.audio.common.AudioDeviceDescription.CONNECTION_BUS; 20 import static android.media.audio.common.AudioDeviceType.IN_DEVICE; 21 import static android.media.audio.common.AudioDeviceType.OUT_DEVICE; 22 import static android.media.audio.common.AudioGainMode.JOINT; 23 24 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE; 25 26 import android.annotation.NonNull; 27 import android.media.audio.common.AudioDevice; 28 import android.media.audio.common.AudioGain; 29 import android.media.audio.common.AudioPort; 30 31 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport; 32 import com.android.internal.util.Preconditions; 33 34 import java.util.Objects; 35 36 /** 37 * Audio Device info received from HAL as part of dynamic gain stage configration 38 */ 39 public final class HalAudioDeviceInfo { 40 private final int mId; 41 private final String mName; 42 private final AudioGain mAudioGain; 43 private final int mType; 44 private final String mConnection; 45 private final String mAddress; 46 private static final int AUDIO_PORT_EXT_DEVICE = 1; 47 HalAudioDeviceInfo(AudioPort port)48 public HalAudioDeviceInfo(AudioPort port) { 49 Objects.requireNonNull(port, "Audio port can not be null"); 50 51 Preconditions.checkArgument(port.ext.getTag() == AUDIO_PORT_EXT_DEVICE, 52 "Invalid audio port ext setting: %d", port.ext.getTag()); 53 AudioDevice device = Objects.requireNonNull(port.ext.getDevice().device, 54 "Audio device can not be null"); 55 checkIfAudioDeviceIsValidOutputBus(device); 56 57 mId = port.id; 58 mName = port.name; 59 mAudioGain = getAudioGain(port.gains); 60 mType = device.type.type; 61 mConnection = device.type.connection; 62 mAddress = device.address.getId(); 63 } 64 getId()65 public int getId() { 66 return mId; 67 } 68 getName()69 public String getName() { 70 return mName; 71 } 72 getGainMinValue()73 public int getGainMinValue() { 74 return mAudioGain.minValue; 75 } 76 getGainMaxValue()77 public int getGainMaxValue() { 78 return mAudioGain.maxValue; 79 } 80 getGainDefaultValue()81 public int getGainDefaultValue() { 82 return mAudioGain.defaultValue; 83 } 84 getGainStepValue()85 public int getGainStepValue() { 86 return mAudioGain.stepValue; 87 } 88 getType()89 public int getType() { 90 return mType; 91 } 92 getConnection()93 public String getConnection() { 94 return mConnection; 95 } 96 getAddress()97 public String getAddress() { 98 return mAddress; 99 } 100 isOutputDevice()101 public boolean isOutputDevice() { 102 return mType == OUT_DEVICE; 103 } 104 isInputDevice()105 public boolean isInputDevice() { 106 return mType == IN_DEVICE; 107 } 108 109 @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE) 110 @Override toString()111 public String toString() { 112 return new StringBuilder() 113 .append("{mId: ").append(mId).append(", mName: ").append(mName) 114 .append(", mAudioGain: ").append(Objects.toString(mAudioGain)) 115 .append(", mType: ").append(mType).append(", mConnection: ").append(mConnection) 116 .append(", mAddress: ").append(mAddress).append("}").toString(); 117 } 118 119 @Override equals(Object o)120 public boolean equals(Object o) { 121 if (this == o) { 122 return true; 123 } 124 125 if (!(o instanceof HalAudioDeviceInfo)) { 126 return false; 127 } 128 129 HalAudioDeviceInfo rhs = (HalAudioDeviceInfo) o; 130 131 // mId is not reliable until Audio HAL migrates to AIDL 132 return mType == rhs.mType && mName.equals(rhs.mName) && mConnection.equals(rhs.mConnection) 133 && mAddress.equals(rhs.mAddress) && Objects.equals(mAudioGain, rhs.mAudioGain); 134 } 135 136 @Override hashCode()137 public int hashCode() { 138 // mId is not reliable until Audio HAL migrates to AIDL 139 return Objects.hash(mName, mAudioGain, mType, mConnection, mAddress); 140 } 141 checkIfAudioDeviceIsValidOutputBus(AudioDevice device)142 private void checkIfAudioDeviceIsValidOutputBus(AudioDevice device) { 143 Preconditions.checkArgument((device.type.type == OUT_DEVICE) 144 || (device.type.type == IN_DEVICE), 145 "Invalid audio device type (expecting IN/OUT_DEVICE): %d", device.type.type); 146 147 Preconditions.checkArgument(device.type.connection.equals(CONNECTION_BUS), 148 "Invalid audio device connection (expecting CONNECTION_BUS): %s", 149 device.type.connection); 150 151 Preconditions.checkStringNotEmpty(device.address.getId(), 152 "Audio device address cannot be empty"); 153 } 154 getAudioGain(@onNull AudioGain[] gains)155 private static AudioGain getAudioGain(@NonNull AudioGain[] gains) { 156 Objects.requireNonNull(gains, "Audio gains can not be null"); 157 Preconditions.checkArgument(gains.length > 0, "Audio port must have gains defined"); 158 for (int index = 0; index < gains.length; index++) { 159 AudioGain gain = Objects.requireNonNull(gains[index], "Audio gain can not be null"); 160 if (gain.mode == JOINT) { 161 return checkAudioGainConfiguration(gain); 162 } 163 } 164 throw new IllegalStateException("Audio port does not have a valid audio gain"); 165 } 166 checkAudioGainConfiguration(AudioGain gain)167 private static AudioGain checkAudioGainConfiguration(AudioGain gain) { 168 Preconditions.checkArgument(gain.maxValue >= gain.minValue, 169 "Max gain %d is lower than min gain %d", 170 gain.maxValue, gain.minValue); 171 Preconditions.checkArgument((gain.defaultValue >= gain.minValue) 172 && (gain.defaultValue <= gain.maxValue), 173 "Default gain %d not in range (%d,%d)", gain.defaultValue, 174 gain.minValue, gain.maxValue); 175 Preconditions.checkArgument(gain.stepValue > 0, 176 "Gain step value must be greater than zero: %d", gain.stepValue); 177 Preconditions.checkArgument( 178 ((gain.maxValue - gain.minValue) % gain.stepValue) == 0, 179 "Gain step value %d greater than min gain to max gain range %d", 180 gain.stepValue, gain.maxValue - gain.minValue); 181 Preconditions.checkArgument( 182 ((gain.defaultValue - gain.minValue) % gain.stepValue) == 0, 183 "Gain step value %d greater than min gain to default gain range %d", 184 gain.stepValue, gain.defaultValue - gain.minValue); 185 return gain; 186 } 187 } 188