Merge "Added APIs for audio preprocessing"
diff --git a/include/media/AudioEffect.h b/include/media/AudioEffect.h
index 496b23e..1417416 100644
--- a/include/media/AudioEffect.h
+++ b/include/media/AudioEffect.h
@@ -21,6 +21,7 @@
 #include <sys/types.h>
 
 #include <media/IAudioFlinger.h>
+#include <media/IAudioPolicyService.h>
 #include <media/IEffect.h>
 #include <media/IEffectClient.h>
 #include <hardware/audio_effect.h>
@@ -111,6 +112,36 @@
 
 
     /*
+     * Returns a list of descriptors corresponding to the pre processings enabled by default
+     * on an AudioRecord with the supplied audio session ID.
+     *
+     * Parameters:
+     *      audioSession:  audio session ID.
+     *      descriptors: address where the effect descriptors should be returned.
+     *      count: as input, the maximum number of descriptor than should be returned
+     *             as output, the number of descriptor returned if status is NO_ERROR or the actual
+     *             number of enabled pre processings if status is NO_MEMORY
+     *
+     * Returned status (from utils/Errors.h) can be:
+     *      NO_ERROR        successful operation.
+     *      NO_MEMORY       the number of descriptor to return is more than the maximum number
+     *                      indicated by count.
+     *      PERMISSION_DENIED could not get AudioFlinger interface
+     *      NO_INIT         effect library failed to initialize
+     *      BAD_VALUE       invalid audio session or descriptor pointers
+     *
+     * Returned value
+     *   *descriptor updated with descriptors of pre processings enabled by default
+     *   *count      number of descriptors returned if returned status is N_ERROR.
+     *               total number of pre processing enabled by default if returned status is
+     *               NO_MEMORY. This happens if the count passed as input is less than the number
+     *               of descriptors to return
+     */
+    static status_t queryDefaultPreProcessing(int audioSession,
+                                              effect_descriptor_t *descriptors,
+                                              uint32_t *count);
+
+    /*
      * Events used by callback function (effect_callback_t).
      */
     enum event_type {
diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h
index 86b9f85..ed265e1 100644
--- a/include/media/IAudioPolicyService.h
+++ b/include/media/IAudioPolicyService.h
@@ -85,6 +85,9 @@
                                     int id) = 0;
     virtual status_t unregisterEffect(int id) = 0;
     virtual bool     isStreamActive(int stream, uint32_t inPastMs = 0) const = 0;
+    virtual status_t queryDefaultPreProcessing(int audioSession,
+                                              effect_descriptor_t *descriptors,
+                                              uint32_t *count) = 0;
 };
 
 
diff --git a/media/java/android/media/audiofx/AcousticEchoCanceler.java b/media/java/android/media/audiofx/AcousticEchoCanceler.java
new file mode 100644
index 0000000..7197dd2
--- /dev/null
+++ b/media/java/android/media/audiofx/AcousticEchoCanceler.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2011 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.audiofx;
+
+/**
+ * Acoustic Echo Canceler (AEC).
+ * <p>Acoustic Echo Canceler (AEC) is an audio pre-processing which removes the contribution of the
+ * signal received from the remote party from the captured audio signal.
+ * <p>AEC is used by voice communication applications (voice chat, video conferencing, SIP calls)
+ * where the presence of echo with significant delay in the signal received from the remote party
+ * is highly disturbing. AEC is often used in conjunction with noise suppression (NS).
+ * <p>An application creates an AcousticEchoCanceler object to instantiate and control an AEC
+ * engine in the audio capture path.
+ * <p>To attach the AcousticEchoCanceler to a particular {@link android.media.AudioRecord},
+ * specify the audio session ID of this AudioRecord when constructing the AcousticEchoCanceler.
+ * The audio session is retrieved by calling
+ * {@link android.media.AudioRecord#getAudioSessionId()} on the AudioRecord instance.
+ * <p>On some devices, an AEC can be inserted by default in the capture path by the platform
+ * according to the {@link android.media.MediaRecorder.AudioSource} used. The application can
+ * query which pre-processings are currently applied to an AudioRecord instance by calling
+ * {@link android.media.audiofx.AudioEffect#queryPreProcessings(int)} with the audio session of the
+ * AudioRecord.
+ * <p>See {@link android.media.audiofx.AudioEffect} class for more details on
+ * controlling audio effects.
+ * @hide
+ */
+
+public class AcousticEchoCanceler extends AudioEffect {
+
+    private final static String TAG = "AcousticEchoCanceler";
+
+    /**
+     * Class constructor.
+     * <p> The application must catch exceptions when creating an AcousticEchoCanceler as the
+     * constructor is not guarantied to succeed:
+     * <ul>
+     *  <li>IllegalArgumentException is thrown if the device does not implement an AEC</li>
+     *  <li>UnsupportedOperationException is thrown is the resources allocated to audio
+     *  pre-procesing are currently exceeded.</li>
+     * </ul>
+     *
+     * @param audioSession system wide unique audio session identifier. The AcousticEchoCanceler
+     * will be applied to the AudioRecord with the same audio session.
+     *
+     * @throws java.lang.IllegalArgumentException
+     * @throws java.lang.UnsupportedOperationException
+     * @throws java.lang.RuntimeException
+     */
+    public AcousticEchoCanceler(int audioSession)
+            throws IllegalArgumentException, UnsupportedOperationException, RuntimeException {
+        super(EFFECT_TYPE_AEC, EFFECT_TYPE_NULL, 0, audioSession);
+    }
+}
diff --git a/media/java/android/media/audiofx/AudioEffect.java b/media/java/android/media/audiofx/AudioEffect.java
index 39c6d3e..3ac0104 100644
--- a/media/java/android/media/audiofx/AudioEffect.java
+++ b/media/java/android/media/audiofx/AudioEffect.java
@@ -66,6 +66,8 @@
 
     private final static String TAG = "AudioEffect-JAVA";
 
+    // effect type UUIDs are taken from hardware/libhardware/include/hardware/audio_effect.h
+
     /**
      * The following UUIDs define effect types corresponding to standard audio
      * effects whose implementation and interface conform to the OpenSL ES
@@ -105,6 +107,27 @@
             .fromString("37cc2c00-dddd-11db-8577-0002a5d5c51b");
 
     /**
+     * UUID for Automatic Gain Control (AGC) audio pre-processing
+     * @hide
+     */
+    public static final UUID EFFECT_TYPE_AGC = UUID
+            .fromString("0a8abfe0-654c-11e0-ba26-0002a5d5c51b");
+
+    /**
+     * UUID for Acoustic Echo Canceler (AEC) audio pre-processing
+     * @hide
+     */
+    public static final UUID EFFECT_TYPE_AEC = UUID
+            .fromString("7b491460-8d4d-11e0-bd61-0002a5d5c51b");
+
+    /**
+     * UUID for Noise Suppressor (NS) audio pre-processing
+     * @hide
+     */
+    public static final UUID EFFECT_TYPE_NS = UUID
+            .fromString("58b4b260-8e06-11e0-aa8e-0002a5d5c51b");
+
+    /**
      * Null effect UUID. Used when the UUID for effect type of
      * @hide
      */
@@ -180,7 +203,8 @@
      * <ul>
      *  <li>type: UUID corresponding to the OpenSL ES interface implemented by this effect</li>
      *  <li>uuid: UUID for this particular implementation</li>
-     *  <li>connectMode: {@link #EFFECT_INSERT} or {@link #EFFECT_AUXILIARY}</li>
+     *  <li>connectMode: {@link #EFFECT_INSERT}, {@link #EFFECT_AUXILIARY} or
+     *  {at_link #EFFECT_PRE_PROCESSING}</li>
      *  <li>name: human readable effect name</li>
      *  <li>implementor: human readable effect implementor name</li>
      * </ul>
@@ -212,11 +236,13 @@
          */
         public UUID uuid;
         /**
-         *  Indicates if the effect is of insert category {@link #EFFECT_INSERT} or auxiliary
-         *  category {@link #EFFECT_AUXILIARY}. Insert effects (Typically an Equalizer) are applied
+         *  Indicates if the effect is of insert category {@link #EFFECT_INSERT}, auxiliary
+         *  category {@link #EFFECT_AUXILIARY} or pre processing category
+         *  {at_link #EFFECT_PRE_PROCESSING}. Insert effects (Typically an Equalizer) are applied
          *  to the entire audio source and usually not shared by several sources. Auxiliary effects
          *  (typically a reverberator) are applied to part of the signal (wet) and the effect output
          *  is added to the original signal (dry).
+         *  Audio pre processing are applied to audio captured on a particular AudioRecord.
          */
         public String connectMode;
         /**
@@ -243,6 +269,12 @@
      * attaching it to the MediaPlayer or AudioTrack.
      */
     public static final String EFFECT_AUXILIARY = "Auxiliary";
+    /**
+     * Effect connection mode is pre processing.
+     * The audio pre processing effects are attached to an audio input (AudioRecord).
+     * @hide
+     */
+    public static final String EFFECT_PRE_PROCESSING = "Pre Processing";
 
     // --------------------------------------------------------------------------
     // Member variables
@@ -410,6 +442,19 @@
         return (Descriptor[]) native_query_effects();
     }
 
+    /**
+     * Query all audio pre processing effects applied to the AudioRecord with the supplied
+     * audio session ID. Returns an array of {@link android.media.audiofx.AudioEffect.Descriptor}
+     * objects.
+     * @param audioSession system wide unique audio session identifier.
+     * @throws IllegalStateException
+     * @hide
+     */
+
+    static public Descriptor[] queryPreProcessings(int audioSession) {
+        return (Descriptor[]) native_query_pre_processing(audioSession);
+    }
+
     // --------------------------------------------------------------------------
     // Control methods
     // --------------------
@@ -1155,6 +1200,8 @@
 
     private static native Object[] native_query_effects();
 
+    private static native Object[] native_query_pre_processing(int audioSession);
+
     // ---------------------------------------------------------
     // Utility methods
     // ------------------
diff --git a/media/java/android/media/audiofx/AutomaticGainControl.java b/media/java/android/media/audiofx/AutomaticGainControl.java
new file mode 100644
index 0000000..44574f0
--- /dev/null
+++ b/media/java/android/media/audiofx/AutomaticGainControl.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2011 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.audiofx;
+
+/**
+ * Automatic Gain Control (AGC).
+ * <p>Automatic Gain Control (AGC) is an audio pre-processing which automatically normalizes the
+ * output of the captured signal by boosting or lowering input from the microphone to match a preset
+ * level so that that the output signal level is virtually constant.
+ * AGC can be used by applications where the input signal dynamic range is not important but where
+ * a constant strong capture level is desired.
+ * <p>An application creates a AutomaticGainControl object to instantiate and control an AGC
+ * engine in the audio framework.
+ * <p>To attach the AutomaticGainControl to a particular {@link android.media.AudioRecord},
+ * specify the audio session ID of this AudioRecord when constructing the AutomaticGainControl.
+ * The audio session is retrieved by calling
+ * {@link android.media.AudioRecord#getAudioSessionId()} on the AudioRecord instance.
+ * <p>On some devices, an AGC can be inserted by default in the capture path by the platform
+ * according to the {@link android.media.MediaRecorder.AudioSource} used. The application can
+ * query which pre-processings are currently applied to an AudioRecord instance by calling
+ * {@link android.media.audiofx.AudioEffect#queryPreProcessings(int)} with the audio session of the
+ * AudioRecord.
+ * <p>See {@link android.media.audiofx.AudioEffect} class for more details on
+ * controlling audio effects.
+ * @hide
+ */
+
+public class AutomaticGainControl extends AudioEffect {
+
+    private final static String TAG = "AutomaticGainControl";
+
+    /**
+     * Class constructor.
+     * <p> The application must catch exceptions when creating an AutomaticGainControl as the
+     * constructor is not guarantied to succeed:
+     * <ul>
+     *  <li>IllegalArgumentException is thrown if the device does not implement an AGC</li>
+     *  <li>UnsupportedOperationException is thrown is the resources allocated to audio
+     *  pre-procesing are currently exceeded.</li>
+     * </ul>
+     *
+     * @param audioSession system wide unique audio session identifier. The AutomaticGainControl
+     * will be applied to the AudioRecord with the same audio session.
+     *
+     * @throws java.lang.IllegalArgumentException
+     * @throws java.lang.UnsupportedOperationException
+     * @throws java.lang.RuntimeException
+     */
+    public AutomaticGainControl(int audioSession)
+            throws IllegalArgumentException, UnsupportedOperationException, RuntimeException {
+        super(EFFECT_TYPE_AGC, EFFECT_TYPE_NULL, 0, audioSession);
+    }
+}
diff --git a/media/java/android/media/audiofx/NoiseSuppressor.java b/media/java/android/media/audiofx/NoiseSuppressor.java
new file mode 100644
index 0000000..4e7a8b6
--- /dev/null
+++ b/media/java/android/media/audiofx/NoiseSuppressor.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2011 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.audiofx;
+
+/**
+ * Noise Suppressor (NS).
+ * <p>Noise suppression (NS) is an audio pre-processing which removes background noise from the
+ * captured signal. The component of the signal considered as noise can be either stationary
+ * (car/airplane engine, AC system) or non-stationary (other peoples conversations, car horn) for
+ * more advanced implementations.
+ * <p>NS is mostly used by voice communication applications (voice chat, video conferencing,
+ * SIP calls).
+ * <p>An application creates a NoiseSuppressor object to instantiate and control an NS
+ * engine in the audio framework.
+ * <p>To attach the NoiseSuppressor to a particular {@link android.media.AudioRecord},
+ * specify the audio session ID of this AudioRecord when constructing the NoiseSuppressor.
+ * The audio session is retrieved by calling
+ * {@link android.media.AudioRecord#getAudioSessionId()} on the AudioRecord instance.
+ * <p>On some devices, NS can be inserted by default in the capture path by the platform
+ * according to the {@link android.media.MediaRecorder.AudioSource} used. The application can
+ * query which pre-processings are currently applied to an AudioRecord instance by calling
+ * {@link android.media.audiofx.AudioEffect#queryPreProcessings(int)} with the audio session of the
+ * AudioRecord.
+ * <p>See {@link android.media.audiofx.AudioEffect} class for more details on
+ * controlling audio effects.
+ * @hide
+ */
+
+public class NoiseSuppressor extends AudioEffect {
+
+    private final static String TAG = "NoiseSuppressor";
+
+    /**
+     * Class constructor.
+     * <p> The application must catch exceptions when creating an NoiseSuppressor as the
+     * constructor is not guarantied to succeed:
+     * <ul>
+     *  <li>IllegalArgumentException is thrown if the device does not implement an NS</li>
+     *  <li>UnsupportedOperationException is thrown is the resources allocated to audio
+     *  pre-procesing are currently exceeded.</li>
+     * </ul>
+     *
+     * @param audioSession system wide unique audio session identifier. The NoiseSuppressor
+     * will be applied to the AudioRecord with the same audio session.
+     *
+     * @throws java.lang.IllegalArgumentException
+     * @throws java.lang.UnsupportedOperationException
+     * @throws java.lang.RuntimeException
+     */
+    public NoiseSuppressor(int audioSession)
+            throws IllegalArgumentException, UnsupportedOperationException, RuntimeException {
+        super(EFFECT_TYPE_NS, EFFECT_TYPE_NULL, 0, audioSession);
+    }
+}
diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp
index e71e727..57cabe2 100644
--- a/media/jni/audioeffect/android_media_AudioEffect.cpp
+++ b/media/jni/audioeffect/android_media_AudioEffect.cpp
@@ -725,18 +725,22 @@
             goto queryEffects_failure;
         }
 
+        if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
+            jdescConnect = env->NewStringUTF("Auxiliary");
+        } else if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_INSERT) {
+            jdescConnect = env->NewStringUTF("Insert");
+        } else if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC) {
+            jdescConnect = env->NewStringUTF("Pre Processing");
+        } else {
+            continue;
+        }
+
         AudioEffect::guidToString(&desc.type, str, EFFECT_STRING_LEN_MAX);
         jdescType = env->NewStringUTF(str);
 
         AudioEffect::guidToString(&desc.uuid, str, EFFECT_STRING_LEN_MAX);
         jdescUuid = env->NewStringUTF(str);
 
-        if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
-            jdescConnect = env->NewStringUTF("Auxiliary");
-        } else {
-            jdescConnect = env->NewStringUTF("Insert");
-        }
-
         jdescName = env->NewStringUTF(desc.name);
         jdescImplementor = env->NewStringUTF(desc.implementor);
 
@@ -771,6 +775,87 @@
 
 }
 
+
+
+static jobjectArray
+android_media_AudioEffect_native_queryPreProcessings(JNIEnv *env, jclass clazz, jint audioSession)
+{
+    // kDefaultNumEffects is a "reasonable" value ensuring that only one query will be enough on
+    // most devices to get all active audio pre processing on a given session.
+    static const uint32_t kDefaultNumEffects = 5;
+
+    effect_descriptor_t *descriptors = new effect_descriptor_t[kDefaultNumEffects];
+    uint32_t numEffects = kDefaultNumEffects;
+
+    status_t status = AudioEffect::queryDefaultPreProcessing(audioSession,
+                                           descriptors,
+                                           &numEffects);
+    if ((status != NO_ERROR && status != NO_MEMORY) ||
+            numEffects == 0) {
+        delete[] descriptors;
+        return NULL;
+    }
+    if (status == NO_MEMORY) {
+        delete [] descriptors;
+        descriptors = new effect_descriptor_t[numEffects];
+        status = AudioEffect::queryDefaultPreProcessing(audioSession,
+                                               descriptors,
+                                               &numEffects);
+    }
+    if (status != NO_ERROR || numEffects == 0) {
+        delete[] descriptors;
+        return NULL;
+    }
+    LOGV("queryDefaultPreProcessing() got %d effects", numEffects);
+
+    jobjectArray ret = env->NewObjectArray(numEffects, fields.clazzDesc, NULL);
+    if (ret == NULL) {
+        delete[] descriptors;
+        return ret;
+    }
+
+    char str[EFFECT_STRING_LEN_MAX];
+    jstring jdescType;
+    jstring jdescUuid;
+    jstring jdescConnect;
+    jstring jdescName;
+    jstring jdescImplementor;
+    jobject jdesc;
+
+    for (uint32_t i = 0; i < numEffects; i++) {
+
+        AudioEffect::guidToString(&descriptors[i].type, str, EFFECT_STRING_LEN_MAX);
+        jdescType = env->NewStringUTF(str);
+        AudioEffect::guidToString(&descriptors[i].uuid, str, EFFECT_STRING_LEN_MAX);
+        jdescUuid = env->NewStringUTF(str);
+        jdescConnect = env->NewStringUTF("Pre Processing");
+        jdescName = env->NewStringUTF(descriptors[i].name);
+        jdescImplementor = env->NewStringUTF(descriptors[i].implementor);
+
+        jdesc = env->NewObject(fields.clazzDesc,
+                               fields.midDescCstor,
+                               jdescType,
+                               jdescUuid,
+                               jdescConnect,
+                               jdescName,
+                               jdescImplementor);
+        env->DeleteLocalRef(jdescType);
+        env->DeleteLocalRef(jdescUuid);
+        env->DeleteLocalRef(jdescConnect);
+        env->DeleteLocalRef(jdescName);
+        env->DeleteLocalRef(jdescImplementor);
+        if (jdesc == NULL) {
+            LOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)");
+            env->DeleteLocalRef(ret);
+            return NULL;;
+        }
+
+        env->SetObjectArrayElement(ret, i, jdesc);
+   }
+
+   return ret;
+}
+
 // ----------------------------------------------------------------------------
 
 // Dalvik VM type signatures
@@ -787,6 +872,8 @@
     {"native_getParameter",  "(I[BI[B)I",  (void *)android_media_AudioEffect_native_getParameter},
     {"native_command",       "(II[BI[B)I", (void *)android_media_AudioEffect_native_command},
     {"native_query_effects", "()[Ljava/lang/Object;", (void *)android_media_AudioEffect_native_queryEffects},
+    {"native_query_pre_processing", "(I)[Ljava/lang/Object;",
+            (void *)android_media_AudioEffect_native_queryPreProcessings},
 };
 
 
diff --git a/media/libmedia/AudioEffect.cpp b/media/libmedia/AudioEffect.cpp
index 3919551..0633744 100644
--- a/media/libmedia/AudioEffect.cpp
+++ b/media/libmedia/AudioEffect.cpp
@@ -419,6 +419,15 @@
     return af->getEffectDescriptor(uuid, descriptor);
 }
 
+
+status_t AudioEffect::queryDefaultPreProcessing(int audioSession,
+                                          effect_descriptor_t *descriptors,
+                                          uint32_t *count)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->queryDefaultPreProcessing(audioSession, descriptors, count);
+}
 // -------------------------------------------------------------------------
 
 status_t AudioEffect::stringToGuid(const char *str, effect_uuid_t *guid)
diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp
index 49d410f..15f4be0 100644
--- a/media/libmedia/IAudioPolicyService.cpp
+++ b/media/libmedia/IAudioPolicyService.cpp
@@ -53,6 +53,7 @@
     UNREGISTER_EFFECT,
     IS_STREAM_ACTIVE,
     GET_DEVICES_FOR_STREAM,
+    QUERY_DEFAULT_PRE_PROCESSING
 };
 
 class BpAudioPolicyService : public BpInterface<IAudioPolicyService>
@@ -321,6 +322,31 @@
         remote()->transact(IS_STREAM_ACTIVE, data, &reply);
         return reply.readInt32();
     }
+
+    virtual status_t queryDefaultPreProcessing(int audioSession,
+                                               effect_descriptor_t *descriptors,
+                                               uint32_t *count)
+    {
+        if (descriptors == NULL || count == NULL) {
+            return BAD_VALUE;
+        }
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.writeInt32(audioSession);
+        data.writeInt32(*count);
+        status_t status = remote()->transact(QUERY_DEFAULT_PRE_PROCESSING, data, &reply);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        status = static_cast <status_t> (reply.readInt32());
+        uint32_t retCount = reply.readInt32();
+        if (retCount != 0) {
+            uint32_t numDesc = (retCount < *count) ? retCount : *count;
+            reply.read(descriptors, sizeof(effect_descriptor_t) * numDesc);
+        }
+        *count = retCount;
+        return status;
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService");
@@ -559,6 +585,29 @@
             return NO_ERROR;
         } break;
 
+        case QUERY_DEFAULT_PRE_PROCESSING: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            int audioSession = data.readInt32();
+            uint32_t count = data.readInt32();
+            uint32_t retCount = count;
+            effect_descriptor_t *descriptors =
+                    (effect_descriptor_t *)new char[count * sizeof(effect_descriptor_t)];
+            status_t status = queryDefaultPreProcessing(audioSession, descriptors, &retCount);
+            reply->writeInt32(status);
+            if (status != NO_ERROR && status != NO_MEMORY) {
+                retCount = 0;
+            }
+            reply->writeInt32(retCount);
+            if (retCount) {
+                if (retCount < count) {
+                    count = retCount;
+                }
+                reply->write(descriptors, sizeof(effect_descriptor_t) * count);
+            }
+            delete[] descriptors;
+            return status;
+        }
+
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp
index dd1e153..6d06d83 100644
--- a/services/audioflinger/AudioPolicyService.cpp
+++ b/services/audioflinger/AudioPolicyService.cpp
@@ -497,6 +497,43 @@
     return mpAudioPolicy->is_stream_active(mpAudioPolicy, stream, inPastMs);
 }
 
+status_t AudioPolicyService::queryDefaultPreProcessing(int audioSession,
+                                                       effect_descriptor_t *descriptors,
+                                                       uint32_t *count)
+{
+
+    if (mpAudioPolicy == NULL) {
+        *count = 0;
+        return NO_INIT;
+    }
+    Mutex::Autolock _l(mLock);
+    status_t status = NO_ERROR;
+
+    size_t index;
+    for (index = 0; index < mInputs.size(); index++) {
+        if (mInputs.valueAt(index)->mSessionId == audioSession) {
+            break;
+        }
+    }
+    if (index == mInputs.size()) {
+        *count = 0;
+        return BAD_VALUE;
+    }
+    Vector< sp<AudioEffect> > effects = mInputs.valueAt(index)->mEffects;
+
+    for (size_t i = 0; i < effects.size(); i++) {
+        effect_descriptor_t desc = effects[i]->descriptor();
+        if (i < *count) {
+            memcpy(descriptors + i, &desc, sizeof(effect_descriptor_t));
+        }
+    }
+    if (effects.size() > *count) {
+        status = NO_MEMORY;
+    }
+    *count = effects.size();
+    return status;
+}
+
 void AudioPolicyService::binderDied(const wp<IBinder>& who) {
     LOGW("binderDied() %p, tid %d, calling tid %d", who.unsafe_get(), gettid(),
             IPCThreadState::self()->getCallingPid());
diff --git a/services/audioflinger/AudioPolicyService.h b/services/audioflinger/AudioPolicyService.h
index 62ad29e..834b794 100644
--- a/services/audioflinger/AudioPolicyService.h
+++ b/services/audioflinger/AudioPolicyService.h
@@ -104,6 +104,9 @@
     virtual status_t unregisterEffect(int id);
     virtual bool isStreamActive(int stream, uint32_t inPastMs = 0) const;
 
+    virtual status_t queryDefaultPreProcessing(int audioSession,
+                                              effect_descriptor_t *descriptors,
+                                              uint32_t *count);
     virtual     status_t    onTransact(
                                 uint32_t code,
                                 const Parcel& data,