Merge "Support query active microphones information in AudioRecord."
diff --git a/api/current.txt b/api/current.txt
index 6fa7976..ded0e43 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -22155,6 +22155,7 @@
method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method public deprecated void addOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener, android.os.Handler);
method protected void finalize();
+ method public java.util.List<android.media.MicrophoneInfo> getActiveMicrophones() throws java.io.IOException;
method public int getAudioFormat();
method public int getAudioSessionId();
method public int getAudioSource();
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index ebd16c7..375d68b 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -25,6 +25,8 @@
#include <utils/Log.h>
#include <media/AudioRecord.h>
+#include <media/MicrophoneInfo.h>
+#include <vector>
#include <nativehelper/ScopedUtfChars.h>
@@ -32,6 +34,7 @@
#include "android_media_AudioErrors.h"
#include "android_media_DeviceCallback.h"
#include "android_media_MediaMetricsJNI.h"
+#include "android_media_MicrophoneInfo.h"
// ----------------------------------------------------------------------------
@@ -41,6 +44,11 @@
static const char* const kClassPathName = "android/media/AudioRecord";
static const char* const kAudioAttributesClassPathName = "android/media/AudioAttributes";
+static jclass gArrayListClass;
+static struct {
+ jmethodID add;
+} gArrayListMethods;
+
struct audio_record_fields_t {
// these fields provide access from C++ to the...
jmethodID postNativeEventInJava; //... event post callback method
@@ -785,6 +793,46 @@
}
// ----------------------------------------------------------------------------
+static jint android_media_AudioRecord_get_active_microphones(JNIEnv *env,
+ jobject thiz, jobject jActiveMicrophones) {
+ if (jActiveMicrophones == NULL) {
+ ALOGE("jActiveMicrophones is null");
+ return (jint)AUDIO_JAVA_BAD_VALUE;
+ }
+ if (!env->IsInstanceOf(jActiveMicrophones, gArrayListClass)) {
+ ALOGE("getActiveMicrophones not an arraylist");
+ return (jint)AUDIO_JAVA_BAD_VALUE;
+ }
+
+ sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
+ if (lpRecorder == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioRecord pointer for getActiveMicrophones()");
+ return (jint)AUDIO_JAVA_ERROR;
+ }
+
+ jint jStatus = AUDIO_JAVA_SUCCESS;
+ std::vector<media::MicrophoneInfo> activeMicrophones;
+ status_t status = lpRecorder->getActiveMicrophones(&activeMicrophones);
+ if (status != NO_ERROR) {
+ ALOGE_IF(status != NO_ERROR, "AudioRecord::getActiveMicrophones error %d", status);
+ jStatus = nativeToJavaStatus(status);
+ return jStatus;
+ }
+
+ for (size_t i = 0; i < activeMicrophones.size(); i++) {
+ jobject jMicrophoneInfo;
+ jStatus = convertMicrophoneInfoFromNative(env, &jMicrophoneInfo, &activeMicrophones[i]);
+ if (jStatus != AUDIO_JAVA_SUCCESS) {
+ return jStatus;
+ }
+ env->CallBooleanMethod(jActiveMicrophones, gArrayListMethods.add, jMicrophoneInfo);
+ env->DeleteLocalRef(jMicrophoneInfo);
+ }
+ return jStatus;
+}
+
+// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
static const JNINativeMethod gMethods[] = {
// name, signature, funcPtr
@@ -824,6 +872,8 @@
(void *)android_media_AudioRecord_disableDeviceCallback},
{"native_get_timestamp", "(Landroid/media/AudioTimestamp;I)I",
(void *)android_media_AudioRecord_get_timestamp},
+ {"native_get_active_microphones", "(Ljava/util/ArrayList;)I",
+ (void *)android_media_AudioRecord_get_active_microphones},
};
// field names found in android/media/AudioRecord.java
@@ -873,6 +923,10 @@
javaAudioTimestampFields.fieldNanoTime =
GetFieldIDOrDie(env, audioTimestampClass, "nanoTime", "J");
+ jclass arrayListClass = FindClassOrDie(env, "java/util/ArrayList");
+ gArrayListClass = MakeGlobalRefOrDie(env, arrayListClass);
+ gArrayListMethods.add = GetMethodIDOrDie(env, arrayListClass, "add", "(Ljava/lang/Object;)Z");
+
return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
}
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index eb6e830..d0963cb 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -16,12 +16,15 @@
package android.media;
+import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.Iterator;
+import java.util.ArrayList;
+import java.util.List;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -35,6 +38,7 @@
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
@@ -1601,6 +1605,32 @@
}
}
+ //--------------------------------------------------------------------------
+ // Microphone information
+ //--------------------
+ /**
+ * Returns a lists of {@link MicrophoneInfo} representing the active microphones.
+ * By querying channel mapping for each active microphone, developer can know how
+ * the microphone is used by each channels or a capture stream.
+ * Note that the information about the active microphones may change during a recording.
+ * See {@link AudioManager#registerAudioDeviceCallback} to be notified of changes
+ * in the audio devices, querying the active microphones then will return the latest
+ * information.
+ *
+ * @return a lists of {@link MicrophoneInfo} representing the active microphones.
+ * @throws IOException if an error occurs
+ */
+ public List<MicrophoneInfo> getActiveMicrophones() throws IOException {
+ ArrayList<MicrophoneInfo> activeMicrophones = new ArrayList<>();
+ int status = native_get_active_microphones(activeMicrophones);
+ if (status != AudioManager.SUCCESS) {
+ Log.e(TAG, "getActiveMicrophones failed:" + status);
+ return new ArrayList<MicrophoneInfo>();
+ }
+ AudioManager.setPortIdForMicrophones(activeMicrophones);
+ return activeMicrophones;
+ }
+
//---------------------------------------------------------
// Interface definitions
//--------------------
@@ -1746,6 +1776,9 @@
private native final int native_get_timestamp(@NonNull AudioTimestamp outTimestamp,
@AudioTimestamp.Timebase int timebase);
+ private native final int native_get_active_microphones(
+ ArrayList<MicrophoneInfo> activeMicrophones);
+
//---------------------------------------------------------
// Utility methods
//------------------