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