1 /*
2  * Copyright (C) 2020 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 com.android.libraries.tv.tvsystem.media;
18 
19 import android.annotation.IntDef;
20 import android.annotation.NonNull;
21 import android.annotation.SystemApi;
22 import android.media.AudioDeviceInfo;
23 import android.media.AudioPort;
24 import android.media.AudioSystem;
25 
26 import java.lang.annotation.Retention;
27 import java.lang.annotation.RetentionPolicy;
28 import java.util.Objects;
29 
30 /**
31  * @hide
32  * Class to represent the attributes of an audio device: its type (speaker, headset...), address
33  * (if known) and role (input, output).
34  * <p>Unlike {@link AudioDeviceInfo}, the device
35  * doesn't need to be connected to be uniquely identified, it can
36  * for instance represent a specific A2DP headset even after a
37  * disconnection, whereas the corresponding <code>AudioDeviceInfo</code>
38  * would then be invalid.
39  * <p>While creating / obtaining an instance is not protected by a
40  * permission, APIs using one rely on MODIFY_AUDIO_ROUTING.
41  */
42 @SystemApi
43 public final class AudioDeviceAttributes {
44 
45     /**
46      * A role identifying input devices, such as microphones.
47      */
48     public static final int ROLE_INPUT = AudioPort.ROLE_SOURCE;
49     /**
50      * A role identifying output devices, such as speakers or headphones.
51      */
52     public static final int ROLE_OUTPUT = AudioPort.ROLE_SINK;
53 
54     /** @hide */
55     @IntDef(flag = false, prefix = "ROLE_", value = {
56             ROLE_INPUT, ROLE_OUTPUT }
57     )
58     @Retention(RetentionPolicy.SOURCE)
59     public @interface Role {}
60 
61     /**
62      * The audio device type, as defined in {@link AudioDeviceInfo}
63      */
64     private final @AudioDeviceInfo.AudioDeviceType int mType;
65     /**
66      * The unique address of the device. Some devices don't have addresses, only an empty string.
67      */
68     private final @NonNull String mAddress;
69 
70     /**
71      * Is input or output device
72      */
73     private final @AudioDeviceAttributes.Role
74     int mRole;
75 
76     /**
77      * @hide
78      * Constructor from a valid {@link AudioDeviceInfo}
79      * @param deviceInfo the connected audio device from which to obtain the device-identifying
80      *                   type and address.
81      */
82     @SystemApi
AudioDeviceAttributes(@onNull AudioDeviceInfo deviceInfo)83     public AudioDeviceAttributes(@NonNull AudioDeviceInfo deviceInfo) {
84         Objects.requireNonNull(deviceInfo);
85         mRole = deviceInfo.isSink() ? ROLE_OUTPUT : ROLE_INPUT;
86         mType = deviceInfo.getType();
87         mAddress = deviceInfo.getAddress();
88     }
89 
90     /**
91      * @hide
92      * Constructor from role, device type and address
93      * @param role indicates input or output role
94      * @param type the device type, as defined in {@link AudioDeviceInfo}
95      * @param address the address of the device, or an empty string for devices without one
96      */
97     @SystemApi
AudioDeviceAttributes(@udioDeviceAttributes.Role int role, @AudioDeviceInfo.AudioDeviceType int type, @NonNull String address)98     public AudioDeviceAttributes(@AudioDeviceAttributes.Role int role,
99             @AudioDeviceInfo.AudioDeviceType int type,
100             @NonNull String address) {
101         Objects.requireNonNull(address);
102         if (role != ROLE_OUTPUT && role != ROLE_INPUT) {
103             throw new IllegalArgumentException("Invalid role " + role);
104         }
105 
106         mRole = role;
107         mType = type;
108         mAddress = address;
109     }
110 
AudioDeviceAttributes(int nativeType, @NonNull String address)111     /*package*/ AudioDeviceAttributes(int nativeType, @NonNull String address) {
112         mRole = (nativeType & AudioSystem.DEVICE_BIT_IN) != 0 ? ROLE_INPUT : ROLE_OUTPUT;
113         mType = AudioDeviceInfo.convertInternalDeviceToDeviceType(nativeType);
114         mAddress = address;
115     }
116 
117     /**
118      * @hide
119      * Returns the role of a device
120      * @return the role
121      */
122     @SystemApi
123     public @AudioDeviceAttributes.Role
getRole()124     int getRole() {
125         return mRole;
126     }
127 
128     /**
129      * @hide
130      * Returns the audio device type of a device
131      * @return the type, as defined in {@link AudioDeviceInfo}
132      */
133     @SystemApi
getType()134     public @AudioDeviceInfo.AudioDeviceType int getType() {
135         return mType;
136     }
137 
138     /**
139      * @hide
140      * Returns the address of the audio device, or an empty string for devices without one
141      * @return the device address
142      */
143     @SystemApi
getAddress()144     public @NonNull String getAddress() {
145         return mAddress;
146     }
147 
148     @Override
hashCode()149     public int hashCode() {
150         return Objects.hash(mRole, mType, mAddress);
151     }
152 
153     @Override
equals(Object o)154     public boolean equals(Object o) {
155         if (this == o) return true;
156         if (o == null || getClass() != o.getClass()) return false;
157 
158         AudioDeviceAttributes that = (AudioDeviceAttributes) o;
159         return ((mRole == that.mRole)
160                 && (mType == that.mType)
161                 && mAddress.equals(that.mAddress));
162     }
163 
164     /** @hide */
roleToString(@udioDeviceAttributes.Role int role)165     public static String roleToString(@AudioDeviceAttributes.Role int role) {
166         return (role == ROLE_OUTPUT ? "output" : "input");
167     }
168 
169     @Override
toString()170     public String toString() {
171         return new String("AudioDeviceAttributes:"
172                 + " role:" + roleToString(mRole)
173                 + " type:" + (mRole == ROLE_OUTPUT ? AudioSystem.getOutputDeviceName(
174                 AudioDeviceInfo.convertDeviceTypeToInternalDevice(mType))
175                 : AudioSystem.getInputDeviceName(
176                         AudioDeviceInfo.convertDeviceTypeToInternalDevice(mType)))
177                 + " addr:" + mAddress);
178     }
179 }
180