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