1 /* 2 * Copyright (C) 2014 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.NonNull; 20 import android.compat.annotation.UnsupportedAppUsage; 21 import android.os.Build; 22 23 import com.android.aconfig.annotations.VisibleForTesting; 24 25 import java.util.Arrays; 26 import java.util.List; 27 28 /** 29 * The AudioDevicePort is a specialized type of AudioPort 30 * describing an input (e.g microphone) or output device (e.g speaker) 31 * of the system. 32 * An AudioDevicePort is an AudioPort controlled by the audio HAL, almost always a physical 33 * device at the boundary of the audio system. 34 * In addition to base audio port attributes, the device descriptor contains: 35 * - the device type (e.g AudioManager.DEVICE_OUT_SPEAKER) 36 * - the device address (e.g MAC address for AD2P sink). 37 * @see AudioPort 38 * @hide 39 */ 40 41 public class AudioDevicePort extends AudioPort { 42 43 /** @hide */ 44 // TODO: b/316864909 - Remove this method once there's a way to fake audio device ports further 45 // down the stack. 46 @VisibleForTesting createForTesting( int type, @NonNull String name, @NonNull String address)47 public static AudioDevicePort createForTesting( 48 int type, @NonNull String name, @NonNull String address) { 49 return new AudioDevicePort( 50 new AudioHandle(/* id= */ 0), 51 name, 52 /* samplingRates= */ null, 53 /* channelMasks= */ null, 54 /* channelIndexMasks= */ null, 55 /* formats= */ null, 56 /* gains= */ null, 57 type, 58 address, 59 /* encapsulationModes= */ null, 60 /* encapsulationMetadataTypes= */ null); 61 } 62 63 private final int mType; 64 private final String mAddress; 65 private final int[] mEncapsulationModes; 66 private final int[] mEncapsulationMetadataTypes; 67 68 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) AudioDevicePort(AudioHandle handle, String deviceName, int[] samplingRates, int[] channelMasks, int[] channelIndexMasks, int[] formats, AudioGain[] gains, int type, String address, int[] encapsulationModes, @AudioTrack.EncapsulationMetadataType int[] encapsulationMetadataTypes)69 AudioDevicePort(AudioHandle handle, String deviceName, 70 int[] samplingRates, int[] channelMasks, int[] channelIndexMasks, 71 int[] formats, AudioGain[] gains, int type, String address, int[] encapsulationModes, 72 @AudioTrack.EncapsulationMetadataType int[] encapsulationMetadataTypes) { 73 super(handle, 74 (AudioManager.isInputDevice(type) == true) ? 75 AudioPort.ROLE_SOURCE : AudioPort.ROLE_SINK, 76 deviceName, samplingRates, channelMasks, channelIndexMasks, formats, gains); 77 mType = type; 78 mAddress = address; 79 mEncapsulationModes = encapsulationModes; 80 mEncapsulationMetadataTypes = encapsulationMetadataTypes; 81 } 82 AudioDevicePort(AudioHandle handle, String deviceName, List<AudioProfile> profiles, AudioGain[] gains, int type, String address, int[] encapsulationModes, @AudioTrack.EncapsulationMetadataType int[] encapsulationMetadataTypes, List<AudioDescriptor> descriptors)83 AudioDevicePort(AudioHandle handle, String deviceName, List<AudioProfile> profiles, 84 AudioGain[] gains, int type, String address, int[] encapsulationModes, 85 @AudioTrack.EncapsulationMetadataType int[] encapsulationMetadataTypes, 86 List<AudioDescriptor> descriptors) { 87 super(handle, 88 AudioManager.isInputDevice(type) ? AudioPort.ROLE_SOURCE : AudioPort.ROLE_SINK, 89 deviceName, profiles, gains, descriptors); 90 mType = type; 91 mAddress = address; 92 mEncapsulationModes = encapsulationModes; 93 mEncapsulationMetadataTypes = encapsulationMetadataTypes; 94 } 95 96 /** 97 * Get the device type (e.g AudioManager.DEVICE_OUT_SPEAKER) 98 */ 99 @UnsupportedAppUsage type()100 public int type() { 101 return mType; 102 } 103 104 /** 105 * Get the device address. Address format varies with the device type. 106 * - USB devices ({@link AudioManager#DEVICE_OUT_USB_DEVICE}, 107 * {@link AudioManager#DEVICE_IN_USB_DEVICE}) use an address composed of the ALSA card number 108 * and device number: "card=2;device=1" 109 * - Bluetooth devices ({@link AudioManager#DEVICE_OUT_BLUETOOTH_SCO}, 110 * {@link AudioManager#DEVICE_OUT_BLUETOOTH_SCO}, 111 * {@link AudioManager#DEVICE_OUT_BLUETOOTH_A2DP}), 112 * {@link AudioManager#DEVICE_OUT_BLE_HEADSET}, {@link AudioManager#DEVICE_OUT_BLE_SPEAKER}) 113 * use the MAC address of the bluetooth device in the form "00:11:22:AA:BB:CC" as reported by 114 * {@link BluetoothDevice#getAddress()}. 115 * - Bluetooth LE broadcast group ({@link AudioManager#DEVICE_OUT_BLE_BROADCAST} use the group number. 116 * - Devices that do not have an address will indicate an empty string "". 117 */ address()118 public String address() { 119 return mAddress; 120 } 121 122 /** 123 * Get supported encapsulation modes. 124 */ encapsulationModes()125 public @NonNull @AudioTrack.EncapsulationMode int[] encapsulationModes() { 126 if (mEncapsulationModes == null) { 127 return new int[0]; 128 } 129 return Arrays.stream(mEncapsulationModes).boxed() 130 .filter(mode -> mode != AudioTrack.ENCAPSULATION_MODE_HANDLE) 131 .mapToInt(Integer::intValue).toArray(); 132 } 133 134 /** 135 * Get supported encapsulation metadata types. 136 */ encapsulationMetadataTypes()137 public @NonNull @AudioTrack.EncapsulationMetadataType int[] encapsulationMetadataTypes() { 138 if (mEncapsulationMetadataTypes == null) { 139 return new int[0]; 140 } 141 int[] encapsulationMetadataTypes = new int[mEncapsulationMetadataTypes.length]; 142 System.arraycopy(mEncapsulationMetadataTypes, 0, 143 encapsulationMetadataTypes, 0, mEncapsulationMetadataTypes.length); 144 return encapsulationMetadataTypes; 145 } 146 147 /** 148 * Build a specific configuration of this audio device port for use by methods 149 * like AudioManager.connectAudioPatch(). 150 */ buildConfig(int samplingRate, int channelMask, int format, AudioGainConfig gain)151 public AudioDevicePortConfig buildConfig(int samplingRate, int channelMask, int format, 152 AudioGainConfig gain) { 153 return new AudioDevicePortConfig(this, samplingRate, channelMask, format, gain); 154 } 155 156 @Override equals(Object o)157 public boolean equals(Object o) { 158 if (o == null || !(o instanceof AudioDevicePort)) { 159 return false; 160 } 161 AudioDevicePort other = (AudioDevicePort)o; 162 if (mType != other.type()) { 163 return false; 164 } 165 if (mAddress == null && other.address() != null) { 166 return false; 167 } 168 if (!mAddress.equals(other.address())) { 169 return false; 170 } 171 return super.equals(o); 172 } 173 174 @Override toString()175 public String toString() { 176 String type = (mRole == ROLE_SOURCE ? 177 AudioSystem.getInputDeviceName(mType) : 178 AudioSystem.getOutputDeviceName(mType)); 179 return "{" + super.toString() 180 + ", mType: " + type 181 + ", mAddress: " + Utils.anonymizeBluetoothAddress(mType, mAddress) 182 + "}"; 183 } 184 } 185