• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.ArrayList;
26 import java.util.Arrays;
27 import java.util.List;
28 
29 /**
30  * The AudioDevicePort is a specialized type of AudioPort
31  * describing an input (e.g microphone) or output device (e.g speaker)
32  * of the system.
33  * An AudioDevicePort is an AudioPort controlled by the audio HAL, almost always a physical
34  * device at the boundary of the audio system.
35  * In addition to base audio port attributes, the device descriptor contains:
36  * - the device type (e.g AudioManager.DEVICE_OUT_SPEAKER)
37  * - the device address (e.g MAC address for AD2P sink).
38  * @see AudioPort
39  * @hide
40  */
41 
42 public class AudioDevicePort extends AudioPort {
43 
44     /** @hide */
45     // TODO: b/316864909 - Remove this method once there's a way to fake audio device ports further
46     // down the stack.
47     @VisibleForTesting
createForTesting( int type, @NonNull String name, @NonNull String address)48     public static AudioDevicePort createForTesting(
49             int type, @NonNull String name, @NonNull String address) {
50         return new AudioDevicePort(
51                 new AudioHandle(/* id= */ 0),
52                 name,
53                 /* samplingRates= */ null,
54                 /* channelMasks= */ null,
55                 /* channelIndexMasks= */ null,
56                 /* formats= */ null,
57                 /* gains= */ null,
58                 type,
59                 address,
60                 /* encapsulationModes= */ null,
61                 /* encapsulationMetadataTypes= */ null);
62     }
63 
64     /** @hide */
65     // TODO: b/316864909 - Remove this method once there's a way to fake audio device ports further
66     // down the stack.
67     @VisibleForTesting
createForTesting(int speakerLayoutChannelMask)68     public static AudioDevicePort createForTesting(int speakerLayoutChannelMask) {
69         return new AudioDevicePort(
70                 new AudioHandle(/* id= */ 0),
71                 /* name= */ "testAudioDevicePort",
72                 /* profiles= */ new ArrayList<>(),
73                 /* gains= */ null,
74                 /* type= */ AudioManager.DEVICE_OUT_SPEAKER,
75                 /* address= */ "testAddress",
76                 /* speakerLayoutChannelMask= */ speakerLayoutChannelMask,
77                 /* encapsulationModes= */ null,
78                 /* encapsulationMetadataTypes= */ null,
79                 /* descriptors= */ new ArrayList<>());
80     }
81 
82     private final int mType;
83     private final String mAddress;
84     private final int mSpeakerLayoutChannelMask;
85     private final int[] mEncapsulationModes;
86     private final int[] mEncapsulationMetadataTypes;
87 
88     @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)89     AudioDevicePort(AudioHandle handle, String deviceName,
90             int[] samplingRates, int[] channelMasks, int[] channelIndexMasks,
91             int[] formats, AudioGain[] gains, int type, String address, int[] encapsulationModes,
92             @AudioTrack.EncapsulationMetadataType int[] encapsulationMetadataTypes) {
93         super(handle,
94              (AudioManager.isInputDevice(type) == true)  ?
95                         AudioPort.ROLE_SOURCE : AudioPort.ROLE_SINK,
96              deviceName, samplingRates, channelMasks, channelIndexMasks, formats, gains);
97         mType = type;
98         mAddress = address;
99         mSpeakerLayoutChannelMask = AudioFormat.CHANNEL_INVALID;
100         mEncapsulationModes = encapsulationModes;
101         mEncapsulationMetadataTypes = encapsulationMetadataTypes;
102     }
103 
AudioDevicePort( AudioHandle handle, String deviceName, List<AudioProfile> profiles, AudioGain[] gains, int type, String address, int speakerLayoutChannelMask, int[] encapsulationModes, @AudioTrack.EncapsulationMetadataType int[] encapsulationMetadataTypes, List<AudioDescriptor> descriptors)104     AudioDevicePort(
105             AudioHandle handle,
106             String deviceName,
107             List<AudioProfile> profiles,
108             AudioGain[] gains,
109             int type,
110             String address,
111             int speakerLayoutChannelMask,
112             int[] encapsulationModes,
113             @AudioTrack.EncapsulationMetadataType int[] encapsulationMetadataTypes,
114             List<AudioDescriptor> descriptors) {
115         super(handle,
116                 AudioManager.isInputDevice(type) ? AudioPort.ROLE_SOURCE : AudioPort.ROLE_SINK,
117                 deviceName, profiles, gains, descriptors);
118         mType = type;
119         mAddress = address;
120         mSpeakerLayoutChannelMask = speakerLayoutChannelMask;
121         mEncapsulationModes = encapsulationModes;
122         mEncapsulationMetadataTypes = encapsulationMetadataTypes;
123     }
124 
125     /**
126      * Get the device type (e.g AudioManager.DEVICE_OUT_SPEAKER)
127      */
128     @UnsupportedAppUsage
type()129     public int type() {
130         return mType;
131     }
132 
133     /**
134      * Get the device address. Address format varies with the device type.
135      * - USB devices ({@link AudioManager#DEVICE_OUT_USB_DEVICE},
136      * {@link AudioManager#DEVICE_IN_USB_DEVICE}) use an address composed of the ALSA card number
137      * and device number: "card=2;device=1"
138      * - Bluetooth devices ({@link AudioManager#DEVICE_OUT_BLUETOOTH_SCO},
139      * {@link AudioManager#DEVICE_OUT_BLUETOOTH_SCO},
140      * {@link AudioManager#DEVICE_OUT_BLUETOOTH_A2DP}),
141      * {@link AudioManager#DEVICE_OUT_BLE_HEADSET}, {@link AudioManager#DEVICE_OUT_BLE_SPEAKER})
142      * use the MAC address of the bluetooth device in the form "00:11:22:AA:BB:CC" as reported by
143      * {@link BluetoothDevice#getAddress()}.
144      * - Bluetooth LE broadcast group ({@link AudioManager#DEVICE_OUT_BLE_BROADCAST} use the group number.
145      * - Devices that do not have an address will indicate an empty string "".
146      */
address()147     public String address() {
148         return mAddress;
149     }
150 
151     /** Get the channel mask representing the physical output speaker layout of the device.
152      *
153      * The layout channel mask only indicates which speaker channels are present, the
154      * physical layout of the speakers should be informed by a standard for multi-channel
155      * sound playback systems, such as ITU-R BS.2051.
156     */
speakerLayoutChannelMask()157     public int speakerLayoutChannelMask() {
158         return mSpeakerLayoutChannelMask;
159     }
160 
161     /**
162      * Get supported encapsulation modes.
163      */
encapsulationModes()164     public @NonNull @AudioTrack.EncapsulationMode int[] encapsulationModes() {
165         if (mEncapsulationModes == null) {
166             return new int[0];
167         }
168         return Arrays.stream(mEncapsulationModes).boxed()
169                 .filter(mode -> mode != AudioTrack.ENCAPSULATION_MODE_HANDLE)
170                 .mapToInt(Integer::intValue).toArray();
171     }
172 
173     /**
174      * Get supported encapsulation metadata types.
175      */
encapsulationMetadataTypes()176     public @NonNull @AudioTrack.EncapsulationMetadataType int[] encapsulationMetadataTypes() {
177         if (mEncapsulationMetadataTypes == null) {
178             return new int[0];
179         }
180         int[] encapsulationMetadataTypes = new int[mEncapsulationMetadataTypes.length];
181         System.arraycopy(mEncapsulationMetadataTypes, 0,
182                          encapsulationMetadataTypes, 0, mEncapsulationMetadataTypes.length);
183         return encapsulationMetadataTypes;
184     }
185 
186     /**
187      * Build a specific configuration of this audio device port for use by methods
188      * like AudioManager.connectAudioPatch().
189      */
buildConfig(int samplingRate, int channelMask, int format, AudioGainConfig gain)190     public AudioDevicePortConfig buildConfig(int samplingRate, int channelMask, int format,
191                                           AudioGainConfig gain) {
192         return new AudioDevicePortConfig(this, samplingRate, channelMask, format, gain);
193     }
194 
195     @Override
equals(Object o)196     public boolean equals(Object o) {
197         if (o == null || !(o instanceof AudioDevicePort)) {
198             return false;
199         }
200         AudioDevicePort other = (AudioDevicePort)o;
201         if (mType != other.type()) {
202             return false;
203         }
204         if (mAddress == null && other.address() != null) {
205             return false;
206         }
207         if (!mAddress.equals(other.address())) {
208             return false;
209         }
210         return super.equals(o);
211     }
212 
213     /**
214      * Returns true if the AudioDevicePort passed as argument represents the same device (same
215      * type and same address). This is different from equals() in that the port IDs are not compared
216      * which allows matching devices across native audio server restarts.
217      * @param other the other audio device port to compare to.
218      * @return true if both device port correspond to the same audio device, false otherwise.
219      * @hide
220      */
isSameAs(AudioDevicePort other)221     public boolean isSameAs(AudioDevicePort other) {
222         if (mType != other.type()) {
223             return false;
224         }
225         if (mAddress == null && other.address() != null) {
226             return false;
227         }
228         if (!mAddress.equals(other.address())) {
229             return false;
230         }
231         return true;
232     }
233 
234     @Override
toString()235     public String toString() {
236         String type = (mRole == ROLE_SOURCE ?
237                             AudioSystem.getInputDeviceName(mType) :
238                             AudioSystem.getOutputDeviceName(mType));
239         return "{" + super.toString()
240                 + ", mType: " + type
241                 + ", mAddress: " + Utils.anonymizeBluetoothAddress(mType, mAddress)
242                 + "}";
243     }
244 }
245