Add support for getting all available microphones characteristics.
Add MicrophoneInfo to represent the microphone characteristics which including location, orientation, frequency response, sensitivity, channel mapping and other useful information. Add a new API in AudioManager to query all current available microphones. Bug: 64038649 Test: Run test and check the print log. Change-Id: Ie0dbfeeb84b88db426518b93c7bb83c8913bca85
This commit is contained in:
@@ -21917,6 +21917,7 @@ package android.media {
|
||||
method public java.util.List<android.media.AudioPlaybackConfiguration> getActivePlaybackConfigurations();
|
||||
method public java.util.List<android.media.AudioRecordingConfiguration> getActiveRecordingConfigurations();
|
||||
method public android.media.AudioDeviceInfo[] getDevices(int);
|
||||
method public java.util.List<android.media.MicrophoneInfo> getMicrophones() throws java.io.IOException;
|
||||
method public int getMode();
|
||||
method public java.lang.String getParameters(java.lang.String);
|
||||
method public java.lang.String getProperty(java.lang.String);
|
||||
@@ -24411,6 +24412,41 @@ package android.media {
|
||||
method public float getMediaClockRate();
|
||||
}
|
||||
|
||||
public final class MicrophoneInfo {
|
||||
method public java.util.List<android.util.Pair<java.lang.Integer, java.lang.Integer>> getChannelMapping();
|
||||
method public java.lang.String getDescription();
|
||||
method public int getDirectionality();
|
||||
method public java.util.List<android.util.Pair<java.lang.Float, java.lang.Float>> getFrequencyResponse();
|
||||
method public int getGroup();
|
||||
method public int getId();
|
||||
method public int getIndexInTheGroup();
|
||||
method public int getLocation();
|
||||
method public float getMaxSpl();
|
||||
method public float getMinSpl();
|
||||
method public android.media.MicrophoneInfo.Coordinate3F getOrientation();
|
||||
method public android.media.MicrophoneInfo.Coordinate3F getPosition();
|
||||
method public float getSensitivity();
|
||||
method public int getType();
|
||||
field public static final int CHANNEL_MAPPING_DIRECT = 1; // 0x1
|
||||
field public static final int CHANNEL_MAPPING_PROCESSED = 2; // 0x2
|
||||
field public static final int DIRECTIONALITY_BI_DIRECTIONAL = 2; // 0x2
|
||||
field public static final int DIRECTIONALITY_CARDIOID = 3; // 0x3
|
||||
field public static final int DIRECTIONALITY_HYPER_CARDIOID = 4; // 0x4
|
||||
field public static final int DIRECTIONALITY_OMNI = 1; // 0x1
|
||||
field public static final int DIRECTIONALITY_SUPER_CARDIOID = 5; // 0x5
|
||||
field public static final int DIRECTIONALITY_UNKNOW = 0; // 0x0
|
||||
field public static final int LOCATION_MAINBODY = 1; // 0x1
|
||||
field public static final int LOCATION_MAINBODY_MOVABLE = 2; // 0x2
|
||||
field public static final int LOCATION_PERIPHERAL = 3; // 0x3
|
||||
field public static final int LOCATION_UNKNOWN = 0; // 0x0
|
||||
}
|
||||
|
||||
public class MicrophoneInfo.Coordinate3F {
|
||||
field public final float x;
|
||||
field public final float y;
|
||||
field public final float z;
|
||||
}
|
||||
|
||||
public final class NotProvisionedException extends android.media.MediaDrmException {
|
||||
ctor public NotProvisionedException(java.lang.String);
|
||||
}
|
||||
|
||||
@@ -164,6 +164,7 @@ cc_library_shared {
|
||||
"android_media_DeviceCallback.cpp",
|
||||
"android_media_JetPlayer.cpp",
|
||||
"android_media_MediaMetricsJNI.cpp",
|
||||
"android_media_MicrophoneInfo.cpp",
|
||||
"android_media_RemoteDisplay.cpp",
|
||||
"android_media_ToneGenerator.cpp",
|
||||
"android_hardware_Camera.cpp",
|
||||
|
||||
@@ -104,6 +104,7 @@ extern int register_android_hardware_location_ActivityRecognitionHardware(JNIEnv
|
||||
extern int register_android_media_AudioRecord(JNIEnv *env);
|
||||
extern int register_android_media_AudioSystem(JNIEnv *env);
|
||||
extern int register_android_media_AudioTrack(JNIEnv *env);
|
||||
extern int register_android_media_MicrophoneInfo(JNIEnv *env);
|
||||
extern int register_android_media_JetPlayer(JNIEnv *env);
|
||||
extern int register_android_media_ToneGenerator(JNIEnv *env);
|
||||
|
||||
@@ -1457,6 +1458,7 @@ static const RegJNIRec gRegJNI[] = {
|
||||
REG_JNI(register_android_media_AudioSystem),
|
||||
REG_JNI(register_android_media_AudioTrack),
|
||||
REG_JNI(register_android_media_JetPlayer),
|
||||
REG_JNI(register_android_media_MicrophoneInfo),
|
||||
REG_JNI(register_android_media_RemoteDisplay),
|
||||
REG_JNI(register_android_media_ToneGenerator),
|
||||
|
||||
|
||||
@@ -21,17 +21,20 @@
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <jni.h>
|
||||
#include <nativehelper/JNIHelp.h>
|
||||
#include "core_jni_helpers.h"
|
||||
|
||||
#include <media/AudioSystem.h>
|
||||
#include <media/AudioPolicy.h>
|
||||
#include <media/MicrophoneInfo.h>
|
||||
#include <nativehelper/ScopedLocalRef.h>
|
||||
#include <system/audio.h>
|
||||
#include <system/audio_policy.h>
|
||||
#include "android_media_AudioFormat.h"
|
||||
#include "android_media_AudioErrors.h"
|
||||
#include "android_media_MicrophoneInfo.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@@ -143,7 +146,6 @@ static struct {
|
||||
jfieldID mSource;
|
||||
} gAudioAttributesFields;
|
||||
|
||||
|
||||
static const char* const kEventHandlerClassPathName =
|
||||
"android/media/AudioPortEventHandler";
|
||||
static struct {
|
||||
@@ -1158,7 +1160,6 @@ exit:
|
||||
return jStatus;
|
||||
}
|
||||
|
||||
|
||||
static jint
|
||||
android_media_AudioSystem_listAudioPorts(JNIEnv *env, jobject clazz,
|
||||
jobject jPorts, jintArray jGeneration)
|
||||
@@ -1789,6 +1790,45 @@ android_media_AudioSystem_isOffloadSupported(JNIEnv *env, jobject thiz,
|
||||
return AudioSystem::isOffloadSupported(format);
|
||||
}
|
||||
|
||||
static jint
|
||||
android_media_AudioSystem_getMicrophones(JNIEnv *env, jobject thiz, jobject jMicrophonesInfo)
|
||||
{
|
||||
ALOGV("getMicrophones");
|
||||
|
||||
if (jMicrophonesInfo == NULL) {
|
||||
ALOGE("jMicrophonesInfo NULL MicrophoneInfo ArrayList");
|
||||
return (jint)AUDIO_JAVA_BAD_VALUE;
|
||||
}
|
||||
if (!env->IsInstanceOf(jMicrophonesInfo, gArrayListClass)) {
|
||||
ALOGE("getMicrophones not an arraylist");
|
||||
return (jint)AUDIO_JAVA_BAD_VALUE;
|
||||
}
|
||||
|
||||
jint jStatus;
|
||||
std::vector<media::MicrophoneInfo> microphones;
|
||||
status_t status = AudioSystem::getMicrophones(µphones);
|
||||
if (status != NO_ERROR) {
|
||||
ALOGE_IF(status != NO_ERROR, "AudioSystem::getMicrophones error %d", status);
|
||||
jStatus = nativeToJavaStatus(status);
|
||||
return jStatus;
|
||||
}
|
||||
if (microphones.size() == 0) {
|
||||
jStatus = (jint)AUDIO_JAVA_SUCCESS;
|
||||
return jStatus;
|
||||
}
|
||||
for (size_t i = 0; i < microphones.size(); i++) {
|
||||
jobject jMicrophoneInfo;
|
||||
jStatus = convertMicrophoneInfoFromNative(env, &jMicrophoneInfo, µphones[i]);
|
||||
if (jStatus != AUDIO_JAVA_SUCCESS) {
|
||||
return jStatus;
|
||||
}
|
||||
env->CallBooleanMethod(jMicrophonesInfo, gArrayListMethods.add, jMicrophoneInfo);
|
||||
env->DeleteLocalRef(jMicrophoneInfo);
|
||||
}
|
||||
|
||||
return jStatus;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static const JNINativeMethod gMethods[] = {
|
||||
@@ -1843,6 +1883,7 @@ static const JNINativeMethod gMethods[] = {
|
||||
{"systemReady", "()I", (void *)android_media_AudioSystem_systemReady},
|
||||
{"getStreamVolumeDB", "(III)F", (void *)android_media_AudioSystem_getStreamVolumeDB},
|
||||
{"native_is_offload_supported", "(IIII)Z", (void *)android_media_AudioSystem_isOffloadSupported},
|
||||
{"getMicrophones", "(Ljava/util/ArrayList;)I", (void *)android_media_AudioSystem_getMicrophones},
|
||||
};
|
||||
|
||||
|
||||
|
||||
187
core/jni/android_media_MicrophoneInfo.cpp
Normal file
187
core/jni/android_media_MicrophoneInfo.cpp
Normal file
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "android_media_MicrophoneInfo.h"
|
||||
#include "android_media_AudioErrors.h"
|
||||
#include "core_jni_helpers.h"
|
||||
|
||||
using namespace android;
|
||||
|
||||
static jclass gArrayListClass;
|
||||
static jmethodID gArrayListCstor;
|
||||
static struct {
|
||||
jmethodID add;
|
||||
} gArrayListMethods;
|
||||
|
||||
static jclass gFloatClass;
|
||||
static jmethodID gFloatCstor;
|
||||
|
||||
static jclass gFloatArrayClass;
|
||||
|
||||
static jclass gIntegerClass;
|
||||
static jmethodID gIntegerCstor;
|
||||
|
||||
static jclass gMicrophoneInfoClass;
|
||||
static jmethodID gMicrophoneInfoCstor;
|
||||
|
||||
static jclass gMicrophoneInfoCoordinateClass;
|
||||
static jmethodID gMicrophoneInfoCoordinateCstor;
|
||||
|
||||
static jclass gPairClass;
|
||||
static jmethodID gPairCstor;
|
||||
|
||||
namespace android {
|
||||
|
||||
jint convertMicrophoneInfoFromNative(JNIEnv *env, jobject *jMicrophoneInfo,
|
||||
const media::MicrophoneInfo *microphoneInfo)
|
||||
{
|
||||
jint jStatus = (jint)AUDIO_JAVA_SUCCESS;
|
||||
jstring jDeviceId = NULL;
|
||||
jstring jAddress = NULL;
|
||||
jobject jGeometricLocation = NULL;
|
||||
jobject jOrientation = NULL;
|
||||
jobject jFrequencyResponses = NULL;
|
||||
jobject jChannelMappings = NULL;
|
||||
|
||||
jDeviceId = env->NewStringUTF(String8(microphoneInfo->getDeviceId()).string());
|
||||
jAddress = env->NewStringUTF(String8(microphoneInfo->getAddress()).string());
|
||||
if (microphoneInfo->getGeometricLocation().size() != 3 ||
|
||||
microphoneInfo->getOrientation().size() != 3) {
|
||||
jStatus = nativeToJavaStatus(BAD_VALUE);
|
||||
goto exit;
|
||||
}
|
||||
jGeometricLocation = env->NewObject(gMicrophoneInfoCoordinateClass,
|
||||
gMicrophoneInfoCoordinateCstor,
|
||||
NULL,
|
||||
microphoneInfo->getGeometricLocation()[0],
|
||||
microphoneInfo->getGeometricLocation()[1],
|
||||
microphoneInfo->getGeometricLocation()[2]);
|
||||
jOrientation = env->NewObject(gMicrophoneInfoCoordinateClass,
|
||||
gMicrophoneInfoCoordinateCstor,
|
||||
NULL,
|
||||
microphoneInfo->getOrientation()[0],
|
||||
microphoneInfo->getOrientation()[1],
|
||||
microphoneInfo->getOrientation()[2]);
|
||||
// Create a list of Pair for frequency response.
|
||||
if (microphoneInfo->getFrequencyResponses().size() != 2 ||
|
||||
microphoneInfo->getFrequencyResponses()[0].size() !=
|
||||
microphoneInfo->getFrequencyResponses()[1].size()) {
|
||||
jStatus = nativeToJavaStatus(BAD_VALUE);
|
||||
goto exit;
|
||||
}
|
||||
jFrequencyResponses = env->NewObject(gArrayListClass, gArrayListCstor);
|
||||
for (size_t i = 0; i < microphoneInfo->getFrequencyResponses()[0].size(); i++) {
|
||||
jobject jFrequency = env->NewObject(gFloatClass, gFloatCstor,
|
||||
microphoneInfo->getFrequencyResponses()[0][i]);
|
||||
jobject jResponse = env->NewObject(gFloatClass, gFloatCstor,
|
||||
microphoneInfo->getFrequencyResponses()[1][i]);
|
||||
jobject jFrequencyResponse = env->NewObject(gPairClass, gPairCstor, jFrequency, jResponse);
|
||||
env->CallBooleanMethod(jFrequencyResponses, gArrayListMethods.add, jFrequencyResponse);
|
||||
env->DeleteLocalRef(jFrequency);
|
||||
env->DeleteLocalRef(jResponse);
|
||||
env->DeleteLocalRef(jFrequencyResponse);
|
||||
}
|
||||
// Create a list of Pair for channel mapping.
|
||||
if (microphoneInfo->getChannelMapping().size() != AUDIO_CHANNEL_COUNT_MAX) {
|
||||
jStatus = nativeToJavaStatus(BAD_VALUE);
|
||||
goto exit;
|
||||
}
|
||||
jChannelMappings = env->NewObject(gArrayListClass, gArrayListCstor);
|
||||
for (size_t i = 0; i < microphoneInfo->getChannelMapping().size(); i++) {
|
||||
int channelMappingType = microphoneInfo->getChannelMapping()[i];
|
||||
if (channelMappingType != AUDIO_MICROPHONE_CHANNEL_MAPPING_UNUSED) {
|
||||
jobject jChannelIndex = env->NewObject(gIntegerClass, gIntegerCstor, i);
|
||||
jobject jChannelMappingType = env->NewObject(gIntegerClass, gIntegerCstor,
|
||||
channelMappingType);
|
||||
jobject jChannelMapping = env->NewObject(gPairClass, gPairCstor,
|
||||
jChannelIndex, jChannelMappingType);
|
||||
env->CallBooleanMethod(jChannelMappings, gArrayListMethods.add, jChannelMapping);
|
||||
env->DeleteLocalRef(jChannelIndex);
|
||||
env->DeleteLocalRef(jChannelMappingType);
|
||||
env->DeleteLocalRef(jChannelMapping);
|
||||
}
|
||||
}
|
||||
*jMicrophoneInfo = env->NewObject(gMicrophoneInfoClass, gMicrophoneInfoCstor, jDeviceId,
|
||||
microphoneInfo->getType(), jAddress,
|
||||
microphoneInfo->getDeviceLocation(),
|
||||
microphoneInfo->getDeviceGroup(),
|
||||
microphoneInfo->getIndexInTheGroup(),
|
||||
jGeometricLocation, jOrientation,
|
||||
jFrequencyResponses, jChannelMappings,
|
||||
microphoneInfo->getSensitivity(),
|
||||
microphoneInfo->getMaxSpl(),
|
||||
microphoneInfo->getMinSpl(),
|
||||
microphoneInfo->getDirectionality());
|
||||
|
||||
exit:
|
||||
if (jDeviceId != NULL) {
|
||||
env->DeleteLocalRef(jDeviceId);
|
||||
}
|
||||
if (jAddress != NULL) {
|
||||
env->DeleteLocalRef(jAddress);
|
||||
}
|
||||
if (jFrequencyResponses != NULL) {
|
||||
env->DeleteLocalRef(jFrequencyResponses);
|
||||
}
|
||||
if (jChannelMappings != NULL) {
|
||||
env->DeleteLocalRef(jChannelMappings);
|
||||
}
|
||||
if (jGeometricLocation != NULL) {
|
||||
env->DeleteLocalRef(jGeometricLocation);
|
||||
}
|
||||
if (jOrientation != NULL) {
|
||||
env->DeleteLocalRef(jOrientation);
|
||||
}
|
||||
return jStatus;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int register_android_media_MicrophoneInfo(JNIEnv *env)
|
||||
{
|
||||
jclass arrayListClass = FindClassOrDie(env, "java/util/ArrayList");
|
||||
gArrayListClass = MakeGlobalRefOrDie(env, arrayListClass);
|
||||
gArrayListCstor = GetMethodIDOrDie(env, arrayListClass, "<init>", "()V");
|
||||
gArrayListMethods.add = GetMethodIDOrDie(env, arrayListClass, "add", "(Ljava/lang/Object;)Z");
|
||||
|
||||
jclass floatClass = FindClassOrDie(env, "java/lang/Float");
|
||||
gFloatClass = MakeGlobalRefOrDie(env, floatClass);
|
||||
gFloatCstor = GetMethodIDOrDie(env, floatClass, "<init>", "(F)V");
|
||||
|
||||
jclass floatArrayClass = FindClassOrDie(env, "[F");
|
||||
gFloatArrayClass = MakeGlobalRefOrDie(env, floatArrayClass);
|
||||
|
||||
jclass integerClass = FindClassOrDie(env, "java/lang/Integer");
|
||||
gIntegerClass = MakeGlobalRefOrDie(env, integerClass);
|
||||
gIntegerCstor = GetMethodIDOrDie(env, integerClass, "<init>", "(I)V");
|
||||
|
||||
jclass microphoneInfoClass = FindClassOrDie(env, "android/media/MicrophoneInfo");
|
||||
gMicrophoneInfoClass = MakeGlobalRefOrDie(env, microphoneInfoClass);
|
||||
gMicrophoneInfoCstor = GetMethodIDOrDie(env, microphoneInfoClass, "<init>",
|
||||
"(Ljava/lang/String;ILjava/lang/String;IIILandroid/media/MicrophoneInfo$Coordinate3F;Landroid/media/MicrophoneInfo$Coordinate3F;Ljava/util/List;Ljava/util/List;FFFI)V");
|
||||
|
||||
jclass microphoneInfoCoordinateClass = FindClassOrDie(
|
||||
env, "android/media/MicrophoneInfo$Coordinate3F");
|
||||
gMicrophoneInfoCoordinateClass = MakeGlobalRefOrDie(env, microphoneInfoCoordinateClass);
|
||||
gMicrophoneInfoCoordinateCstor = GetMethodIDOrDie(env, microphoneInfoCoordinateClass, "<init>",
|
||||
"(Landroid/media/MicrophoneInfo;FFF)V");
|
||||
|
||||
jclass pairClass = FindClassOrDie(env, "android/util/Pair");
|
||||
gPairClass = MakeGlobalRefOrDie(env, pairClass);
|
||||
gPairCstor = GetMethodIDOrDie(env, pairClass, "<init>", "(Ljava/lang/Object;Ljava/lang/Object;)V");
|
||||
|
||||
return 0;
|
||||
}
|
||||
33
core/jni/android_media_MicrophoneInfo.h
Normal file
33
core/jni/android_media_MicrophoneInfo.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_MEDIA_MICROPHONEINFO_H
|
||||
#define ANDROID_MEDIA_MICROPHONEINFO_H
|
||||
|
||||
#include <system/audio.h>
|
||||
#include <media/MicrophoneInfo.h>
|
||||
|
||||
#include "jni.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
// Conversion from C++ MicrophoneInfo object to Java MicrophoneInfo object
|
||||
|
||||
extern jint convertMicrophoneInfoFromNative(JNIEnv *env, jobject *jMicrophoneInfo,
|
||||
const media::MicrophoneInfo *microphoneInfo);
|
||||
} // namespace android
|
||||
|
||||
#endif
|
||||
@@ -48,11 +48,13 @@ import android.os.ServiceManager;
|
||||
import android.os.SystemClock;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.ArrayList;
|
||||
@@ -4566,6 +4568,51 @@ public class AudioManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set port id for microphones by matching device type and address.
|
||||
* @hide
|
||||
*/
|
||||
public static void setPortIdForMicrophones(ArrayList<MicrophoneInfo> microphones) {
|
||||
AudioDeviceInfo[] devices = getDevicesStatic(AudioManager.GET_DEVICES_INPUTS);
|
||||
for (int i = microphones.size() - 1; i >= 0; i--) {
|
||||
boolean foundPortId = false;
|
||||
for (AudioDeviceInfo device : devices) {
|
||||
if (device.getPort().type() == microphones.get(i).getInternalDeviceType()
|
||||
&& TextUtils.equals(device.getAddress(), microphones.get(i).getAddress())) {
|
||||
microphones.get(i).setId(device.getId());
|
||||
foundPortId = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!foundPortId) {
|
||||
Log.i(TAG, "Failed to find port id for device with type:"
|
||||
+ microphones.get(i).getType() + " address:"
|
||||
+ microphones.get(i).getAddress());
|
||||
microphones.remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of {@link MicrophoneInfo} that corresponds to the characteristics
|
||||
* of all available microphones. The list is empty when no microphones are available
|
||||
* on the device. An error during the query will result in an IOException being thrown.
|
||||
*
|
||||
* @return a list that contains all microphones' characteristics
|
||||
* @throws IOException if an error occurs.
|
||||
*/
|
||||
public List<MicrophoneInfo> getMicrophones() throws IOException {
|
||||
ArrayList<MicrophoneInfo> microphones = new ArrayList<MicrophoneInfo>();
|
||||
int status = AudioSystem.getMicrophones(microphones);
|
||||
if (status != AudioManager.SUCCESS) {
|
||||
// fail and bail!
|
||||
Log.e(TAG, "getMicrophones failed:" + status);
|
||||
return new ArrayList<MicrophoneInfo>(); // Always return a list.
|
||||
}
|
||||
setPortIdForMicrophones(microphones);
|
||||
return microphones;
|
||||
}
|
||||
|
||||
// Since we need to calculate the changes since THE LAST NOTIFICATION, and not since the
|
||||
// (unpredictable) last time updateAudioPortCache() was called by someone, keep a list
|
||||
// of the ports that exist at the time of the last notification.
|
||||
|
||||
@@ -827,6 +827,8 @@ public class AudioSystem
|
||||
private static native boolean native_is_offload_supported(int encoding, int sampleRate,
|
||||
int channelMask, int channelIndexMask);
|
||||
|
||||
public static native int getMicrophones(ArrayList<MicrophoneInfo> microphonesInfo);
|
||||
|
||||
// Items shared with audio service
|
||||
|
||||
/**
|
||||
|
||||
342
media/java/android/media/MicrophoneInfo.java
Normal file
342
media/java/android/media/MicrophoneInfo.java
Normal file
@@ -0,0 +1,342 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.media;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.util.Pair;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Class providing information on a microphone. It indicates the location and orientation of the
|
||||
* microphone on the device as well as useful information like frequency response and sensitivity.
|
||||
* It can be used by applications implementing special pre processing effects like noise suppression
|
||||
* of beam forming that need to know about precise microphone characteristics in order to adapt
|
||||
* their algorithms.
|
||||
*/
|
||||
public final class MicrophoneInfo {
|
||||
|
||||
/**
|
||||
* A microphone that the location is unknown.
|
||||
*/
|
||||
public static final int LOCATION_UNKNOWN = 0;
|
||||
|
||||
/**
|
||||
* A microphone that locate on main body of the device.
|
||||
*/
|
||||
public static final int LOCATION_MAINBODY = 1;
|
||||
|
||||
/**
|
||||
* A microphone that locate on a movable main body of the device.
|
||||
*/
|
||||
public static final int LOCATION_MAINBODY_MOVABLE = 2;
|
||||
|
||||
/**
|
||||
* A microphone that locate on a peripheral.
|
||||
*/
|
||||
public static final int LOCATION_PERIPHERAL = 3;
|
||||
|
||||
/**
|
||||
* Unknown microphone directionality.
|
||||
*/
|
||||
public static final int DIRECTIONALITY_UNKNOW = 0;
|
||||
|
||||
/**
|
||||
* Microphone directionality type: omni.
|
||||
*/
|
||||
public static final int DIRECTIONALITY_OMNI = 1;
|
||||
|
||||
/**
|
||||
* Microphone directionality type: bi-directional.
|
||||
*/
|
||||
public static final int DIRECTIONALITY_BI_DIRECTIONAL = 2;
|
||||
|
||||
/**
|
||||
* Microphone directionality type: cardioid.
|
||||
*/
|
||||
public static final int DIRECTIONALITY_CARDIOID = 3;
|
||||
|
||||
/**
|
||||
* Microphone directionality type: hyper cardioid.
|
||||
*/
|
||||
public static final int DIRECTIONALITY_HYPER_CARDIOID = 4;
|
||||
|
||||
/**
|
||||
* Microphone directionality type: super cardioid.
|
||||
*/
|
||||
public static final int DIRECTIONALITY_SUPER_CARDIOID = 5;
|
||||
|
||||
/**
|
||||
* The channel contains raw audio from this microphone.
|
||||
*/
|
||||
public static final int CHANNEL_MAPPING_DIRECT = 1;
|
||||
|
||||
/**
|
||||
* The channel contains processed audio from this microphone and possibly another microphone.
|
||||
*/
|
||||
public static final int CHANNEL_MAPPING_PROCESSED = 2;
|
||||
|
||||
/** @hide */
|
||||
@IntDef(flag = true, prefix = { "LOCATION_" }, value = {
|
||||
LOCATION_UNKNOWN,
|
||||
LOCATION_MAINBODY,
|
||||
LOCATION_MAINBODY_MOVABLE,
|
||||
LOCATION_PERIPHERAL,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface MicrophoneLocation {}
|
||||
|
||||
/** @hide */
|
||||
@IntDef(flag = true, prefix = { "DIRECTIONALITY_" }, value = {
|
||||
DIRECTIONALITY_UNKNOW,
|
||||
DIRECTIONALITY_OMNI,
|
||||
DIRECTIONALITY_BI_DIRECTIONAL,
|
||||
DIRECTIONALITY_CARDIOID,
|
||||
DIRECTIONALITY_HYPER_CARDIOID,
|
||||
DIRECTIONALITY_SUPER_CARDIOID,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface MicrophoneDirectionality {}
|
||||
|
||||
private Coordinate3F mPosition;
|
||||
private Coordinate3F mOrientation;
|
||||
private String mDeviceId;
|
||||
private String mAddress;
|
||||
private List<Pair<Float, Float>> mFrequencyResponse;
|
||||
private List<Pair<Integer, Integer>> mChannelMapping;
|
||||
private float mMaxSpl;
|
||||
private float mMinSpl;
|
||||
private float mSensitivity;
|
||||
private int mLocation;
|
||||
private int mGroup; /* Usually 0 will be used for main body. */
|
||||
private int mIndexInTheGroup;
|
||||
private int mPortId; /* mPortId will correspond to the id in AudioPort */
|
||||
private int mType;
|
||||
private int mDirectionality;
|
||||
|
||||
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) {
|
||||
mDeviceId = deviceId;
|
||||
mType = type;
|
||||
mAddress = address;
|
||||
mLocation = location;
|
||||
mGroup = group;
|
||||
mIndexInTheGroup = indexInTheGroup;
|
||||
mPosition = position;
|
||||
mOrientation = orientation;
|
||||
mFrequencyResponse = frequencyResponse;
|
||||
mChannelMapping = channelMapping;
|
||||
mSensitivity = sensitivity;
|
||||
mMaxSpl = maxSpl;
|
||||
mMinSpl = minSpl;
|
||||
mDirectionality = directionality;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns alphanumeric code that uniquely identifies the device.
|
||||
*
|
||||
* @return the description of the microphone
|
||||
*/
|
||||
public String getDescription() {
|
||||
return mDeviceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns The system unique device ID that corresponds to the id
|
||||
* returned by {@link AudioDeviceInfo#getId()}.
|
||||
*
|
||||
* @return the microphone's id
|
||||
*/
|
||||
public int getId() {
|
||||
return mPortId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* Returns the internal device type (e.g AudioSystem.DEVICE_IN_BUILTIN_MIC).
|
||||
* The internal device type could be used when getting microphone's port id
|
||||
* by matching type and address.
|
||||
*
|
||||
* @return the internal device type
|
||||
*/
|
||||
public int getInternalDeviceType() {
|
||||
return mType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the device type identifier of the microphone (e.g AudioDeviceInfo.TYPE_BUILTIN_MIC).
|
||||
*
|
||||
* @return the device type of the microphone
|
||||
*/
|
||||
public int getType() {
|
||||
return AudioDeviceInfo.convertInternalDeviceToDeviceType(mType);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* Returns The "address" string of the microphone that corresponds to the
|
||||
* address returned by {@link AudioDeviceInfo#getAddress()}
|
||||
* @return the address of the microphone
|
||||
*/
|
||||
public String getAddress() {
|
||||
return mAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the location of the microphone. The return value is
|
||||
* one of {@link #LOCATION_UNKNOWN}, {@link #LOCATION_MAINBODY},
|
||||
* {@link #LOCATION_MAINBODY_MOVABLE}, or {@link #LOCATION_PERIPHERAL}.
|
||||
*
|
||||
* @return the location of the microphone
|
||||
*/
|
||||
public @MicrophoneLocation int getLocation() {
|
||||
return mLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns A device group id that can be used to group together microphones on the same
|
||||
* peripheral, attachments or logical groups. Main body is usually group 0.
|
||||
*
|
||||
* @return the group of the microphone
|
||||
*/
|
||||
public int getGroup() {
|
||||
return mGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns unique index for device within its group.
|
||||
*
|
||||
* @return the microphone's index in its group
|
||||
*/
|
||||
public int getIndexInTheGroup() {
|
||||
return mIndexInTheGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns A {@link Coordinate3F} object that represents the geometric location of microphone
|
||||
* in meters, from botton-left-back corner of appliance. X-axis, Y-axis and Z-axis show
|
||||
* as the x, y, z values.
|
||||
*
|
||||
* @return the geometric location of the microphone
|
||||
*/
|
||||
public Coordinate3F getPosition() {
|
||||
return mPosition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns A {@link Coordinate3F} object that represents the orientation of microphone.
|
||||
* X-axis, Y-axis and Z-axis show as the x, y, z value. The orientation will be normalized
|
||||
* such as sqrt(x^2 + y^2 + z^2) equals 1.
|
||||
*
|
||||
* @return the orientation of the microphone
|
||||
*/
|
||||
public Coordinate3F getOrientation() {
|
||||
return mOrientation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link android.util.Pair} list of frequency responses.
|
||||
* For every {@link android.util.Pair} in the list, the first value represents frequency in Hz,
|
||||
* and the second value represents response in dB.
|
||||
*
|
||||
* @return the frequency response of the microphone
|
||||
*/
|
||||
public List<Pair<Float, Float>> getFrequencyResponse() {
|
||||
return mFrequencyResponse;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link android.util.Pair} list for channel mapping, which indicating how this
|
||||
* microphone is used by each channels or a capture stream. For each {@link android.util.Pair},
|
||||
* the first value is channel index, the second value is channel mapping type, which could be
|
||||
* either {@link #CHANNEL_MAPPING_DIRECT} or {@link #CHANNEL_MAPPING_PROCESSED}.
|
||||
* If a channel has contributions from more than one microphone, it is likely the HAL
|
||||
* did some extra processing to combine the sources, but this is to be inferred by the user.
|
||||
* Empty list when the MicrophoneInfo is returned by AudioManager.getMicrophones().
|
||||
* At least one entry when the MicrophoneInfo is returned by AudioRecord.getActiveMicrophones().
|
||||
*
|
||||
* @return a {@link android.util.Pair} list for channel mapping
|
||||
*/
|
||||
public List<Pair<Integer, Integer>> getChannelMapping() {
|
||||
return mChannelMapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the level in dBFS produced by a 1000Hz tone at 94 dB SPL.
|
||||
*
|
||||
* @return the sensitivity of the microphone
|
||||
*/
|
||||
public float getSensitivity() {
|
||||
return mSensitivity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the level in dB of the maximum SPL supported by the device at 1000Hz.
|
||||
*
|
||||
* @return the maximum level in dB
|
||||
*/
|
||||
public float getMaxSpl() {
|
||||
return mMaxSpl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the level in dB of the minimum SPL that can be registered by the device at 1000Hz.
|
||||
*
|
||||
* @return the minimum level in dB
|
||||
*/
|
||||
public float getMinSpl() {
|
||||
return mMinSpl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the directionality of microphone. The return value is one of
|
||||
* {@link #DIRECTIONALITY_UNKNOW}, {@link #DIRECTIONALITY_OMNI},
|
||||
* {@link #DIRECTIONALITY_BI_DIRECTIONAL}, {@link #DIRECTIONALITY_CARDIOID},
|
||||
* {@link #DIRECTIONALITY_HYPER_CARDIOID}, or {@link #DIRECTIONALITY_SUPER_CARDIOID}.
|
||||
*
|
||||
* @return the directionality of microphone
|
||||
*/
|
||||
public @MicrophoneDirectionality int getDirectionality() {
|
||||
return mDirectionality;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the port id for the device.
|
||||
* @hide
|
||||
*/
|
||||
public void setId(int portId) {
|
||||
mPortId = portId;
|
||||
}
|
||||
|
||||
/* A class containing three float value to represent a 3D coordinate */
|
||||
public class Coordinate3F {
|
||||
public final float x;
|
||||
public final float y;
|
||||
public final float z;
|
||||
|
||||
Coordinate3F(float x, float y, float z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user