1 /*
2  * Copyright (C) 2019 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.IntDef;
20 import android.annotation.NonNull;
21 import android.annotation.SystemApi;
22 import android.os.Parcel;
23 import android.os.Parcelable;
24 
25 import java.lang.annotation.Retention;
26 import java.lang.annotation.RetentionPolicy;
27 import java.util.Objects;
28 
29 /**
30  * @hide
31  * Class to represent the attributes of an audio device: its type (speaker, headset...), address
32  * (if known) and role (input, output).
33  * <p>Unlike {@link AudioDeviceInfo}, the device
34  * doesn't need to be connected to be uniquely identified, it can
35  * for instance represent a specific A2DP headset even after a
36  * disconnection, whereas the corresponding <code>AudioDeviceInfo</code>
37  * would then be invalid.
38  * <p>While creating / obtaining an instance is not protected by a
39  * permission, APIs using one rely on MODIFY_AUDIO_ROUTING.
40  */
41 @SystemApi
42 public final class AudioDeviceAttributes implements Parcelable {
43 
44     /**
45      * A role identifying input devices, such as microphones.
46      */
47     public static final int ROLE_INPUT = AudioPort.ROLE_SOURCE;
48     /**
49      * A role identifying output devices, such as speakers or headphones.
50      */
51     public static final int ROLE_OUTPUT = AudioPort.ROLE_SINK;
52 
53     /** @hide */
54     @IntDef(flag = false, prefix = "ROLE_", value = {
55             ROLE_INPUT, ROLE_OUTPUT }
56     )
57     @Retention(RetentionPolicy.SOURCE)
58     public @interface Role {}
59 
60     /**
61      * The audio device type, as defined in {@link AudioDeviceInfo}
62      */
63     private final @AudioDeviceInfo.AudioDeviceType int mType;
64     /**
65      * The unique address of the device. Some devices don't have addresses, only an empty string.
66      */
67     private final @NonNull String mAddress;
68 
69     /**
70      * Is input or output device
71      */
72     private final @Role int mRole;
73 
74     /**
75      * The internal audio device type
76      */
77     private final int mNativeType;
78 
79     /**
80      * @hide
81      * Constructor from a valid {@link AudioDeviceInfo}
82      * @param deviceInfo the connected audio device from which to obtain the device-identifying
83      *                   type and address.
84      */
85     @SystemApi
AudioDeviceAttributes(@onNull AudioDeviceInfo deviceInfo)86     public AudioDeviceAttributes(@NonNull AudioDeviceInfo deviceInfo) {
87         Objects.requireNonNull(deviceInfo);
88         mRole = deviceInfo.isSink() ? ROLE_OUTPUT : ROLE_INPUT;
89         mType = deviceInfo.getType();
90         mAddress = deviceInfo.getAddress();
91         mNativeType = deviceInfo.getInternalType();
92     }
93 
94     /**
95      * @hide
96      * Constructor from role, device type and address
97      * @param role indicates input or output role
98      * @param type the device type, as defined in {@link AudioDeviceInfo}
99      * @param address the address of the device, or an empty string for devices without one
100      */
101     @SystemApi
AudioDeviceAttributes(@ole int role, @AudioDeviceInfo.AudioDeviceType int type, @NonNull String address)102     public AudioDeviceAttributes(@Role int role, @AudioDeviceInfo.AudioDeviceType int type,
103                               @NonNull String address) {
104         Objects.requireNonNull(address);
105         if (role != ROLE_OUTPUT && role != ROLE_INPUT) {
106             throw new IllegalArgumentException("Invalid role " + role);
107         }
108         if (role == ROLE_OUTPUT) {
109             AudioDeviceInfo.enforceValidAudioDeviceTypeOut(type);
110             mNativeType = AudioDeviceInfo.convertDeviceTypeToInternalDevice(type);
111         } else if (role == ROLE_INPUT) {
112             AudioDeviceInfo.enforceValidAudioDeviceTypeIn(type);
113             mNativeType = AudioDeviceInfo.convertDeviceTypeToInternalInputDevice(type);
114         } else {
115             mNativeType = AudioSystem.DEVICE_NONE;
116         }
117 
118         mRole = role;
119         mType = type;
120         mAddress = address;
121     }
122 
123     /**
124      * @hide
125      * Constructor from internal device type and address
126      * @param type the internal device type, as defined in {@link AudioSystem}
127      * @param address the address of the device, or an empty string for devices without one
128      */
AudioDeviceAttributes(int nativeType, @NonNull String address)129     public AudioDeviceAttributes(int nativeType, @NonNull String address) {
130         mRole = (nativeType & AudioSystem.DEVICE_BIT_IN) != 0 ? ROLE_INPUT : ROLE_OUTPUT;
131         mType = AudioDeviceInfo.convertInternalDeviceToDeviceType(nativeType);
132         mAddress = address;
133         mNativeType = nativeType;
134     }
135 
136     /**
137      * @hide
138      * Returns the role of a device
139      * @return the role
140      */
141     @SystemApi
getRole()142     public @Role int getRole() {
143         return mRole;
144     }
145 
146     /**
147      * @hide
148      * Returns the audio device type of a device
149      * @return the type, as defined in {@link AudioDeviceInfo}
150      */
151     @SystemApi
getType()152     public @AudioDeviceInfo.AudioDeviceType int getType() {
153         return mType;
154     }
155 
156     /**
157      * @hide
158      * Returns the address of the audio device, or an empty string for devices without one
159      * @return the device address
160      */
161     @SystemApi
getAddress()162     public @NonNull String getAddress() {
163         return mAddress;
164     }
165 
166     /**
167      * @hide
168      * Returns the internal device type of a device
169      * @return the internal device type
170      */
getInternalType()171     public int getInternalType() {
172         return mNativeType;
173     }
174 
175     @Override
hashCode()176     public int hashCode() {
177         return Objects.hash(mRole, mType, mAddress);
178     }
179 
180     @Override
equals(Object o)181     public boolean equals(Object o) {
182         if (this == o) return true;
183         if (o == null || getClass() != o.getClass()) return false;
184 
185         AudioDeviceAttributes that = (AudioDeviceAttributes) o;
186         return ((mRole == that.mRole)
187                 && (mType == that.mType)
188                 && mAddress.equals(that.mAddress));
189     }
190 
191     /** @hide */
roleToString(@ole int role)192     public static String roleToString(@Role int role) {
193         return (role == ROLE_OUTPUT ? "output" : "input");
194     }
195 
196     @Override
toString()197     public String toString() {
198         return new String("AudioDeviceAttributes:"
199                 + " role:" + roleToString(mRole)
200                 + " type:" + (mRole == ROLE_OUTPUT ? AudioSystem.getOutputDeviceName(mNativeType)
201                         : AudioSystem.getInputDeviceName(mNativeType))
202                 + " addr:" + mAddress);
203     }
204 
205     @Override
describeContents()206     public int describeContents() {
207         return 0;
208     }
209 
210     @Override
writeToParcel(@onNull Parcel dest, int flags)211     public void writeToParcel(@NonNull Parcel dest, int flags) {
212         dest.writeInt(mRole);
213         dest.writeInt(mType);
214         dest.writeString(mAddress);
215         dest.writeInt(mNativeType);
216     }
217 
AudioDeviceAttributes(@onNull Parcel in)218     private AudioDeviceAttributes(@NonNull Parcel in) {
219         mRole = in.readInt();
220         mType = in.readInt();
221         mAddress = in.readString();
222         mNativeType = in.readInt();
223     }
224 
225     public static final @NonNull Parcelable.Creator<AudioDeviceAttributes> CREATOR =
226             new Parcelable.Creator<AudioDeviceAttributes>() {
227         /**
228          * Rebuilds an AudioDeviceAttributes previously stored with writeToParcel().
229          * @param p Parcel object to read the AudioDeviceAttributes from
230          * @return a new AudioDeviceAttributes created from the data in the parcel
231          */
232         public AudioDeviceAttributes createFromParcel(Parcel p) {
233             return new AudioDeviceAttributes(p);
234         }
235 
236         public AudioDeviceAttributes[] newArray(int size) {
237             return new AudioDeviceAttributes[size];
238         }
239     };
240 }
241