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