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
17package android.media;
18
19import android.annotation.IntDef;
20import android.annotation.NonNull;
21import android.util.SparseIntArray;
22
23import java.lang.annotation.Retention;
24import java.lang.annotation.RetentionPolicy;
25import java.util.Objects;
26import java.util.TreeSet;
27
28/**
29 * Class to provide information about the audio devices.
30 */
31public final class AudioDeviceInfo {
32
33    /**
34     * A device type associated with an unknown or uninitialized device.
35     */
36    public static final int TYPE_UNKNOWN          = 0;
37    /**
38     * A device type describing the attached earphone speaker.
39     */
40    public static final int TYPE_BUILTIN_EARPIECE = 1;
41    /**
42     * A device type describing the speaker system (i.e. a mono speaker or stereo speakers) built
43     * in a device.
44     */
45    public static final int TYPE_BUILTIN_SPEAKER  = 2;
46    /**
47     * A device type describing a headset, which is the combination of a headphones and microphone.
48     */
49    public static final int TYPE_WIRED_HEADSET    = 3;
50    /**
51     * A device type describing a pair of wired headphones.
52     */
53    public static final int TYPE_WIRED_HEADPHONES = 4;
54    /**
55     * A device type describing an analog line-level connection.
56     */
57    public static final int TYPE_LINE_ANALOG      = 5;
58    /**
59     * A device type describing a digital line connection (e.g. SPDIF).
60     */
61    public static final int TYPE_LINE_DIGITAL     = 6;
62    /**
63     * A device type describing a Bluetooth device typically used for telephony.
64     */
65    public static final int TYPE_BLUETOOTH_SCO    = 7;
66    /**
67     * A device type describing a Bluetooth device supporting the A2DP profile.
68     */
69    public static final int TYPE_BLUETOOTH_A2DP   = 8;
70    /**
71     * A device type describing an HDMI connection .
72     */
73    public static final int TYPE_HDMI             = 9;
74    /**
75     * A device type describing the Audio Return Channel of an HDMI connection.
76     */
77    public static final int TYPE_HDMI_ARC         = 10;
78    /**
79     * A device type describing a USB audio device.
80     */
81    public static final int TYPE_USB_DEVICE       = 11;
82    /**
83     * A device type describing a USB audio device in accessory mode.
84     */
85    public static final int TYPE_USB_ACCESSORY    = 12;
86    /**
87     * A device type describing the audio device associated with a dock.
88     */
89    public static final int TYPE_DOCK             = 13;
90    /**
91     * A device type associated with the transmission of audio signals over FM.
92     */
93    public static final int TYPE_FM               = 14;
94    /**
95     * A device type describing the microphone(s) built in a device.
96     */
97    public static final int TYPE_BUILTIN_MIC      = 15;
98    /**
99     * A device type for accessing the audio content transmitted over FM.
100     */
101    public static final int TYPE_FM_TUNER         = 16;
102    /**
103     * A device type for accessing the audio content transmitted over the TV tuner system.
104     */
105    public static final int TYPE_TV_TUNER         = 17;
106    /**
107     * A device type describing the transmission of audio signals over the telephony network.
108     */
109    public static final int TYPE_TELEPHONY        = 18;
110    /**
111     * A device type describing the auxiliary line-level connectors.
112     */
113    public static final int TYPE_AUX_LINE         = 19;
114    /**
115     * A device type connected over IP.
116     */
117    public static final int TYPE_IP               = 20;
118    /**
119     * A type-agnostic device used for communication with external audio systems
120     */
121    public static final int TYPE_BUS              = 21;
122    /**
123     * A device type describing a USB audio headset.
124     */
125    public static final int TYPE_USB_HEADSET       = 22;
126    /**
127     * A device type describing a Hearing Aid.
128     */
129    public static final int TYPE_HEARING_AID   = 23;
130
131    /** @hide */
132    @IntDef(flag = false, prefix = "TYPE", value = {
133            TYPE_BUILTIN_EARPIECE,
134            TYPE_BUILTIN_SPEAKER,
135            TYPE_WIRED_HEADSET,
136            TYPE_WIRED_HEADPHONES,
137            TYPE_BLUETOOTH_SCO,
138            TYPE_BLUETOOTH_A2DP,
139            TYPE_HDMI,
140            TYPE_DOCK,
141            TYPE_USB_ACCESSORY,
142            TYPE_USB_DEVICE,
143            TYPE_USB_HEADSET,
144            TYPE_TELEPHONY,
145            TYPE_LINE_ANALOG,
146            TYPE_HDMI_ARC,
147            TYPE_LINE_DIGITAL,
148            TYPE_FM,
149            TYPE_AUX_LINE,
150            TYPE_IP,
151            TYPE_BUS,
152            TYPE_HEARING_AID }
153    )
154    @Retention(RetentionPolicy.SOURCE)
155    public @interface AudioDeviceTypeOut {}
156
157    /** @hide */
158    /*package*/ static boolean isValidAudioDeviceTypeOut(int type) {
159        switch (type) {
160            case TYPE_BUILTIN_EARPIECE:
161            case TYPE_BUILTIN_SPEAKER:
162            case TYPE_WIRED_HEADSET:
163            case TYPE_WIRED_HEADPHONES:
164            case TYPE_BLUETOOTH_SCO:
165            case TYPE_BLUETOOTH_A2DP:
166            case TYPE_HDMI:
167            case TYPE_DOCK:
168            case TYPE_USB_ACCESSORY:
169            case TYPE_USB_DEVICE:
170            case TYPE_USB_HEADSET:
171            case TYPE_TELEPHONY:
172            case TYPE_LINE_ANALOG:
173            case TYPE_HDMI_ARC:
174            case TYPE_LINE_DIGITAL:
175            case TYPE_FM:
176            case TYPE_AUX_LINE:
177            case TYPE_IP:
178            case TYPE_BUS:
179            case TYPE_HEARING_AID:
180                return true;
181            default:
182                return false;
183        }
184    }
185
186    @Override
187    public boolean equals(Object o) {
188        if (this == o) return true;
189        if (o == null || getClass() != o.getClass()) return false;
190        AudioDeviceInfo that = (AudioDeviceInfo) o;
191        return Objects.equals(getPort(), that.getPort());
192    }
193
194    @Override
195    public int hashCode() {
196        return Objects.hash(getPort());
197    }
198
199    private final AudioDevicePort mPort;
200
201    AudioDeviceInfo(AudioDevicePort port) {
202       mPort = port;
203    }
204
205    /**
206     * @hide
207     * @return The underlying {@link AudioDevicePort} instance.
208     */
209    public AudioDevicePort getPort() {
210        return mPort;
211    }
212
213    /**
214     * @return The internal device ID.
215     */
216    public int getId() {
217        return mPort.handle().id();
218    }
219
220    /**
221     * @return The human-readable name of the audio device.
222     */
223    public CharSequence getProductName() {
224        String portName = mPort.name();
225        return portName.length() != 0 ? portName : android.os.Build.MODEL;
226    }
227
228    /**
229     * @return The "address" string of the device. This generally contains device-specific
230     * parameters.
231     */
232    public @NonNull String getAddress() {
233        return mPort.address();
234    }
235
236   /**
237     * @return true if the audio device is a source for audio data (e.e an input).
238     */
239    public boolean isSource() {
240        return mPort.role() == AudioPort.ROLE_SOURCE;
241    }
242
243    /**
244     * @return true if the audio device is a sink for audio data (i.e. an output).
245     */
246    public boolean isSink() {
247        return mPort.role() == AudioPort.ROLE_SINK;
248    }
249
250    /**
251     * @return An array of sample rates supported by the audio device.
252     *
253     * Note: an empty array indicates that the device supports arbitrary rates.
254     */
255    public @NonNull int[] getSampleRates() {
256        return mPort.samplingRates();
257    }
258
259    /**
260     * @return An array of channel position masks (e.g. {@link AudioFormat#CHANNEL_IN_STEREO},
261     * {@link AudioFormat#CHANNEL_OUT_7POINT1}) for which this audio device can be configured.
262     *
263     * @see AudioFormat
264     *
265     * Note: an empty array indicates that the device supports arbitrary channel masks.
266     */
267    public @NonNull int[] getChannelMasks() {
268        return mPort.channelMasks();
269    }
270
271    /**
272     * @return An array of channel index masks for which this audio device can be configured.
273     *
274     * @see AudioFormat
275     *
276     * Note: an empty array indicates that the device supports arbitrary channel index masks.
277     */
278    public @NonNull int[] getChannelIndexMasks() {
279        return mPort.channelIndexMasks();
280    }
281
282    /**
283     * @return An array of channel counts (1, 2, 4, ...) for which this audio device
284     * can be configured.
285     *
286     * Note: an empty array indicates that the device supports arbitrary channel counts.
287     */
288    public @NonNull int[] getChannelCounts() {
289        TreeSet<Integer> countSet = new TreeSet<Integer>();
290
291        // Channel Masks
292        for (int mask : getChannelMasks()) {
293            countSet.add(isSink() ?
294                    AudioFormat.channelCountFromOutChannelMask(mask)
295                    : AudioFormat.channelCountFromInChannelMask(mask));
296        }
297
298        // Index Masks
299        for (int index_mask : getChannelIndexMasks()) {
300            countSet.add(Integer.bitCount(index_mask));
301        }
302
303        int[] counts = new int[countSet.size()];
304        int index = 0;
305        for (int count : countSet) {
306            counts[index++] = count;
307        }
308        return counts;
309    }
310
311    /**
312     * @return An array of audio encodings (e.g. {@link AudioFormat#ENCODING_PCM_16BIT},
313     * {@link AudioFormat#ENCODING_PCM_FLOAT}) supported by the audio device.
314     * <code>ENCODING_PCM_FLOAT</code> indicates the device supports more
315     * than 16 bits of integer precision.  As there is no AudioFormat constant
316     * specifically defined for 24-bit PCM, the value <code>ENCODING_PCM_FLOAT</code>
317     * indicates that {@link AudioTrack} or {@link AudioRecord} can preserve at least 24 bits of
318     * integer precision to that device.
319     *
320     * @see AudioFormat
321     *
322     * Note: an empty array indicates that the device supports arbitrary encodings.
323     */
324    public @NonNull int[] getEncodings() {
325        return AudioFormat.filterPublicFormats(mPort.formats());
326    }
327
328   /**
329     * @return The device type identifier of the audio device (i.e. TYPE_BUILTIN_SPEAKER).
330     */
331    public int getType() {
332        return INT_TO_EXT_DEVICE_MAPPING.get(mPort.type(), TYPE_UNKNOWN);
333    }
334
335    /** @hide */
336    public static int convertDeviceTypeToInternalDevice(int deviceType) {
337        return EXT_TO_INT_DEVICE_MAPPING.get(deviceType, AudioSystem.DEVICE_NONE);
338    }
339
340    /** @hide */
341    public static int convertInternalDeviceToDeviceType(int intDevice) {
342        return INT_TO_EXT_DEVICE_MAPPING.get(intDevice, TYPE_UNKNOWN);
343    }
344
345    private static final SparseIntArray INT_TO_EXT_DEVICE_MAPPING;
346
347    private static final SparseIntArray EXT_TO_INT_DEVICE_MAPPING;
348
349    static {
350        INT_TO_EXT_DEVICE_MAPPING = new SparseIntArray();
351        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_EARPIECE, TYPE_BUILTIN_EARPIECE);
352        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_SPEAKER, TYPE_BUILTIN_SPEAKER);
353        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_WIRED_HEADSET, TYPE_WIRED_HEADSET);
354        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE, TYPE_WIRED_HEADPHONES);
355        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, TYPE_BLUETOOTH_SCO);
356        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET, TYPE_BLUETOOTH_SCO);
357        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT, TYPE_BLUETOOTH_SCO);
358        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, TYPE_BLUETOOTH_A2DP);
359        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES, TYPE_BLUETOOTH_A2DP);
360        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER, TYPE_BLUETOOTH_A2DP);
361        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_HDMI, TYPE_HDMI);
362        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET, TYPE_DOCK);
363        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET, TYPE_DOCK);
364        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_USB_ACCESSORY, TYPE_USB_ACCESSORY);
365        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_USB_DEVICE, TYPE_USB_DEVICE);
366        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_USB_HEADSET, TYPE_USB_HEADSET);
367        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_TELEPHONY_TX, TYPE_TELEPHONY);
368        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_LINE, TYPE_LINE_ANALOG);
369        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_HDMI_ARC, TYPE_HDMI_ARC);
370        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_SPDIF, TYPE_LINE_DIGITAL);
371        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_FM, TYPE_FM);
372        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_AUX_LINE, TYPE_AUX_LINE);
373        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_IP, TYPE_IP);
374        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BUS, TYPE_BUS);
375        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_HEARING_AID, TYPE_HEARING_AID);
376
377        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BUILTIN_MIC, TYPE_BUILTIN_MIC);
378        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET, TYPE_BLUETOOTH_SCO);
379        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_WIRED_HEADSET, TYPE_WIRED_HEADSET);
380        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_HDMI, TYPE_HDMI);
381        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_TELEPHONY_RX, TYPE_TELEPHONY);
382        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BACK_MIC, TYPE_BUILTIN_MIC);
383        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_ANLG_DOCK_HEADSET, TYPE_DOCK);
384        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_DGTL_DOCK_HEADSET, TYPE_DOCK);
385        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_USB_ACCESSORY, TYPE_USB_ACCESSORY);
386        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_USB_DEVICE, TYPE_USB_DEVICE);
387        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_USB_HEADSET, TYPE_USB_HEADSET);
388        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_FM_TUNER, TYPE_FM_TUNER);
389        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_TV_TUNER, TYPE_TV_TUNER);
390        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_LINE, TYPE_LINE_ANALOG);
391        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_SPDIF, TYPE_LINE_DIGITAL);
392        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, TYPE_BLUETOOTH_A2DP);
393        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_IP, TYPE_IP);
394        INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BUS, TYPE_BUS);
395
396        // not covered here, legacy
397        //AudioSystem.DEVICE_OUT_REMOTE_SUBMIX
398        //AudioSystem.DEVICE_IN_REMOTE_SUBMIX
399
400        // privileges mapping to output device
401        EXT_TO_INT_DEVICE_MAPPING = new SparseIntArray();
402        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BUILTIN_EARPIECE, AudioSystem.DEVICE_OUT_EARPIECE);
403        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BUILTIN_SPEAKER, AudioSystem.DEVICE_OUT_SPEAKER);
404        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_WIRED_HEADSET, AudioSystem.DEVICE_OUT_WIRED_HEADSET);
405        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_WIRED_HEADPHONES, AudioSystem.DEVICE_OUT_WIRED_HEADPHONE);
406        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_LINE_ANALOG, AudioSystem.DEVICE_OUT_LINE);
407        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_LINE_DIGITAL, AudioSystem.DEVICE_OUT_SPDIF);
408        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BLUETOOTH_SCO, AudioSystem.DEVICE_OUT_BLUETOOTH_SCO);
409        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BLUETOOTH_A2DP, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
410        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_HDMI, AudioSystem.DEVICE_OUT_HDMI);
411        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_HDMI_ARC, AudioSystem.DEVICE_OUT_HDMI_ARC);
412        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_USB_DEVICE, AudioSystem.DEVICE_OUT_USB_DEVICE);
413        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_USB_HEADSET, AudioSystem.DEVICE_OUT_USB_HEADSET);
414        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_USB_ACCESSORY, AudioSystem.DEVICE_OUT_USB_ACCESSORY);
415        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_DOCK, AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET);
416        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_FM, AudioSystem.DEVICE_OUT_FM);
417        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BUILTIN_MIC, AudioSystem.DEVICE_IN_BUILTIN_MIC);
418        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_FM_TUNER, AudioSystem.DEVICE_IN_FM_TUNER);
419        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_TV_TUNER, AudioSystem.DEVICE_IN_TV_TUNER);
420        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_TELEPHONY, AudioSystem.DEVICE_OUT_TELEPHONY_TX);
421        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_AUX_LINE, AudioSystem.DEVICE_OUT_AUX_LINE);
422        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_IP, AudioSystem.DEVICE_OUT_IP);
423        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BUS, AudioSystem.DEVICE_OUT_BUS);
424        EXT_TO_INT_DEVICE_MAPPING.put(TYPE_HEARING_AID, AudioSystem.DEVICE_OUT_HEARING_AID);
425    }
426}
427
428