1 /* 2 * Copyright (C) 2019 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 android.media; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.SystemApi; 22 import android.os.Parcel; 23 import android.os.Parcelable; 24 25 import java.lang.annotation.Retention; 26 import java.lang.annotation.RetentionPolicy; 27 import java.util.Objects; 28 29 /** 30 * @hide 31 * Class to represent the attributes of an audio device: its type (speaker, headset...), address 32 * (if known) and role (input, output). 33 * <p>Unlike {@link AudioDeviceInfo}, the device 34 * doesn't need to be connected to be uniquely identified, it can 35 * for instance represent a specific A2DP headset even after a 36 * disconnection, whereas the corresponding <code>AudioDeviceInfo</code> 37 * would then be invalid. 38 * <p>While creating / obtaining an instance is not protected by a 39 * permission, APIs using one rely on MODIFY_AUDIO_ROUTING. 40 */ 41 @SystemApi 42 public final class AudioDeviceAttributes implements Parcelable { 43 44 /** 45 * A role identifying input devices, such as microphones. 46 */ 47 public static final int ROLE_INPUT = AudioPort.ROLE_SOURCE; 48 /** 49 * A role identifying output devices, such as speakers or headphones. 50 */ 51 public static final int ROLE_OUTPUT = AudioPort.ROLE_SINK; 52 53 /** @hide */ 54 @IntDef(flag = false, prefix = "ROLE_", value = { 55 ROLE_INPUT, ROLE_OUTPUT } 56 ) 57 @Retention(RetentionPolicy.SOURCE) 58 public @interface Role {} 59 60 /** 61 * The audio device type, as defined in {@link AudioDeviceInfo} 62 */ 63 private final @AudioDeviceInfo.AudioDeviceType int mType; 64 /** 65 * The unique address of the device. Some devices don't have addresses, only an empty string. 66 */ 67 private final @NonNull String mAddress; 68 69 /** 70 * Is input or output device 71 */ 72 private final @Role int mRole; 73 74 /** 75 * The internal audio device type 76 */ 77 private final int mNativeType; 78 79 /** 80 * @hide 81 * Constructor from a valid {@link AudioDeviceInfo} 82 * @param deviceInfo the connected audio device from which to obtain the device-identifying 83 * type and address. 84 */ 85 @SystemApi AudioDeviceAttributes(@onNull AudioDeviceInfo deviceInfo)86 public AudioDeviceAttributes(@NonNull AudioDeviceInfo deviceInfo) { 87 Objects.requireNonNull(deviceInfo); 88 mRole = deviceInfo.isSink() ? ROLE_OUTPUT : ROLE_INPUT; 89 mType = deviceInfo.getType(); 90 mAddress = deviceInfo.getAddress(); 91 mNativeType = deviceInfo.getInternalType(); 92 } 93 94 /** 95 * @hide 96 * Constructor from role, device type and address 97 * @param role indicates input or output role 98 * @param type the device type, as defined in {@link AudioDeviceInfo} 99 * @param address the address of the device, or an empty string for devices without one 100 */ 101 @SystemApi AudioDeviceAttributes(@ole int role, @AudioDeviceInfo.AudioDeviceType int type, @NonNull String address)102 public AudioDeviceAttributes(@Role int role, @AudioDeviceInfo.AudioDeviceType int type, 103 @NonNull String address) { 104 Objects.requireNonNull(address); 105 if (role != ROLE_OUTPUT && role != ROLE_INPUT) { 106 throw new IllegalArgumentException("Invalid role " + role); 107 } 108 if (role == ROLE_OUTPUT) { 109 AudioDeviceInfo.enforceValidAudioDeviceTypeOut(type); 110 mNativeType = AudioDeviceInfo.convertDeviceTypeToInternalDevice(type); 111 } else if (role == ROLE_INPUT) { 112 AudioDeviceInfo.enforceValidAudioDeviceTypeIn(type); 113 mNativeType = AudioDeviceInfo.convertDeviceTypeToInternalInputDevice(type); 114 } else { 115 mNativeType = AudioSystem.DEVICE_NONE; 116 } 117 118 mRole = role; 119 mType = type; 120 mAddress = address; 121 } 122 123 /** 124 * @hide 125 * Constructor from internal device type and address 126 * @param type the internal device type, as defined in {@link AudioSystem} 127 * @param address the address of the device, or an empty string for devices without one 128 */ AudioDeviceAttributes(int nativeType, @NonNull String address)129 public AudioDeviceAttributes(int nativeType, @NonNull String address) { 130 mRole = (nativeType & AudioSystem.DEVICE_BIT_IN) != 0 ? ROLE_INPUT : ROLE_OUTPUT; 131 mType = AudioDeviceInfo.convertInternalDeviceToDeviceType(nativeType); 132 mAddress = address; 133 mNativeType = nativeType; 134 } 135 136 /** 137 * @hide 138 * Returns the role of a device 139 * @return the role 140 */ 141 @SystemApi getRole()142 public @Role int getRole() { 143 return mRole; 144 } 145 146 /** 147 * @hide 148 * Returns the audio device type of a device 149 * @return the type, as defined in {@link AudioDeviceInfo} 150 */ 151 @SystemApi getType()152 public @AudioDeviceInfo.AudioDeviceType int getType() { 153 return mType; 154 } 155 156 /** 157 * @hide 158 * Returns the address of the audio device, or an empty string for devices without one 159 * @return the device address 160 */ 161 @SystemApi getAddress()162 public @NonNull String getAddress() { 163 return mAddress; 164 } 165 166 /** 167 * @hide 168 * Returns the internal device type of a device 169 * @return the internal device type 170 */ getInternalType()171 public int getInternalType() { 172 return mNativeType; 173 } 174 175 @Override hashCode()176 public int hashCode() { 177 return Objects.hash(mRole, mType, mAddress); 178 } 179 180 @Override equals(Object o)181 public boolean equals(Object o) { 182 if (this == o) return true; 183 if (o == null || getClass() != o.getClass()) return false; 184 185 AudioDeviceAttributes that = (AudioDeviceAttributes) o; 186 return ((mRole == that.mRole) 187 && (mType == that.mType) 188 && mAddress.equals(that.mAddress)); 189 } 190 191 /** @hide */ roleToString(@ole int role)192 public static String roleToString(@Role int role) { 193 return (role == ROLE_OUTPUT ? "output" : "input"); 194 } 195 196 @Override toString()197 public String toString() { 198 return new String("AudioDeviceAttributes:" 199 + " role:" + roleToString(mRole) 200 + " type:" + (mRole == ROLE_OUTPUT ? AudioSystem.getOutputDeviceName(mNativeType) 201 : AudioSystem.getInputDeviceName(mNativeType)) 202 + " addr:" + mAddress); 203 } 204 205 @Override describeContents()206 public int describeContents() { 207 return 0; 208 } 209 210 @Override writeToParcel(@onNull Parcel dest, int flags)211 public void writeToParcel(@NonNull Parcel dest, int flags) { 212 dest.writeInt(mRole); 213 dest.writeInt(mType); 214 dest.writeString(mAddress); 215 dest.writeInt(mNativeType); 216 } 217 AudioDeviceAttributes(@onNull Parcel in)218 private AudioDeviceAttributes(@NonNull Parcel in) { 219 mRole = in.readInt(); 220 mType = in.readInt(); 221 mAddress = in.readString(); 222 mNativeType = in.readInt(); 223 } 224 225 public static final @NonNull Parcelable.Creator<AudioDeviceAttributes> CREATOR = 226 new Parcelable.Creator<AudioDeviceAttributes>() { 227 /** 228 * Rebuilds an AudioDeviceAttributes previously stored with writeToParcel(). 229 * @param p Parcel object to read the AudioDeviceAttributes from 230 * @return a new AudioDeviceAttributes created from the data in the parcel 231 */ 232 public AudioDeviceAttributes createFromParcel(Parcel p) { 233 return new AudioDeviceAttributes(p); 234 } 235 236 public AudioDeviceAttributes[] newArray(int size) { 237 return new AudioDeviceAttributes[size]; 238 } 239 }; 240 } 241