Merge "Add audio level monitoring capabilities in Visualizer effect" into klp-dev
diff --git a/media/java/android/media/audiofx/Visualizer.java b/media/java/android/media/audiofx/Visualizer.java
index 9197ed8..580a4f9 100644
--- a/media/java/android/media/audiofx/Visualizer.java
+++ b/media/java/android/media/audiofx/Visualizer.java
@@ -93,6 +93,24 @@
*/
public static final int SCALING_MODE_AS_PLAYED = 1;
+ /**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * Defines a measurement mode with no requested measurement.
+ */
+ public static final int MEASUREMENT_MODE_NONE = 0;
+
+ /**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * Defines a measurement mode which computes the peak and RMS value in mB, where 0mB is the
+ * maximum sample value, and -9600mB is the minimum value.
+ * Values for peak and RMS can be retrieved with {@link #getIntMeasurements(int, int[])}, where
+ * the array holds the peak value at index {@link #MEASUREMENT_INDEX_PEAK} in the measurement
+ * array, and the RMS value at index {@link #MEASUREMENT_INDEX_RMS}.
+ */
+ public static final int MEASUREMENT_MODE_PEAK_RMS = 1 << 0;
+
// to keep in sync with frameworks/base/media/jni/audioeffect/android_media_Visualizer.cpp
private static final int NATIVE_EVENT_PCM_CAPTURE = 0;
private static final int NATIVE_EVENT_FFT_CAPTURE = 1;
@@ -350,6 +368,47 @@
}
/**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * Sets the combination of measurement modes to be performed by this audio effect.
+ * @param mode a mask of the measurements to perform. The valid values are
+ * {@link #MEASUREMENT_MODE_NONE} (to cancel any measurement)
+ * or {@link #MEASUREMENT_MODE_PEAK_RMS}.
+ * @return {@link #SUCCESS} in case of success, {@link #ERROR_BAD_VALUE} in case of failure.
+ * @throws IllegalStateException
+ */
+ public int setMeasurementMode(int mode)
+ throws IllegalStateException {
+ synchronized (mStateLock) {
+ if (mState == STATE_UNINITIALIZED) {
+ throw(new IllegalStateException("setMeasurementMode() called in wrong state: "
+ + mState));
+ }
+ return native_setMeasurementMode(mode);
+ }
+ }
+
+ /**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * Returns the current measurement modes performed by this audio effect
+ * @return the mask of the measurements,
+ * {@link #MEASUREMENT_MODE_NONE} (when no measurements are performed)
+ * or {@link #MEASUREMENT_MODE_PEAK_RMS}.
+ * @throws IllegalStateException
+ */
+ public int getMeasurementMode()
+ throws IllegalStateException {
+ synchronized (mStateLock) {
+ if (mState == STATE_UNINITIALIZED) {
+ throw(new IllegalStateException("getMeasurementMode() called in wrong state: "
+ + mState));
+ }
+ return native_getMeasurementMode();
+ }
+ }
+
+ /**
* Returns the sampling rate of the captured audio.
* @return the sampling rate in milliHertz.
*/
@@ -437,6 +496,51 @@
}
}
+ /**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * A class to store peak and RMS values.
+ * Peak and RMS are expressed in mB, as described in the
+ * {@link Visualizer#MEASUREMENT_MODE_PEAK_RMS} measurement mode.
+ */
+ public static final class MeasurementPeakRms {
+ /**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ */
+ public int mPeak;
+ /**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ */
+ public int mRms;
+ }
+
+ /**
+ * @hide
+ * Retrieves the latest peak and RMS measurement.
+ * Sets the peak and RMS fields of the {@link Visualizer.MeasurementPeakRms} to the latest
+ * measured values.
+ * @param measurement a non-null {@link Visualizer.MeasurementPeakRms} instance to store
+ * the measurement values.
+ * @return {@link #SUCCESS} in case of success, {@link #ERROR_BAD_VALUE},
+ * {@link #ERROR_NO_MEMORY}, {@link #ERROR_INVALID_OPERATION} or {@link #ERROR_DEAD_OBJECT}
+ * in case of failure.
+ */
+ public int getMeasurementPeakRms(MeasurementPeakRms measurement) {
+ if (measurement == null) {
+ Log.e(TAG, "Cannot store measurements in a null object");
+ return ERROR_BAD_VALUE;
+ }
+ synchronized (mStateLock) {
+ if (mState != STATE_ENABLED) {
+ throw (new IllegalStateException("getMeasurementPeakRms() called in wrong state: "
+ + mState));
+ }
+ return native_getPeakRms(measurement);
+ }
+ }
+
//---------------------------------------------------------
// Interface definitions
//--------------------
@@ -640,12 +744,18 @@
private native final int native_getScalingMode();
+ private native final int native_setMeasurementMode(int mode);
+
+ private native final int native_getMeasurementMode();
+
private native final int native_getSamplingRate();
private native final int native_getWaveForm(byte[] waveform);
private native final int native_getFft(byte[] fft);
+ private native final int native_getPeakRms(MeasurementPeakRms measurement);
+
private native final int native_setPeriodicCapture(int rate, boolean waveForm, boolean fft);
//---------------------------------------------------------
diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp
index 4d77cfd..40cd06b 100644
--- a/media/jni/audioeffect/android_media_Visualizer.cpp
+++ b/media/jni/audioeffect/android_media_Visualizer.cpp
@@ -43,6 +43,8 @@
// ----------------------------------------------------------------------------
static const char* const kClassPathName = "android/media/audiofx/Visualizer";
+static const char* const kClassPeakRmsPathName =
+ "android/media/audiofx/Visualizer$MeasurementPeakRms";
struct fields_t {
// these fields provide access from C++ to the...
@@ -50,6 +52,8 @@
jmethodID midPostNativeEvent; // event post callback method
jfieldID fidNativeVisualizer; // stores in Java the native Visualizer object
jfieldID fidJniData; // stores in Java additional resources used by the native Visualizer
+ jfieldID fidPeak; // to access Visualizer.MeasurementPeakRms.mPeak
+ jfieldID fidRms; // to access Visualizer.MeasurementPeakRms.mRms
};
static fields_t fields;
@@ -257,6 +261,14 @@
fields.clazzEffect = (jclass)env->NewGlobalRef(clazz);
+ // Get the Visualizer.MeasurementPeakRms class
+ clazz = env->FindClass(kClassPeakRmsPathName);
+ if (clazz == NULL) {
+ ALOGE("Can't find %s", kClassPeakRmsPathName);
+ return;
+ }
+ jclass clazzMeasurementPeakRms = (jclass)env->NewGlobalRef(clazz);
+
// Get the postEvent method
fields.midPostNativeEvent = env->GetStaticMethodID(
fields.clazzEffect,
@@ -283,7 +295,24 @@
ALOGE("Can't find Visualizer.%s", "mJniData");
return;
}
+ // fidPeak
+ fields.fidPeak = env->GetFieldID(
+ clazzMeasurementPeakRms,
+ "mPeak", "I");
+ if (fields.fidPeak == NULL) {
+ ALOGE("Can't find Visualizer.MeasurementPeakRms.%s", "mPeak");
+ return;
+ }
+ // fidRms
+ fields.fidRms = env->GetFieldID(
+ clazzMeasurementPeakRms,
+ "mRms", "I");
+ if (fields.fidRms == NULL) {
+ ALOGE("Can't find Visualizer.MeasurementPeakRms.%s", "mPeak");
+ return;
+ }
+ env->DeleteGlobalRef(clazzMeasurementPeakRms);
}
static void android_media_visualizer_effect_callback(int32_t event,
@@ -513,6 +542,26 @@
}
static jint
+android_media_visualizer_native_setMeasurementMode(JNIEnv *env, jobject thiz, jint mode)
+{
+ Visualizer* lpVisualizer = getVisualizer(env, thiz);
+ if (lpVisualizer == NULL) {
+ return VISUALIZER_ERROR_NO_INIT;
+ }
+ return translateError(lpVisualizer->setMeasurementMode(mode));
+}
+
+static jint
+android_media_visualizer_native_getMeasurementMode(JNIEnv *env, jobject thiz)
+{
+ Visualizer* lpVisualizer = getVisualizer(env, thiz);
+ if (lpVisualizer == NULL) {
+ return MEASUREMENT_MODE_NONE;
+ }
+ return lpVisualizer->getMeasurementMode();
+}
+
+static jint
android_media_visualizer_native_getSamplingRate(JNIEnv *env, jobject thiz)
{
Visualizer* lpVisualizer = getVisualizer(env, thiz);
@@ -560,6 +609,25 @@
}
static jint
+android_media_visualizer_native_getPeakRms(JNIEnv *env, jobject thiz, jobject jPeakRmsObj)
+{
+ Visualizer* lpVisualizer = getVisualizer(env, thiz);
+ if (lpVisualizer == NULL) {
+ return VISUALIZER_ERROR_NO_INIT;
+ }
+ int32_t measurements[2];
+ jint status = translateError(
+ lpVisualizer->getIntMeasurements(MEASUREMENT_MODE_PEAK_RMS,
+ 2, measurements));
+ if (status == VISUALIZER_SUCCESS) {
+ // measurement worked, write the values to the java object
+ env->SetIntField(jPeakRmsObj, fields.fidPeak, measurements[MEASUREMENT_IDX_PEAK]);
+ env->SetIntField(jPeakRmsObj, fields.fidRms, measurements[MEASUREMENT_IDX_RMS]);
+ }
+ return status;
+}
+
+static jint
android_media_setPeriodicCapture(JNIEnv *env, jobject thiz, jint rate, jboolean jWaveform, jboolean jFft)
{
Visualizer* lpVisualizer = getVisualizer(env, thiz);
@@ -606,9 +674,13 @@
{"native_getCaptureSize", "()I", (void *)android_media_visualizer_native_getCaptureSize},
{"native_setScalingMode", "(I)I", (void *)android_media_visualizer_native_setScalingMode},
{"native_getScalingMode", "()I", (void *)android_media_visualizer_native_getScalingMode},
+ {"native_setMeasurementMode","(I)I", (void *)android_media_visualizer_native_setMeasurementMode},
+ {"native_getMeasurementMode","()I", (void *)android_media_visualizer_native_getMeasurementMode},
{"native_getSamplingRate", "()I", (void *)android_media_visualizer_native_getSamplingRate},
{"native_getWaveForm", "([B)I", (void *)android_media_visualizer_native_getWaveForm},
{"native_getFft", "([B)I", (void *)android_media_visualizer_native_getFft},
+ {"native_getPeakRms", "(Landroid/media/audiofx/Visualizer$MeasurementPeakRms;)I",
+ (void *)android_media_visualizer_native_getPeakRms},
{"native_setPeriodicCapture","(IZZ)I",(void *)android_media_setPeriodicCapture},
};