1 /*
2  * Copyright (C) 2018 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.compat.annotation.UnsupportedAppUsage;
22 import android.util.Pair;
23 
24 import java.lang.annotation.Retention;
25 import java.lang.annotation.RetentionPolicy;
26 import java.util.List;
27 
28 /**
29  * Class providing information on a microphone. It indicates the location and orientation of the
30  * microphone on the device as well as useful information like frequency response and sensitivity.
31  * It can be used by applications implementing special pre processing effects like noise suppression
32  * of beam forming that need to know about precise microphone characteristics in order to adapt
33  * their algorithms.
34  */
35 public final class MicrophoneInfo {
36 
37     /**
38      * A microphone that the location is unknown.
39      */
40     public static final int LOCATION_UNKNOWN = 0;
41 
42     /**
43      * A microphone that locate on main body of the device.
44      */
45     public static final int LOCATION_MAINBODY = 1;
46 
47     /**
48      * A microphone that locate on a movable main body of the device.
49      */
50     public static final int LOCATION_MAINBODY_MOVABLE = 2;
51 
52     /**
53      * A microphone that locate on a peripheral.
54      */
55     public static final int LOCATION_PERIPHERAL = 3;
56 
57     /**
58      * Unknown microphone directionality.
59      */
60     public static final int DIRECTIONALITY_UNKNOWN = 0;
61 
62     /**
63      * Microphone directionality type: omni.
64      */
65     public static final int DIRECTIONALITY_OMNI = 1;
66 
67     /**
68      * Microphone directionality type: bi-directional.
69      */
70     public static final int DIRECTIONALITY_BI_DIRECTIONAL = 2;
71 
72     /**
73      * Microphone directionality type: cardioid.
74      */
75     public static final int DIRECTIONALITY_CARDIOID = 3;
76 
77     /**
78      * Microphone directionality type: hyper cardioid.
79      */
80     public static final int DIRECTIONALITY_HYPER_CARDIOID = 4;
81 
82     /**
83      * Microphone directionality type: super cardioid.
84      */
85     public static final int DIRECTIONALITY_SUPER_CARDIOID = 5;
86 
87     /**
88      * The channel contains raw audio from this microphone.
89      */
90     public static final int CHANNEL_MAPPING_DIRECT = 1;
91 
92     /**
93      * The channel contains processed audio from this microphone and possibly another microphone.
94      */
95     public static final int CHANNEL_MAPPING_PROCESSED = 2;
96 
97     /**
98      * Value used for when the group of the microphone is unknown.
99      */
100     public static final int GROUP_UNKNOWN = -1;
101 
102     /**
103      * Value used for when the index in the group of the microphone is unknown.
104      */
105     public static final int INDEX_IN_THE_GROUP_UNKNOWN = -1;
106 
107     /**
108      * Value used for when the position of the microphone is unknown.
109      */
110     public static final Coordinate3F POSITION_UNKNOWN = new Coordinate3F(
111             -Float.MAX_VALUE, -Float.MAX_VALUE, -Float.MAX_VALUE);
112 
113     /**
114      * Value used for when the orientation of the microphone is unknown.
115      */
116     public static final Coordinate3F ORIENTATION_UNKNOWN = new Coordinate3F(0.0f, 0.0f, 0.0f);
117 
118     /**
119      * Value used for when the sensitivity of the microphone is unknown.
120      */
121     public static final float SENSITIVITY_UNKNOWN = -Float.MAX_VALUE;
122 
123     /**
124      * Value used for when the SPL of the microphone is unknown. This value could be used when
125      * maximum SPL or minimum SPL is unknown.
126      */
127     public static final float SPL_UNKNOWN = -Float.MAX_VALUE;
128 
129     /** @hide */
130     @IntDef(flag = true, prefix = { "LOCATION_" }, value = {
131             LOCATION_UNKNOWN,
132             LOCATION_MAINBODY,
133             LOCATION_MAINBODY_MOVABLE,
134             LOCATION_PERIPHERAL,
135     })
136     @Retention(RetentionPolicy.SOURCE)
137     public @interface MicrophoneLocation {}
138 
139     /** @hide */
140     @IntDef(flag = true, prefix = { "DIRECTIONALITY_" }, value = {
141             DIRECTIONALITY_UNKNOWN,
142             DIRECTIONALITY_OMNI,
143             DIRECTIONALITY_BI_DIRECTIONAL,
144             DIRECTIONALITY_CARDIOID,
145             DIRECTIONALITY_HYPER_CARDIOID,
146             DIRECTIONALITY_SUPER_CARDIOID,
147     })
148     @Retention(RetentionPolicy.SOURCE)
149     public @interface MicrophoneDirectionality {}
150 
151     private Coordinate3F mPosition;
152     private Coordinate3F mOrientation;
153     private String mDeviceId;
154     private String mAddress;
155     private List<Pair<Float, Float>> mFrequencyResponse;
156     private List<Pair<Integer, Integer>> mChannelMapping;
157     private float mMaxSpl;
158     private float mMinSpl;
159     private float mSensitivity;
160     private int mLocation;
161     private int mGroup; /* Usually 0 will be used for main body. */
162     private int mIndexInTheGroup;
163     private int mPortId; /* mPortId will correspond to the id in AudioPort */
164     private int mType;
165     private int mDirectionality;
166 
167     @UnsupportedAppUsage
MicrophoneInfo(String deviceId, int type, String address, int location, int group, int indexInTheGroup, Coordinate3F position, Coordinate3F orientation, List<Pair<Float, Float>> frequencyResponse, List<Pair<Integer, Integer>> channelMapping, float sensitivity, float maxSpl, float minSpl, int directionality)168     MicrophoneInfo(String deviceId, int type, String address, int location,
169             int group, int indexInTheGroup, Coordinate3F position,
170             Coordinate3F orientation, List<Pair<Float, Float>> frequencyResponse,
171             List<Pair<Integer, Integer>> channelMapping, float sensitivity, float maxSpl,
172             float minSpl, int directionality) {
173         mDeviceId = deviceId;
174         mType = type;
175         mAddress = address;
176         mLocation = location;
177         mGroup = group;
178         mIndexInTheGroup = indexInTheGroup;
179         mPosition = position;
180         mOrientation = orientation;
181         mFrequencyResponse = frequencyResponse;
182         mChannelMapping = channelMapping;
183         mSensitivity = sensitivity;
184         mMaxSpl = maxSpl;
185         mMinSpl = minSpl;
186         mDirectionality = directionality;
187     }
188 
189     /**
190      * Returns alphanumeric code that uniquely identifies the device.
191      *
192      * @return the description of the microphone
193      */
getDescription()194     public String getDescription() {
195         return mDeviceId;
196     }
197 
198     /**
199      * Returns The system unique device ID that corresponds to the id
200      * returned by {@link AudioDeviceInfo#getId()}.
201      *
202      * @return the microphone's id
203      */
getId()204     public int getId() {
205         return mPortId;
206     }
207 
208     /**
209      * @hide
210      * Returns the internal device type (e.g AudioSystem.DEVICE_IN_BUILTIN_MIC).
211      * The internal device type could be used when getting microphone's port id
212      * by matching type and address.
213      *
214      * @return the internal device type
215      */
getInternalDeviceType()216     public int getInternalDeviceType() {
217         return mType;
218     }
219 
220     /**
221      * Returns the device type identifier of the microphone (e.g AudioDeviceInfo.TYPE_BUILTIN_MIC).
222      *
223      * @return the device type of the microphone
224      */
getType()225     public int getType() {
226         return AudioDeviceInfo.convertInternalDeviceToDeviceType(mType);
227     }
228 
229     /**
230      * Returns The "address" string of the microphone that corresponds to the
231      * address returned by {@link AudioDeviceInfo#getAddress()}
232      * @return the address of the microphone
233      */
getAddress()234     public @NonNull String getAddress() {
235         return mAddress;
236     }
237 
238     /**
239      * Returns the location of the microphone. The return value is
240      * one of {@link #LOCATION_UNKNOWN}, {@link #LOCATION_MAINBODY},
241      * {@link #LOCATION_MAINBODY_MOVABLE}, or {@link #LOCATION_PERIPHERAL}.
242      *
243      * @return the location of the microphone
244      */
getLocation()245     public @MicrophoneLocation int getLocation() {
246         return mLocation;
247     }
248 
249     /**
250      * Returns A device group id that can be used to group together microphones on the same
251      * peripheral, attachments or logical groups. Main body is usually group 0.
252      *
253      * @return the group of the microphone or {@link #GROUP_UNKNOWN} if the group is unknown
254      */
getGroup()255     public int getGroup() {
256         return mGroup;
257     }
258 
259     /**
260      * Returns unique index for device within its group.
261      *
262      * @return the microphone's index in its group or {@link #INDEX_IN_THE_GROUP_UNKNOWN} if the
263      * index in the group is unknown
264      */
getIndexInTheGroup()265     public int getIndexInTheGroup() {
266         return mIndexInTheGroup;
267     }
268 
269     /**
270      * Returns A {@link Coordinate3F} object that represents the geometric location of microphone
271      * in meters, from bottom-left-back corner of appliance. X-axis, Y-axis and Z-axis show
272      * as the x, y, z values.
273      *
274      * @return the geometric location of the microphone or {@link #POSITION_UNKNOWN} if the
275      * geometric location is unknown
276      */
getPosition()277     public Coordinate3F getPosition() {
278         return mPosition;
279     }
280 
281     /**
282      * Returns A {@link Coordinate3F} object that represents the orientation of microphone.
283      * X-axis, Y-axis and Z-axis show as the x, y, z value. The orientation will be normalized
284      * such as sqrt(x^2 + y^2 + z^2) equals 1.
285      *
286      * @return the orientation of the microphone or {@link #ORIENTATION_UNKNOWN} if orientation
287      * is unknown
288      */
getOrientation()289     public Coordinate3F getOrientation() {
290         return mOrientation;
291     }
292 
293     /**
294      * Returns a {@link android.util.Pair} list of frequency responses.
295      * For every {@link android.util.Pair} in the list, the first value represents frequency in Hz,
296      * and the second value represents response in dB.
297      *
298      * @return the frequency response of the microphone
299      */
getFrequencyResponse()300     public List<Pair<Float, Float>> getFrequencyResponse() {
301         return mFrequencyResponse;
302     }
303 
304     /**
305      * Returns a {@link android.util.Pair} list for channel mapping, which indicating how this
306      * microphone is used by each channels or a capture stream. For each {@link android.util.Pair},
307      * the first value is channel index, the second value is channel mapping type, which could be
308      * either {@link #CHANNEL_MAPPING_DIRECT} or {@link #CHANNEL_MAPPING_PROCESSED}.
309      * If a channel has contributions from more than one microphone, it is likely the HAL
310      * did some extra processing to combine the sources, but this is to be inferred by the user.
311      * Empty list when the MicrophoneInfo is returned by AudioManager.getMicrophones().
312      * At least one entry when the MicrophoneInfo is returned by AudioRecord.getActiveMicrophones().
313      *
314      * @return a {@link android.util.Pair} list for channel mapping
315      */
getChannelMapping()316     public List<Pair<Integer, Integer>> getChannelMapping() {
317         return mChannelMapping;
318     }
319 
320     /**
321      * Returns the level in dBFS produced by a 1000Hz tone at 94 dB SPL.
322      *
323      * @return the sensitivity of the microphone or {@link #SENSITIVITY_UNKNOWN} if the sensitivity
324      * is unknown
325      */
getSensitivity()326     public float getSensitivity() {
327         return mSensitivity;
328     }
329 
330     /**
331      * Returns the level in dB of the maximum SPL supported by the device at 1000Hz.
332      *
333      * @return the maximum level in dB or {@link #SPL_UNKNOWN} if maximum SPL is unknown
334      */
getMaxSpl()335     public float getMaxSpl() {
336         return mMaxSpl;
337     }
338 
339     /**
340      * Returns the level in dB of the minimum SPL that can be registered by the device at 1000Hz.
341      *
342      * @return the minimum level in dB or {@link #SPL_UNKNOWN} if minimum SPL is unknown
343      */
getMinSpl()344     public float getMinSpl() {
345         return mMinSpl;
346     }
347 
348     /**
349      * Returns the directionality of microphone. The return value is one of
350      * {@link #DIRECTIONALITY_UNKNOWN}, {@link #DIRECTIONALITY_OMNI},
351      * {@link #DIRECTIONALITY_BI_DIRECTIONAL}, {@link #DIRECTIONALITY_CARDIOID},
352      * {@link #DIRECTIONALITY_HYPER_CARDIOID}, or {@link #DIRECTIONALITY_SUPER_CARDIOID}.
353      *
354      * @return the directionality of microphone
355      */
getDirectionality()356     public @MicrophoneDirectionality int getDirectionality() {
357         return mDirectionality;
358     }
359 
360     /**
361      * Set the port id for the device.
362      * @hide
363      */
setId(int portId)364     public void setId(int portId) {
365         mPortId = portId;
366     }
367 
368     /**
369      * Set the channel mapping for the device.
370      * @hide
371      */
setChannelMapping(List<Pair<Integer, Integer>> channelMapping)372     public void setChannelMapping(List<Pair<Integer, Integer>> channelMapping) {
373         mChannelMapping = channelMapping;
374     }
375 
376     /* A class containing three float value to represent a 3D coordinate */
377     public static final class Coordinate3F {
378         public final float x;
379         public final float y;
380         public final float z;
381 
Coordinate3F(float x, float y, float z)382         Coordinate3F(float x, float y, float z) {
383             this.x = x;
384             this.y = y;
385             this.z = z;
386         }
387 
388         @Override
equals(Object obj)389         public boolean equals(Object obj) {
390             if (this == obj) {
391                 return true;
392             }
393             if (!(obj instanceof Coordinate3F)) {
394                 return false;
395             }
396             Coordinate3F other = (Coordinate3F) obj;
397             return this.x == other.x && this.y == other.y && this.z == other.z;
398         }
399     }
400 }
401