Merge "Add libaudioclient to libwilhelm"
am: bb45b9aff5

Change-Id: Ib0ba816d0b08a6858e9307ab2f2886d0b014c51d
diff --git a/include/SLES/OpenSLES_Android.h b/include/SLES/OpenSLES_Android.h
index dc85580..7122058 100644
--- a/include/SLES/OpenSLES_Android.h
+++ b/include/SLES/OpenSLES_Android.h
@@ -417,10 +417,6 @@
         SLAndroidAcousticEchoCancellationItf self,
         SLboolean *pEnabled
     );
-    SLresult (*IsAvailable)(
-        SLAndroidAcousticEchoCancellationItf self,
-        SLboolean *pEnabled
-    );
 };
 
 /*---------------------------------------------------------------------------*/
@@ -440,10 +436,6 @@
         SLAndroidAutomaticGainControlItf self,
         SLboolean *pEnabled
     );
-    SLresult (*IsAvailable)(
-        SLAndroidAutomaticGainControlItf self,
-        SLboolean *pEnabled
-    );
 };
 
 /*---------------------------------------------------------------------------*/
@@ -463,10 +455,6 @@
         SLAndroidNoiseSuppressionItf self,
         SLboolean *pEnabled
     );
-    SLresult (*IsAvailable)(
-        SLAndroidNoiseSuppressionItf self,
-        SLboolean *pEnabled
-    );
 };
 
 #ifdef __cplusplus
diff --git a/include/SLES/OpenSLES_AndroidConfiguration.h b/include/SLES/OpenSLES_AndroidConfiguration.h
index 3846dcd..ae12f77 100644
--- a/include/SLES/OpenSLES_AndroidConfiguration.h
+++ b/include/SLES/OpenSLES_AndroidConfiguration.h
@@ -68,6 +68,35 @@
 #define SL_ANDROID_STREAM_NOTIFICATION ((SLint32) 0x00000005)
 
 
+/*---------------------------------------------------------------------------*/
+/* Android AudioPlayer and AudioRecorder configuration                       */
+/*---------------------------------------------------------------------------*/
+
+/** Audio Performance mode.
+ * Performance mode tells the framework how to configure the audio path
+ * for a player or recorder according to application performance and
+ * functional requirements.
+ * It affects the output or input latency based on acceptable tradeoffs on
+ * battery drain and use of pre or post processing effects.
+ * Performance mode should be set before realizing the object and should be
+ * read after realizing the object to check if the requested mode could be
+ * granted or not.
+ */
+/** Audio Performance mode key */
+#define SL_ANDROID_KEY_PERFORMANCE_MODE ((const SLchar*) "androidPerformanceMode")
+
+/** Audio performance values */
+/*      No specific performance requirement. Allows HW and SW pre/post processing. */
+#define SL_ANDROID_PERFORMANCE_NONE ((SLuint32) 0x00000000)
+/*      Priority given to latency. No HW or software pre/post processing.
+ *      This is the default if no performance mode is specified. */
+#define SL_ANDROID_PERFORMANCE_LATENCY ((SLuint32) 0x00000001)
+/*      Priority given to latency while still allowing HW pre and post processing. */
+#define SL_ANDROID_PERFORMANCE_LATENCY_EFFECTS ((SLuint32) 0x00000002)
+/*      Priority given to power saving if latency is not a concern.
+ *      Allows HW and SW pre/post processing. */
+#define SL_ANDROID_PERFORMANCE_POWER_SAVING ((SLuint32) 0x00000003)
+
 
 #ifdef __cplusplus
 }
diff --git a/src/Android.mk b/src/Android.mk
index cbe2d64..a4f8a0a 100644
--- a/src/Android.mk
+++ b/src/Android.mk
@@ -10,6 +10,7 @@
 LOCAL_C_INCLUDES:= $(LOCAL_PATH)/../include
 
 LOCAL_CFLAGS += -fvisibility=hidden -UNDEBUG
+LOCAL_CFLAGS += -Wall -Werror
 
 LOCAL_MODULE := libOpenSLESUT
 
@@ -24,6 +25,7 @@
 # optional, see comments in MPH_to.c: -DUSE_DESIGNATED_INITIALIZERS -S
 # and also see ../tools/mphgen/Makefile
 LOCAL_CFLAGS += -DUSE_DESIGNATED_INITIALIZERS -UNDEBUG
+LOCAL_CFLAGS += -Wall -Werror
 
 LOCAL_SRC_FILES:=                     \
         assert.cpp \
@@ -187,7 +189,6 @@
         libcutils                 \
         libgui                    \
         libdl                     \
-        libeffects                \
         libandroid_runtime
 
 LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libmedia
@@ -219,6 +220,7 @@
 LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libwilhelm
 LOCAL_CFLAGS += -DLI_API= -fvisibility=hidden -UNDEBUG \
                 -DSL_API='__attribute__((visibility("default")))'
+LOCAL_CFLAGS += -Wall -Werror
 LOCAL_SHARED_LIBRARIES := libwilhelm liblog
 include $(BUILD_SHARED_LIBRARY)
 
@@ -232,5 +234,6 @@
 LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libwilhelm
 LOCAL_CFLAGS += -DLI_API= -fvisibility=hidden -UNDEBUG \
                 -DXA_API='__attribute__((visibility("default")))'
+LOCAL_CFLAGS += -Wall -Werror
 LOCAL_SHARED_LIBRARIES := libwilhelm liblog
 include $(BUILD_SHARED_LIBRARY)
diff --git a/src/OpenSLES_IID.cpp b/src/OpenSLES_IID.cpp
index 272ac47..7da03c7 100644
--- a/src/OpenSLES_IID.cpp
+++ b/src/OpenSLES_IID.cpp
@@ -254,9 +254,9 @@
 // Android API level 20 extended interfaces
 
     // SL_IID_ANDROIDACOUSTICECHOCANCELLATION
-    { 0x4786de20, 0xd622, 0x11e3, 0xbd30, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } },
+    { 0x7b491460, 0x8d4d, 0x11e0, 0xbd61, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } },
     // SL_IID_ANDROIDAUTOMATICGAINCONTROL
-    { 0xadb80fc0, 0xd622, 0x11e3, 0x927e, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } },
+    { 0x0a8abfe0, 0x654c, 0x11e0, 0xba26, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } },
     // SL_IID_ANDROIDNOISESUPPRESSION
-    { 0xbb85ff40, 0xd622, 0x11e3, 0xb770, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } },
+    { 0x58b4b260, 0x8e06, 0x11e0, 0xaa8e, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } },
 };
diff --git a/src/android/AudioPlayer_to_android.cpp b/src/android/AudioPlayer_to_android.cpp
index 4492d02..d188c45 100644
--- a/src/android/AudioPlayer_to_android.cpp
+++ b/src/android/AudioPlayer_to_android.cpp
@@ -34,6 +34,7 @@
                                     android::sp<android::AudioEffect> > ;
 
 #define KEY_STREAM_TYPE_PARAMSIZE  sizeof(SLint32)
+#define KEY_PERFORMANCE_MODE_PARAMSIZE  sizeof(SLint32)
 
 #define AUDIOTRACK_MIN_PLAYBACKRATE_PERMILLE  500
 #define AUDIOTRACK_MAX_PLAYBACKRATE_PERMILLE 2000
@@ -484,6 +485,42 @@
     return result;
 }
 
+//-----------------------------------------------------------------------------
+SLresult audioPlayer_setPerformanceMode(CAudioPlayer* ap, SLuint32 mode) {
+    SLresult result = SL_RESULT_SUCCESS;
+    SL_LOGV("performance mode set to %d", mode);
+
+    SLuint32 perfMode = ANDROID_PERFORMANCE_MODE_DEFAULT;
+    switch (mode) {
+    case SL_ANDROID_PERFORMANCE_LATENCY:
+        perfMode = ANDROID_PERFORMANCE_MODE_LATENCY;
+        break;
+    case SL_ANDROID_PERFORMANCE_LATENCY_EFFECTS:
+        perfMode = ANDROID_PERFORMANCE_MODE_LATENCY_EFFECTS;
+        break;
+    case SL_ANDROID_PERFORMANCE_NONE:
+        perfMode = ANDROID_PERFORMANCE_MODE_NONE;
+        break;
+    case SL_ANDROID_PERFORMANCE_POWER_SAVING:
+        perfMode = ANDROID_PERFORMANCE_MODE_POWER_SAVING;
+        break;
+    default:
+        SL_LOGE(ERROR_CONFIG_PERF_MODE_UNKNOWN);
+        result = SL_RESULT_PARAMETER_INVALID;
+        break;
+    }
+
+    // performance mode needs to be set before the object is realized
+    // (ap->mAudioTrack is supposed to be NULL until then)
+    if (SL_OBJECT_STATE_UNREALIZED != ap->mObject.mState) {
+        SL_LOGE(ERROR_CONFIG_PERF_MODE_REALIZED);
+        result = SL_RESULT_PRECONDITIONS_VIOLATED;
+    } else {
+        ap->mPerformanceMode = perfMode;
+    }
+
+    return result;
+}
 
 //-----------------------------------------------------------------------------
 SLresult audioPlayer_getStreamType(CAudioPlayer* ap, SLint32 *pType) {
@@ -518,6 +555,31 @@
     return result;
 }
 
+//-----------------------------------------------------------------------------
+SLresult audioPlayer_getPerformanceMode(CAudioPlayer* ap, SLuint32 *pMode) {
+    SLresult result = SL_RESULT_SUCCESS;
+
+    switch (ap->mPerformanceMode) {
+    case ANDROID_PERFORMANCE_MODE_LATENCY:
+        *pMode = SL_ANDROID_PERFORMANCE_LATENCY;
+        break;
+    case ANDROID_PERFORMANCE_MODE_LATENCY_EFFECTS:
+        *pMode = SL_ANDROID_PERFORMANCE_LATENCY_EFFECTS;
+        break;
+    case ANDROID_PERFORMANCE_MODE_NONE:
+        *pMode = SL_ANDROID_PERFORMANCE_NONE;
+        break;
+    case ANDROID_PERFORMANCE_MODE_POWER_SAVING:
+        *pMode = SL_ANDROID_PERFORMANCE_POWER_SAVING;
+        break;
+    default:
+        result = SL_RESULT_INTERNAL_ERROR;
+        *pMode = SL_ANDROID_PERFORMANCE_LATENCY;
+        break;
+    }
+
+    return result;
+}
 
 //-----------------------------------------------------------------------------
 void audioPlayer_auxEffectUpdate(CAudioPlayer* ap) {
@@ -1289,6 +1351,7 @@
     // android::AudioSystem::acquireAudioSessionId(pAudioPlayer->mSessionId);
 
     pAudioPlayer->mStreamType = ANDROID_DEFAULT_OUTPUT_STREAM_TYPE;
+    pAudioPlayer->mPerformanceMode = ANDROID_PERFORMANCE_MODE_DEFAULT;
 
     // mAudioTrack
     pAudioPlayer->mCallbackProtector = new android::CallbackProtector();
@@ -1336,6 +1399,15 @@
         } else {
             result = audioPlayer_setStreamType(ap, *(SLuint32*)pConfigValue);
         }
+    } else if (strcmp((const char*)configKey, (const char*)SL_ANDROID_KEY_PERFORMANCE_MODE) == 0) {
+
+        // performance mode
+        if (KEY_PERFORMANCE_MODE_PARAMSIZE > valueSize) {
+            SL_LOGE(ERROR_CONFIG_VALUESIZE_TOO_LOW);
+            result = SL_RESULT_BUFFER_INSUFFICIENT;
+        } else {
+            result = audioPlayer_setPerformanceMode(ap, *(SLuint32*)pConfigValue);
+        }
 
     } else {
         SL_LOGE(ERROR_CONFIG_UNKNOWN_KEY);
@@ -1366,6 +1438,19 @@
         }
         *pValueSize = KEY_STREAM_TYPE_PARAMSIZE;
 
+    } else if (strcmp((const char*)configKey, (const char*)SL_ANDROID_KEY_PERFORMANCE_MODE) == 0) {
+
+        // performance mode
+        if (NULL == pConfigValue) {
+            result = SL_RESULT_SUCCESS;
+        } else if (KEY_PERFORMANCE_MODE_PARAMSIZE > *pValueSize) {
+            SL_LOGE(ERROR_CONFIG_VALUESIZE_TOO_LOW);
+            result = SL_RESULT_BUFFER_INSUFFICIENT;
+        } else {
+            result = audioPlayer_getPerformanceMode(ap, (SLuint32*)pConfigValue);
+        }
+        *pValueSize = KEY_PERFORMANCE_MODE_PARAMSIZE;
+
     } else {
         SL_LOGE(ERROR_CONFIG_UNKNOWN_KEY);
         result = SL_RESULT_PARAMETER_INVALID;
@@ -1375,10 +1460,11 @@
 }
 
 
-// Called from android_audioPlayer_realize for a PCM buffer queue player
-// to determine if it can use a fast track.
-static bool canUseFastTrack(CAudioPlayer *pAudioPlayer)
+// Called from android_audioPlayer_realize for a PCM buffer queue player before creating the
+// AudioTrack to determine which performance modes are allowed based on effect interfaces present
+static void checkAndSetPerformanceModePre(CAudioPlayer *pAudioPlayer)
 {
+    SLuint32 allowedModes = ANDROID_PERFORMANCE_MODE_ALL;
     assert(pAudioPlayer->mAndroidObjType == AUDIOPLAYER_FROM_PCM_BUFFERQUEUE);
 
     // no need to check the buffer queue size, application side
@@ -1392,7 +1478,6 @@
     // If a blacklisted interface is added after realization using
     // DynamicInterfaceManagement::AddInterface,
     // then this won't be detected but the interface will be ineffective.
-    bool blacklistResult = true;
     static const unsigned blacklist[] = {
         MPH_BASSBOOST,
         MPH_EFFECTSEND,
@@ -1407,11 +1492,16 @@
     };
     for (unsigned i = 0; i < sizeof(blacklist)/sizeof(blacklist[0]); ++i) {
         if (IsInterfaceInitialized(&pAudioPlayer->mObject, blacklist[i])) {
-            blacklistResult = false;
+            //TODO: query effect for EFFECT_FLAG_HW_ACC_xx flag to refine mode
+            allowedModes &=
+                    ~(ANDROID_PERFORMANCE_MODE_LATENCY|ANDROID_PERFORMANCE_MODE_LATENCY_EFFECTS);
             break;
         }
     }
 #if LOG_NDEBUG == 0
+    bool blacklistResult = (
+            (allowedModes &
+                (ANDROID_PERFORMANCE_MODE_LATENCY|ANDROID_PERFORMANCE_MODE_LATENCY_EFFECTS)) != 0);
     bool whitelistResult = true;
     static const unsigned whitelist[] = {
         MPH_BUFFERQUEUE,
@@ -1440,13 +1530,48 @@
     }
     if (whitelistResult != blacklistResult) {
         SL_LOGW("whitelistResult != blacklistResult");
-        // and use blacklistResult below
     }
 #endif
-    return blacklistResult;
+    if (pAudioPlayer->mPerformanceMode == ANDROID_PERFORMANCE_MODE_LATENCY) {
+        if ((allowedModes & ANDROID_PERFORMANCE_MODE_LATENCY) == 0) {
+            pAudioPlayer->mPerformanceMode = ANDROID_PERFORMANCE_MODE_LATENCY_EFFECTS;
+        }
+    }
+    if (pAudioPlayer->mPerformanceMode == ANDROID_PERFORMANCE_MODE_LATENCY_EFFECTS) {
+        if ((allowedModes & ANDROID_PERFORMANCE_MODE_LATENCY_EFFECTS) == 0) {
+            pAudioPlayer->mPerformanceMode = ANDROID_PERFORMANCE_MODE_NONE;
+        }
+    }
 }
 
-
+// Called from android_audioPlayer_realize for a PCM buffer queue player after creating the
+// AudioTrack to adjust performance mode based on actual output flags
+static void checkAndSetPerformanceModePost(CAudioPlayer *pAudioPlayer)
+{
+    audio_output_flags_t flags = pAudioPlayer->mAudioTrack->getFlags();
+    switch (pAudioPlayer->mPerformanceMode) {
+    case ANDROID_PERFORMANCE_MODE_LATENCY:
+        if ((flags & (AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_RAW)) ==
+                (AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_RAW)) {
+            break;
+        }
+        pAudioPlayer->mPerformanceMode = ANDROID_PERFORMANCE_MODE_LATENCY_EFFECTS;
+        /* FALL THROUGH */
+    case ANDROID_PERFORMANCE_MODE_LATENCY_EFFECTS:
+        if ((flags & AUDIO_OUTPUT_FLAG_FAST) == 0) {
+            pAudioPlayer->mPerformanceMode = ANDROID_PERFORMANCE_MODE_NONE;
+        }
+        break;
+    case ANDROID_PERFORMANCE_MODE_POWER_SAVING:
+        if ((flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) == 0) {
+            pAudioPlayer->mPerformanceMode = ANDROID_PERFORMANCE_MODE_NONE;
+        }
+        break;
+    case ANDROID_PERFORMANCE_MODE_NONE:
+    default:
+        break;
+    }
+}
 //-----------------------------------------------------------------------------
 // FIXME abstract out the diff between CMediaPlayer and CAudioPlayer
 SLresult android_audioPlayer_realize(CAudioPlayer *pAudioPlayer, SLboolean async) {
@@ -1488,16 +1613,31 @@
             df_pcm->channelMask,
             channelMask);
 
+        checkAndSetPerformanceModePre(pAudioPlayer);
+
         audio_output_flags_t policy;
-        int32_t notificationFrames;
-        if (canUseFastTrack(pAudioPlayer)) {
+        switch (pAudioPlayer->mPerformanceMode) {
+        case ANDROID_PERFORMANCE_MODE_POWER_SAVING:
+            policy = AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
+            break;
+        case ANDROID_PERFORMANCE_MODE_NONE:
+            policy = AUDIO_OUTPUT_FLAG_NONE;
+            break;
+        case ANDROID_PERFORMANCE_MODE_LATENCY_EFFECTS:
+            policy = AUDIO_OUTPUT_FLAG_FAST;
+            break;
+        case ANDROID_PERFORMANCE_MODE_LATENCY:
+        default:
             policy = (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_RAW);
+            break;
+        }
+
+        int32_t notificationFrames;
+        if ((policy & AUDIO_OUTPUT_FLAG_FAST) != 0) {
             // negative notificationFrames is the number of notifications (sub-buffers) per track buffer
             // for details see the explanation at frameworks/av/include/media/AudioTrack.h
             notificationFrames = -pAudioPlayer->mBufferQueue.mNumBuffers;
         } else {
-            policy = AUDIO_OUTPUT_FLAG_NONE;
-            // use default notifications
             notificationFrames = 0;
         }
 
@@ -1521,6 +1661,9 @@
             return result;
         }
 
+        // update performance mode according to actual flags granted to AudioTrack
+        checkAndSetPerformanceModePost(pAudioPlayer);
+
         // initialize platform-independent CAudioPlayer fields
 
         pAudioPlayer->mNumChannels = df_pcm->numChannels;
@@ -1545,6 +1688,8 @@
             if (j_env->ExceptionCheck()) {
                 SL_LOGE("Java exception releasing recorder routing object.");
                 result = SL_RESULT_INTERNAL_ERROR;
+                pAudioPlayer->mAudioTrack.clear();
+                return result;
             }
         }
     }
@@ -1674,25 +1819,34 @@
         break;
     }
 
-    // proceed with effect initialization
-    // initialize EQ
-    // FIXME use a table of effect descriptors when adding support for more effects
-    if (memcmp(SL_IID_EQUALIZER, &pAudioPlayer->mEqualizer.mEqDescriptor.type,
-            sizeof(effect_uuid_t)) == 0) {
-        SL_LOGV("Need to initialize EQ for AudioPlayer=%p", pAudioPlayer);
-        android_eq_init(pAudioPlayer->mSessionId, &pAudioPlayer->mEqualizer);
-    }
-    // initialize BassBoost
-    if (memcmp(SL_IID_BASSBOOST, &pAudioPlayer->mBassBoost.mBassBoostDescriptor.type,
-            sizeof(effect_uuid_t)) == 0) {
-        SL_LOGV("Need to initialize BassBoost for AudioPlayer=%p", pAudioPlayer);
-        android_bb_init(pAudioPlayer->mSessionId, &pAudioPlayer->mBassBoost);
-    }
-    // initialize Virtualizer
-    if (memcmp(SL_IID_VIRTUALIZER, &pAudioPlayer->mVirtualizer.mVirtualizerDescriptor.type,
-               sizeof(effect_uuid_t)) == 0) {
-        SL_LOGV("Need to initialize Virtualizer for AudioPlayer=%p", pAudioPlayer);
-        android_virt_init(pAudioPlayer->mSessionId, &pAudioPlayer->mVirtualizer);
+    if (result == SL_RESULT_SUCCESS) {
+        // proceed with effect initialization
+        // initialize EQ
+        // FIXME use a table of effect descriptors when adding support for more effects
+
+        // No session effects allowed even in latency with effects performance mode because HW
+        // accelerated effects are only tolerated as post processing in this mode
+        if ((pAudioPlayer->mAndroidObjType != AUDIOPLAYER_FROM_PCM_BUFFERQUEUE) ||
+                ((pAudioPlayer->mPerformanceMode != ANDROID_PERFORMANCE_MODE_LATENCY) &&
+                 (pAudioPlayer->mPerformanceMode != ANDROID_PERFORMANCE_MODE_LATENCY_EFFECTS))) {
+            if (memcmp(SL_IID_EQUALIZER, &pAudioPlayer->mEqualizer.mEqDescriptor.type,
+                    sizeof(effect_uuid_t)) == 0) {
+                SL_LOGV("Need to initialize EQ for AudioPlayer=%p", pAudioPlayer);
+                android_eq_init(pAudioPlayer->mSessionId, &pAudioPlayer->mEqualizer);
+            }
+            // initialize BassBoost
+            if (memcmp(SL_IID_BASSBOOST, &pAudioPlayer->mBassBoost.mBassBoostDescriptor.type,
+                    sizeof(effect_uuid_t)) == 0) {
+                SL_LOGV("Need to initialize BassBoost for AudioPlayer=%p", pAudioPlayer);
+                android_bb_init(pAudioPlayer->mSessionId, &pAudioPlayer->mBassBoost);
+            }
+            // initialize Virtualizer
+            if (memcmp(SL_IID_VIRTUALIZER, &pAudioPlayer->mVirtualizer.mVirtualizerDescriptor.type,
+                       sizeof(effect_uuid_t)) == 0) {
+                SL_LOGV("Need to initialize Virtualizer for AudioPlayer=%p", pAudioPlayer);
+                android_virt_init(pAudioPlayer->mSessionId, &pAudioPlayer->mVirtualizer);
+            }
+        }
     }
 
     // initialize EffectSend
diff --git a/src/android/AudioRecorder_to_android.cpp b/src/android/AudioRecorder_to_android.cpp
index fbf8890..361499d 100644
--- a/src/android/AudioRecorder_to_android.cpp
+++ b/src/android/AudioRecorder_to_android.cpp
@@ -27,6 +27,7 @@
 
 #define KEY_RECORDING_SOURCE_PARAMSIZE  sizeof(SLuint32)
 #define KEY_RECORDING_PRESET_PARAMSIZE  sizeof(SLuint32)
+#define KEY_PERFORMANCE_MODE_PARAMSIZE  sizeof(SLuint32)
 
 //-----------------------------------------------------------------------------
 // Internal utility functions
@@ -72,6 +73,44 @@
 }
 
 
+//-----------------------------------------------------------------------------
+SLresult audioRecorder_setPerformanceMode(CAudioRecorder* ar, SLuint32 mode) {
+    SLresult result = SL_RESULT_SUCCESS;
+    SL_LOGV("performance mode set to %d", mode);
+
+    SLuint32 perfMode = ANDROID_PERFORMANCE_MODE_DEFAULT;
+    switch (mode) {
+    case SL_ANDROID_PERFORMANCE_LATENCY:
+        perfMode = ANDROID_PERFORMANCE_MODE_LATENCY;
+        break;
+    case SL_ANDROID_PERFORMANCE_LATENCY_EFFECTS:
+        perfMode = ANDROID_PERFORMANCE_MODE_LATENCY_EFFECTS;
+        break;
+    case SL_ANDROID_PERFORMANCE_NONE:
+        perfMode = ANDROID_PERFORMANCE_MODE_NONE;
+        break;
+    case SL_ANDROID_PERFORMANCE_POWER_SAVING:
+        perfMode = ANDROID_PERFORMANCE_MODE_POWER_SAVING;
+        break;
+    default:
+        SL_LOGE(ERROR_CONFIG_PERF_MODE_UNKNOWN);
+        result = SL_RESULT_PARAMETER_INVALID;
+        break;
+    }
+
+    // performance mode needs to be set before the object is realized
+    // (ar->mAudioRecord is supposed to be NULL until then)
+    if (SL_OBJECT_STATE_UNREALIZED != ar->mObject.mState) {
+        SL_LOGE(ERROR_CONFIG_PERF_MODE_REALIZED);
+        result = SL_RESULT_PRECONDITIONS_VIOLATED;
+    } else {
+        ar->mPerformanceMode = perfMode;
+    }
+
+    return result;
+}
+
+
 SLresult audioRecorder_getPreset(CAudioRecorder* ar, SLuint32* pPreset) {
     SLresult result = SL_RESULT_SUCCESS;
 
@@ -107,6 +146,33 @@
 }
 
 
+//-----------------------------------------------------------------------------
+SLresult audioRecorder_getPerformanceMode(CAudioRecorder* ar, SLuint32 *pMode) {
+    SLresult result = SL_RESULT_SUCCESS;
+
+    switch (ar->mPerformanceMode) {
+    case ANDROID_PERFORMANCE_MODE_LATENCY:
+        *pMode = SL_ANDROID_PERFORMANCE_LATENCY;
+        break;
+    case ANDROID_PERFORMANCE_MODE_LATENCY_EFFECTS:
+        *pMode = SL_ANDROID_PERFORMANCE_LATENCY_EFFECTS;
+        break;
+    case ANDROID_PERFORMANCE_MODE_NONE:
+        *pMode = SL_ANDROID_PERFORMANCE_NONE;
+        break;
+    case ANDROID_PERFORMANCE_MODE_POWER_SAVING:
+        *pMode = SL_ANDROID_PERFORMANCE_POWER_SAVING;
+        break;
+    default:
+        result = SL_RESULT_INTERNAL_ERROR;
+        *pMode = SL_ANDROID_PERFORMANCE_LATENCY;
+        break;
+    }
+
+    return result;
+}
+
+
 void audioRecorder_handleNewPos_lockRecord(CAudioRecorder* ar) {
     //SL_LOGV("received event EVENT_NEW_POS from AudioRecord");
     slRecordCallback callback = NULL;
@@ -353,6 +419,7 @@
         ar->mAudioRecord.clear();
         ar->mCallbackProtector = new android::CallbackProtector();
         ar->mRecordSource = AUDIO_SOURCE_DEFAULT;
+        ar->mPerformanceMode = ANDROID_PERFORMANCE_MODE_DEFAULT;
     } else {
         result = SL_RESULT_CONTENT_UNSUPPORTED;
     }
@@ -378,6 +445,15 @@
             result = audioRecorder_setPreset(ar, *(SLuint32*)pConfigValue);
         }
 
+    } else if (strcmp((const char*)configKey, (const char*)SL_ANDROID_KEY_PERFORMANCE_MODE) == 0) {
+
+        // performance mode
+        if (KEY_PERFORMANCE_MODE_PARAMSIZE > valueSize) {
+            SL_LOGE(ERROR_CONFIG_VALUESIZE_TOO_LOW);
+            result = SL_RESULT_BUFFER_INSUFFICIENT;
+        } else {
+            result = audioRecorder_setPerformanceMode(ar, *(SLuint32*)pConfigValue);
+        }
     } else {
         SL_LOGE(ERROR_CONFIG_UNKNOWN_KEY);
         result = SL_RESULT_PARAMETER_INVALID;
@@ -407,6 +483,19 @@
         }
         *pValueSize = KEY_RECORDING_PRESET_PARAMSIZE;
 
+    } else if (strcmp((const char*)configKey, (const char*)SL_ANDROID_KEY_PERFORMANCE_MODE) == 0) {
+
+        // performance mode
+        if (NULL == pConfigValue) {
+            result = SL_RESULT_SUCCESS;
+        } else if (KEY_PERFORMANCE_MODE_PARAMSIZE > *pValueSize) {
+            SL_LOGE(ERROR_CONFIG_VALUESIZE_TOO_LOW);
+            result = SL_RESULT_BUFFER_INSUFFICIENT;
+        } else {
+            result = audioRecorder_getPerformanceMode(ar, (SLuint32*)pConfigValue);
+        }
+        *pValueSize = KEY_PERFORMANCE_MODE_PARAMSIZE;
+
     } else {
         SL_LOGE(ERROR_CONFIG_UNKNOWN_KEY);
         result = SL_RESULT_PARAMETER_INVALID;
@@ -415,7 +504,131 @@
     return result;
 }
 
+// Called from android_audioRecorder_realize for a PCM buffer queue recorder before creating the
+// AudioRecord to determine which performance modes are allowed based on effect interfaces present
+static void checkAndSetPerformanceModePre(CAudioRecorder* ar)
+{
+    SLuint32 allowedModes = ANDROID_PERFORMANCE_MODE_ALL;
+    assert(ar->mAndroidObjType == AUDIORECORDER_FROM_MIC_TO_PCM_BUFFERQUEUE);
 
+    // no need to check the buffer queue size, application side
+    // double-buffering (and more) is not a requirement for using fast tracks
+
+    // Check a blacklist of interfaces that are incompatible with fast tracks.
+    // The alternative, to check a whitelist of compatible interfaces, is
+    // more maintainable but is too slow.  As a compromise, in a debug build
+    // we use both methods and warn if they produce different results.
+    // In release builds, we only use the blacklist method.
+    // If a blacklisted interface is added after realization using
+    // DynamicInterfaceManagement::AddInterface,
+    // then this won't be detected but the interface will be ineffective.
+    static const unsigned blacklist[] = {
+        MPH_ANDROIDACOUSTICECHOCANCELLATION,
+        MPH_ANDROIDAUTOMATICGAINCONTROL,
+        MPH_ANDROIDNOISESUPPRESSION,
+        MPH_ANDROIDEFFECT,
+        // FIXME The problem with a blacklist is remembering to add new interfaces here
+    };
+
+    for (unsigned i = 0; i < sizeof(blacklist)/sizeof(blacklist[0]); ++i) {
+        if (IsInterfaceInitialized(&ar->mObject, blacklist[i])) {
+            uint32_t flags = 0;
+
+            allowedModes &= ~ANDROID_PERFORMANCE_MODE_LATENCY;
+
+            // if generic effect interface is used we don't know which effect will be used and
+            // disable all low latency performance modes
+            if (blacklist[i] != MPH_ANDROIDEFFECT) {
+                switch (blacklist[i]) {
+                case MPH_ANDROIDACOUSTICECHOCANCELLATION:
+                    SL_LOGV("checkAndSetPerformanceModePre found AEC name %s",
+                            ar->mAcousticEchoCancellation.mAECDescriptor.name);
+                    flags = ar->mAcousticEchoCancellation.mAECDescriptor.flags;
+                    break;
+                case MPH_ANDROIDAUTOMATICGAINCONTROL:
+                    SL_LOGV("checkAndSetPerformanceModePre found AGC name %s",
+                            ar->mAutomaticGainControl.mAGCDescriptor.name);
+                    flags = ar->mAutomaticGainControl.mAGCDescriptor.flags;
+                    break;
+                case MPH_ANDROIDNOISESUPPRESSION:
+                    SL_LOGV("checkAndSetPerformanceModePre found NS name %s",
+                            ar->mNoiseSuppression.mNSDescriptor.name);
+                    flags = ar->mNoiseSuppression.mNSDescriptor.flags;
+                    break;
+                default:
+                    break;
+                }
+            }
+            if ((flags & EFFECT_FLAG_HW_ACC_TUNNEL) == 0) {
+                allowedModes &= ~ANDROID_PERFORMANCE_MODE_LATENCY_EFFECTS;
+                break;
+            }
+        }
+    }
+#if LOG_NDEBUG == 0
+    bool blacklistResult = (
+            (allowedModes &
+                (ANDROID_PERFORMANCE_MODE_LATENCY|ANDROID_PERFORMANCE_MODE_LATENCY_EFFECTS)) != 0);
+    bool whitelistResult = true;
+    static const unsigned whitelist[] = {
+        MPH_BUFFERQUEUE,
+        MPH_DYNAMICINTERFACEMANAGEMENT,
+        MPH_OBJECT,
+        MPH_RECORD,
+        MPH_ANDROIDCONFIGURATION,
+        MPH_ANDROIDSIMPLEBUFFERQUEUE,
+    };
+    for (unsigned mph = MPH_MIN; mph < MPH_MAX; ++mph) {
+        for (unsigned i = 0; i < sizeof(whitelist)/sizeof(whitelist[0]); ++i) {
+            if (mph == whitelist[i]) {
+                goto compatible;
+            }
+        }
+        if (IsInterfaceInitialized(&ar->mObject, mph)) {
+            whitelistResult = false;
+            break;
+        }
+compatible: ;
+    }
+    if (whitelistResult != blacklistResult) {
+        SL_LOGW("whitelistResult != blacklistResult");
+    }
+#endif
+    if (ar->mPerformanceMode == ANDROID_PERFORMANCE_MODE_LATENCY) {
+        if ((allowedModes & ANDROID_PERFORMANCE_MODE_LATENCY) == 0) {
+            ar->mPerformanceMode = ANDROID_PERFORMANCE_MODE_LATENCY_EFFECTS;
+        }
+    }
+    if (ar->mPerformanceMode == ANDROID_PERFORMANCE_MODE_LATENCY_EFFECTS) {
+        if ((allowedModes & ANDROID_PERFORMANCE_MODE_LATENCY_EFFECTS) == 0) {
+            ar->mPerformanceMode = ANDROID_PERFORMANCE_MODE_NONE;
+        }
+    }
+}
+
+// Called from android_audioRecorder_realize for a PCM buffer queue recorder after creating the
+// AudioRecord to adjust performance mode based on actual input flags
+static void checkAndSetPerformanceModePost(CAudioRecorder* ar)
+{
+    audio_input_flags_t flags = ar->mAudioRecord->getFlags();
+    switch (ar->mPerformanceMode) {
+    case ANDROID_PERFORMANCE_MODE_LATENCY:
+        if ((flags & (AUDIO_INPUT_FLAG_FAST | AUDIO_INPUT_FLAG_RAW)) ==
+                (AUDIO_INPUT_FLAG_FAST | AUDIO_INPUT_FLAG_RAW)) {
+            break;
+        }
+        ar->mPerformanceMode = ANDROID_PERFORMANCE_MODE_LATENCY_EFFECTS;
+        /* FALL THROUGH */
+    case ANDROID_PERFORMANCE_MODE_LATENCY_EFFECTS:
+        if ((flags & AUDIO_INPUT_FLAG_FAST) == 0) {
+            ar->mPerformanceMode = ANDROID_PERFORMANCE_MODE_NONE;
+        }
+        break;
+    case ANDROID_PERFORMANCE_MODE_NONE:
+    default:
+        break;
+    }
+}
 //-----------------------------------------------------------------------------
 SLresult android_audioRecorder_realize(CAudioRecorder* ar, SLboolean async) {
     SL_LOGV("android_audioRecorder_realize(%p) entering", ar);
@@ -433,8 +646,22 @@
 
     uint32_t sampleRate = sles_to_android_sampleRate(df_pcm->samplesPerSec);
 
-    // currently nothing analogous to canUseFastTrack() for recording
-    audio_input_flags_t policy = AUDIO_INPUT_FLAG_FAST;
+    checkAndSetPerformanceModePre(ar);
+
+    audio_input_flags_t policy;
+    switch (ar->mPerformanceMode) {
+    case ANDROID_PERFORMANCE_MODE_NONE:
+    case ANDROID_PERFORMANCE_MODE_POWER_SAVING:
+        policy = AUDIO_INPUT_FLAG_NONE;
+        break;
+    case ANDROID_PERFORMANCE_MODE_LATENCY_EFFECTS:
+        policy = AUDIO_INPUT_FLAG_FAST;
+        break;
+    case ANDROID_PERFORMANCE_MODE_LATENCY:
+    default:
+        policy = (audio_input_flags_t)(AUDIO_INPUT_FLAG_FAST | AUDIO_INPUT_FLAG_RAW);
+        break;
+    }
 
     SL_LOGV("Audio Record format: %dch(0x%x), %dbit, %dKHz",
             df_pcm->numChannels,
@@ -481,8 +708,12 @@
         // FIXME should return a more specific result depending on status
         result = SL_RESULT_CONTENT_UNSUPPORTED;
         ar->mAudioRecord.clear();
+        return result;
     }
 
+    // update performance mode according to actual flags granted to AudioRecord
+    checkAndSetPerformanceModePost(ar);
+
     // If there is a JavaAudioRoutingProxy associated with this recorder, hook it up...
     JNIEnv* j_env = NULL;
     jclass clsAudioRecord = NULL;
@@ -499,9 +730,47 @@
         if (j_env->ExceptionCheck()) {
             SL_LOGE("Java exception releasing recorder routing object.");
             result = SL_RESULT_INTERNAL_ERROR;
+            ar->mAudioRecord.clear();
+            return result;
         }
    }
 
+    if (ar->mPerformanceMode != ANDROID_PERFORMANCE_MODE_LATENCY) {
+        audio_session_t sessionId = ar->mAudioRecord->getSessionId();
+        // initialize AEC
+        effect_descriptor_t *descriptor = &ar->mAcousticEchoCancellation.mAECDescriptor;
+        if (memcmp(SL_IID_ANDROIDACOUSTICECHOCANCELLATION, &descriptor->type,
+                   sizeof(effect_uuid_t)) == 0) {
+            if ((ar->mPerformanceMode != ANDROID_PERFORMANCE_MODE_LATENCY_EFFECTS) ||
+                    (descriptor->flags & EFFECT_FLAG_HW_ACC_TUNNEL)) {
+                SL_LOGV("Need to initialize AEC for AudioRecorder=%p", ar);
+                android_aec_init(sessionId, &ar->mAcousticEchoCancellation);
+            }
+        }
+
+        // initialize AGC
+        descriptor = &ar->mAutomaticGainControl.mAGCDescriptor;
+        if (memcmp(SL_IID_ANDROIDAUTOMATICGAINCONTROL, &descriptor->type,
+                   sizeof(effect_uuid_t)) == 0) {
+            if ((ar->mPerformanceMode != ANDROID_PERFORMANCE_MODE_LATENCY_EFFECTS) ||
+                    (descriptor->flags & EFFECT_FLAG_HW_ACC_TUNNEL)) {
+                SL_LOGV("Need to initialize AGC for AudioRecorder=%p", ar);
+                android_agc_init(sessionId, &ar->mAutomaticGainControl);
+            }
+        }
+
+        // initialize NS
+        descriptor = &ar->mNoiseSuppression.mNSDescriptor;
+        if (memcmp(SL_IID_ANDROIDNOISESUPPRESSION, &descriptor->type,
+                   sizeof(effect_uuid_t)) == 0) {
+            if ((ar->mPerformanceMode != ANDROID_PERFORMANCE_MODE_LATENCY_EFFECTS) ||
+                    (descriptor->flags & EFFECT_FLAG_HW_ACC_TUNNEL)) {
+                SL_LOGV("Need to initialize NS for AudioRecorder=%p", ar);
+                android_ns_init(sessionId, &ar->mNoiseSuppression);
+            }
+        }
+    }
+
     return result;
 }
 
diff --git a/src/android/android_Effect.cpp b/src/android/android_Effect.cpp
index 3db425a..7143697 100644
--- a/src/android/android_Effect.cpp
+++ b/src/android/android_Effect.cpp
@@ -451,6 +451,38 @@
     }
 }
 
+//-----------------------------------------------------------------------------
+void android_aec_init(audio_session_t sessionId, IAndroidAcousticEchoCancellation* iaec) {
+    SL_LOGV("android_aec_init on session %d", sessionId);
+
+    if (!android_fx_initEffectObj(sessionId, iaec->mAECEffect,
+            &iaec->mAECDescriptor.type)) {
+        SL_LOGE("AEC effect initialization failed");
+        return;
+    }
+}
+
+//-----------------------------------------------------------------------------
+void android_agc_init(audio_session_t sessionId, IAndroidAutomaticGainControl* iagc) {
+    SL_LOGV("android_agc_init on session %d", sessionId);
+
+    if (!android_fx_initEffectObj(sessionId, iagc->mAGCEffect,
+            &iagc->mAGCDescriptor.type)) {
+        SL_LOGE("AGC effect initialization failed");
+        return;
+    }
+}
+
+//-----------------------------------------------------------------------------
+void android_ns_init(audio_session_t sessionId, IAndroidNoiseSuppression* ins) {
+    SL_LOGV("android_ns_init on session %d", sessionId);
+
+    if (!android_fx_initEffectObj(sessionId, ins->mNSEffect,
+            &ins->mNSDescriptor.type)) {
+        SL_LOGE("NS effect initialization failed");
+        return;
+    }
+}
 
 //-----------------------------------------------------------------------------
 /**
diff --git a/src/android/android_Effect.h b/src/android/android_Effect.h
index f78c9df..a6694c3 100644
--- a/src/android/android_Effect.h
+++ b/src/android/android_Effect.h
@@ -70,6 +70,21 @@
         int32_t param, void *pValue);
 
 /**************************************************************************************************
+ * AEC functions
+ ****************************/
+extern void android_aec_init(audio_session_t sessionId, IAndroidAcousticEchoCancellation* iaec);
+
+/**************************************************************************************************
+ * AGC functions
+ ****************************/
+extern void android_agc_init(audio_session_t sessionId, IAndroidAutomaticGainControl* iagc);
+
+/**************************************************************************************************
+ * NS functions
+ ****************************/
+extern void android_ns_init(audio_session_t sessionId, IAndroidNoiseSuppression* ins);
+
+/**************************************************************************************************
  * Generic Effect functions
  ****************************/
 extern SLresult android_genericFx_queryNumEffects(SLuint32 *pNumSupportedAudioEffects);
diff --git a/src/android/android_defs.h b/src/android/android_defs.h
index 9961cc5..daae607 100644
--- a/src/android/android_defs.h
+++ b/src/android/android_defs.h
@@ -207,4 +207,17 @@
     FdInfo fdi;
 };
 
+
+#define ANDROID_PERFORMANCE_MODE_NONE            ((SLuint32) 0x1 << 0)
+#define ANDROID_PERFORMANCE_MODE_LATENCY         ((SLuint32) 0x1 << 1)
+#define ANDROID_PERFORMANCE_MODE_LATENCY_EFFECTS ((SLuint32) 0x1 << 2)
+#define ANDROID_PERFORMANCE_MODE_POWER_SAVING    ((SLuint32) 0x1 << 3)
+
+#define ANDROID_PERFORMANCE_MODE_DEFAULT ANDROID_PERFORMANCE_MODE_LATENCY
+#define ANDROID_PERFORMANCE_MODE_ALL (ANDROID_PERFORMANCE_MODE_LATENCY | \
+                                      ANDROID_PERFORMANCE_MODE_LATENCY_EFFECTS | \
+                                      ANDROID_PERFORMANCE_MODE_NONE | \
+                                      ANDROID_PERFORMANCE_MODE_POWER_SAVING)
+
+
 } // namespace android
diff --git a/src/android/android_prompts.h b/src/android/android_prompts.h
index 9feeda1..dfb363d 100644
--- a/src/android/android_prompts.h
+++ b/src/android/android_prompts.h
@@ -69,3 +69,7 @@
         "Configuration error: value size too low to store valid value"
 #define ERROR_CONFIG_NULL_PARAM \
         "Configuration error: invalid NULL parameter"
+#define ERROR_CONFIG_PERF_MODE_UNKNOWN \
+        "Cannot set performance mode: unknown or invalid mode"
+#define ERROR_CONFIG_PERF_MODE_REALIZED \
+        "Cannot set performance mode in: player/recorder realized"
diff --git a/src/autogen/IID_to_MPH.cpp b/src/autogen/IID_to_MPH.cpp
index 3beee9b..538d0e7 100644
--- a/src/autogen/IID_to_MPH.cpp
+++ b/src/autogen/IID_to_MPH.cpp
@@ -29,205 +29,205 @@
 
 int IID_to_MPH(const SLInterfaceID iid)
 {
-#define MAX_HASH_VALUE 250
+#define MAX_HASH_VALUE 180
   static const unsigned char asso_values[] =
     {
-      251,  22, 251,  87, 251, 251,   0, 251,  37,  17,
-      251,  12,   4, 251, 251,  95, 251, 251, 251, 251,
-      102, 251,  17, 251, 251,  85, 251, 251, 251,   7,
-      251, 115, 251, 251, 251, 251, 251, 251,   7,   2,
-      251, 251,  15,   2,  87, 122,  15, 251, 251, 122,
-      251, 251, 251,  70, 251,  50, 251, 251,  32, 251,
-      251,   7, 251,  47,   2, 251,  52,  12,  47,   2,
-      251,  25, 251,  67, 251,  85,  32,  25, 251, 251,
-        2, 251, 251, 251,   2, 251,   2, 251, 251, 251,
-        2, 251, 251,   2, 251, 251, 251,  12, 105, 125,
-      251, 125, 251, 251,   2, 251,  12, 120, 251,  10,
-       75,   2,   2, 251, 251, 120, 115, 251, 251, 251,
-      110, 120,  10, 110, 251, 251, 251, 105,  15, 251,
-        5,  50, 251, 251, 251, 251, 251, 100, 251, 251,
-      120,   2, 251,  95, 251, 251, 251, 125,   2, 251,
-      251,  90, 251, 251,  90, 251,   0, 251,  90, 251,
-      251, 251, 251,  75, 100,   2, 251, 100,  80, 251,
-      110, 251, 251,  70,  80,  75, 115,  22,  50,  75,
-       90, 251, 251, 251,  65,  65, 251,  60,  65, 251,
-      251, 251,  60,   5,  55,  55, 105,   5,  50,  45,
-       65, 251, 251, 251,  55,  45,  45, 251,  45,  30,
-       40, 251,  65,  55, 251,  75, 251,  30,  75,  45,
-      251,  80,  25, 251, 251,  20, 251,  20,   2, 251,
-      251,  50, 251, 251, 251,  60, 110,  17,  20,  30,
-      251,  45,   0,  85,  20, 251, 120, 251, 251, 251,
-      251, 251, 251,  35,  40,  60
+       35,  20,  79,  99, 181, 181,  74, 181, 181, 181,
+      181, 181, 181, 181,  84, 181,  79,  59, 181, 181,
+      181, 181,  54, 181,  69,  39, 181, 181,  29, 181,
+      181,  85,   5, 181, 181, 181, 181, 181,  49, 181,
+       24, 181, 181, 181,  14, 181, 117, 181, 181, 181,
+      181, 181,   9, 181, 181, 181, 181, 181,  14, 100,
+      181,   9,  24, 181,  50, 181, 181, 181, 181, 127,
+      181, 181, 107,  85, 181, 181, 181, 181, 181, 181,
+      181, 181, 181, 181, 181, 181, 127, 181,  19, 181,
+      181, 181,   9, 181, 181, 181,  25, 122,  14, 107,
+      181, 181, 181, 181, 181, 181, 181,   4, 181, 102,
+      181, 181,   0, 181,   4,  97, 122, 181,  72,  45,
+      181, 181, 105, 181, 181, 181,  87, 181,  30, 181,
+      181, 181, 181, 181, 181, 107, 125, 181, 181, 181,
+      181, 181,  80,  82, 181,  77, 181, 120, 181, 181,
+      181, 181, 181,  97, 181, 181,  87, 181, 181,  65,
+        5, 181,  57, 181, 181,  82, 115, 181, 181,  52,
+      181,  72,  55, 181, 181,  62, 181,  45, 181, 181,
+      181, 181,  32, 181,  32,  30, 181, 181, 181, 181,
+      181, 181,   0, 181, 181, 181, 110,  47, 181, 181,
+      181, 181, 181, 181, 181, 181, 120, 181, 181, 181,
+      100,  47, 181, 181, 181,  37, 181, 181,   2, 181,
+      181, 181, 181,  27,  10, 181, 181,  27, 181, 181,
+      181, 181, 181, 181,  22, 181,  75, 181, 181, 181,
+       10,  12, 181, 181,  70, 181,   7,   7, 181, 181,
+      181, 105,   2, 125, 181, 181
     };
     static const signed char hash_to_MPH[] = {
-        MPH_BASSBOOST,
-        -1,
-        MPH_BUFFERQUEUE,
-        -1,
-        MPH_XAVIDEOENCODERCAPABILITIES,
-        MPH_XAIMAGEENCODERCAPABILITIES,
-        -1,
-        MPH_XAOBJECT,
-        -1,
-        MPH_VISUALIZATION,
-        MPH_DYNAMICSOURCE,
-        -1,
-        MPH_XAAUDIOIODEVICECAPABILITIES,
-        -1,
-        MPH_MIDITIME,
-        MPH_RECORD,
-        -1,
-        MPH_3DLOCATION,
-        -1,
-        MPH_VIBRA,
-        MPH_XAEQUALIZER,
-        -1,
-        MPH_ANDROIDEFFECTCAPABILITIES,
-        -1,
-        MPH_EQUALIZER,
-        MPH_XACONFIGEXTENSION,
-        -1,
-        MPH_RATEPITCH,
-        -1,
-        MPH_XAAUDIODECODERCAPABILITIES,
-        MPH_PLAYBACKRATE,
-        -1,
-        MPH_XALED,
-        -1,
-        MPH_VOLUME,
-        MPH_PREFETCHSTATUS,
-        -1,
-        MPH_XAMETADATAEXTRACTION,
-        -1,
-        MPH_XAVOLUME,
-        MPH_XAIMAGECONTROLS,
-        -1,
-        MPH_EFFECTSEND,
-        -1,
-        MPH_XACAMERACAPABILITIES,
-        MPH_DEVICEVOLUME,
-        -1,
-        MPH_XAVIDEOENCODER,
-        -1,
-        -1,
-        MPH_ANDROIDACOUSTICECHOCANCELLATION,
-        -1,
-        MPH_XAOUTPUTMIX,
-        -1,
-        -1,
-        MPH_XASNAPSHOT,
-        -1,
-        MPH_ENGINE,
-        -1,
-        -1,
-        MPH_PLAY,
-        -1,
-        MPH_MUTESOLO,
-        -1,
-        -1,
-        MPH_PITCH,
-        -1,
-        MPH_XADYNAMICSOURCE,
-        -1,
-        -1,
-        MPH_XACAMERA,
-        -1,
-        MPH_XAVIBRA,
-        -1,
-        -1,
-        MPH_AUDIOIODEVICECAPABILITIES,
+        MPH_ANDROIDEFFECTSEND,
         -1,
         MPH_XADYNAMICINTERFACEMANAGEMENT,
         -1,
+        MPH_XAAUDIODECODERCAPABILITIES,
+        MPH_XALED,
         -1,
-        MPH_XAVIDEODECODERCAPABILITIES,
+        MPH_BASSBOOST,
+        -1,
+        MPH_XAOUTPUTMIX,
+        MPH_MIDITIME,
+        -1,
+        MPH_RECORD,
+        -1,
+        MPH_AUDIOIODEVICECAPABILITIES,
+        MPH_MUTESOLO,
+        -1,
+        MPH_VOLUME,
+        -1,
+        MPH_ANDROIDCONFIGURATION,
+        MPH_XASNAPSHOT,
+        -1,
+        MPH_XAIMAGECONTROLS,
+        -1,
+        MPH_SEEK,
+        MPH_3DLOCATION,
+        -1,
+        MPH_XATHREADSYNC,
+        -1,
+        MPH_XAIMAGEDECODERCAPABILITIES,
+        MPH_XACAMERACAPABILITIES,
+        -1,
+        MPH_XAVOLUME,
+        -1,
+        MPH_VIBRA,
+        MPH_XAIMAGEEFFECTS,
+        -1,
+        MPH_XAPLAY,
+        -1,
+        MPH_PRESETREVERB,
+        MPH_XAOBJECT,
+        -1,
+        MPH_XACONFIGEXTENSION,
+        -1,
+        MPH_EQUALIZER,
+        MPH_XAVIBRA,
         -1,
         MPH_3DMACROSCOPIC,
         -1,
-        -1,
-        MPH_OUTPUTMIXEXT,
-        -1,
-        MPH_XADEVICEVOLUME,
-        -1,
-        -1,
-        MPH_XAIMAGEENCODER,
-        -1,
-        MPH_XAMETADATAINSERTION,
-        -1,
-        -1,
+        MPH_PITCH,
         MPH_ENGINECAPABILITIES,
         -1,
-        MPH_XAENGINE,
+        MPH_XAMETADATAEXTRACTION,
         -1,
+        MPH_3DDOPPLER,
+        MPH_XAVIDEODECODERCAPABILITIES,
         -1,
-        MPH_XAAUDIOENCODERCAPABILITIES,
+        MPH_RATEPITCH,
+        -1,
+        MPH_ANDROIDAUTOMATICGAINCONTROL,
+        MPH_AUDIODECODERCAPABILITIES,
+        -1,
+        MPH_XARADIO,
+        -1,
+        MPH_OUTPUTMIXEXT,
+        MPH_ENVIRONMENTALREVERB,
         -1,
         MPH_XAVIDEOPOSTPROCESSING,
         -1,
+        MPH_3DCOMMIT,
+        MPH_OUTPUTMIX,
         -1,
-        MPH_XAIMAGEDECODERCAPABILITIES,
+        MPH_METADATATRAVERSAL,
         -1,
-        MPH_3DGROUPING,
+        MPH_XASEEK,
+        MPH_XASTREAMINFORMATION,
         -1,
+        MPH_DEVICEVOLUME,
         -1,
-        MPH_ENVIRONMENTALREVERB,
-        -1,
-        MPH_3DSOURCE,
-        -1,
-        -1,
-        MPH_XAPREFETCHSTATUS,
+        MPH_OBJECT,
+        MPH_VIRTUALIZER,
         -1,
         MPH_XARDS,
         -1,
+        MPH_XAVIDEOENCODER,
+        MPH_PLAY,
         -1,
+        MPH_XADYNAMICSOURCE,
+        -1,
+        MPH_3DGROUPING,
+        MPH_XAVIDEOENCODERCAPABILITIES,
+        -1,
+        MPH_XAPREFETCHSTATUS,
+        -1,
+        MPH_XAMETADATATRAVERSAL,
+        MPH_XAEQUALIZER,
+        -1,
+        MPH_BUFFERQUEUE,
+        -1,
+        MPH_ANDROIDBUFFERQUEUESOURCE,
+        MPH_XARECORD,
+        -1,
+        MPH_XAMETADATAINSERTION,
+        -1,
+        MPH_XADEVICEVOLUME,
         MPH_ANDROIDNOISESUPPRESSION,
         -1,
-        MPH_AUDIODECODERCAPABILITIES,
+        MPH_ENGINE,
+        -1,
+        MPH_MIDIMUTESOLO,
+        MPH_METADATAEXTRACTION,
+        -1,
+        MPH_XACAMERA,
         -1,
         -1,
-        MPH_XAAUDIOENCODER,
-        -1,
-        MPH_XASTREAMINFORMATION,
-        -1,
-        -1,
-        MPH_XAIMAGEEFFECTS,
+        MPH_PREFETCHSTATUS,
         -1,
         MPH_LED,
         -1,
         -1,
-        MPH_SEEK,
+        MPH_XAAUDIOENCODER,
         -1,
-        MPH_VIRTUALIZER,
+        MPH_XAENGINE,
         -1,
         -1,
-        MPH_3DCOMMIT,
+        MPH_ANDROIDEFFECTCAPABILITIES,
         -1,
-        MPH_XASEEK,
+        MPH_MIDIMESSAGE,
         -1,
         -1,
-        MPH_XARADIO,
+        MPH_VISUALIZATION,
         -1,
-        MPH_PRESETREVERB,
+        MPH_3DSOURCE,
         -1,
         -1,
-        MPH_AUDIOENCODER,
+        MPH_PLAYBACKRATE,
         -1,
-        MPH_ANDROIDSIMPLEBUFFERQUEUE,
+        MPH_XAAUDIOENCODERCAPABILITIES,
         -1,
         -1,
+        MPH_EFFECTSEND,
+        -1,
+        MPH_XAAUDIOIODEVICECAPABILITIES,
+        -1,
+        -1,
+        MPH_NULL,
+        -1,
+        MPH_ANDROIDACOUSTICECHOCANCELLATION,
+        -1,
+        -1,
+        MPH_XAIMAGEENCODERCAPABILITIES,
+        -1,
         MPH_ANDROIDEFFECT,
         -1,
+        -1,
+        MPH_MIDITEMPO,
+        -1,
         MPH_XAPLAYBACKRATE,
         -1,
         -1,
-        MPH_MIDIMESSAGE,
+        MPH_DYNAMICINTERFACEMANAGEMENT,
         -1,
-        MPH_MIDIMUTESOLO,
+        MPH_DYNAMICSOURCE,
         -1,
         -1,
-        MPH_ANDROIDAUTOMATICGAINCONTROL,
+        MPH_ANDROIDSIMPLEBUFFERQUEUE,
         -1,
-        -1,
+        MPH_THREADSYNC,
         -1,
         -1,
         MPH_AUDIOENCODERCAPABILITIES,
@@ -235,88 +235,18 @@
         -1,
         -1,
         -1,
-        MPH_XATHREADSYNC,
+        MPH_XAIMAGEENCODER,
         -1,
         -1,
         -1,
         -1,
-        MPH_3DDOPPLER,
-        -1,
-        -1,
-        -1,
-        -1,
-        MPH_OUTPUTMIX,
-        -1,
-        -1,
-        -1,
-        -1,
-        MPH_XAPLAY,
-        -1,
-        -1,
-        -1,
-        -1,
-        MPH_XARECORD,
-        -1,
-        -1,
-        -1,
-        -1,
-        MPH_ANDROIDCONFIGURATION,
-        -1,
-        -1,
-        -1,
-        -1,
-        MPH_ANDROIDBUFFERQUEUESOURCE,
-        -1,
-        -1,
-        -1,
-        -1,
-        MPH_METADATATRAVERSAL,
-        -1,
-        -1,
-        -1,
-        -1,
-        MPH_ANDROIDEFFECTSEND,
-        -1,
-        -1,
-        -1,
-        -1,
-        MPH_NULL,
-        -1,
-        -1,
-        -1,
-        -1,
-        MPH_METADATAEXTRACTION,
-        -1,
-        -1,
-        -1,
-        -1,
-        MPH_MIDITEMPO,
-        -1,
-        -1,
-        -1,
-        -1,
-        MPH_XAMETADATATRAVERSAL,
-        -1,
-        -1,
-        -1,
-        -1,
-        MPH_THREADSYNC,
-        -1,
-        -1,
-        -1,
-        -1,
-        MPH_OBJECT,
-        -1,
-        -1,
-        -1,
-        -1,
-        MPH_DYNAMICINTERFACEMANAGEMENT
+        MPH_AUDIOENCODER
     };
     if (&SL_IID_array[0] <= iid && &SL_IID_array[MPH_MAX] > iid)
         return iid - &SL_IID_array[0];
     if (NULL != iid) {
-        unsigned key = asso_values[((unsigned char *)iid)[3]] +
-            asso_values[((unsigned char *)iid)[1]];
+        unsigned key = asso_values[((unsigned char *)iid)[8]] +
+            asso_values[((unsigned char *)iid)[0]];
         if (key <= MAX_HASH_VALUE) {
             int MPH = hash_to_MPH[key];
             if (MPH >= 0) {
diff --git a/src/autogen/MPH_to_AudioRecorder.h b/src/autogen/MPH_to_AudioRecorder.h
index 8759114..b5564eb 100644
--- a/src/autogen/MPH_to_AudioRecorder.h
+++ b/src/autogen/MPH_to_AudioRecorder.h
@@ -3,4 +3,4 @@
  -1, -1, -1, -1, -1, -1, -1, -1, -1,  0, -1, -1, -1, -1, -1, -1, -1,  2, -1, -1,
  -1, -1,  7,  8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 11, 12, 13
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
diff --git a/src/classes.cpp b/src/classes.cpp
index bc96f37..50997ea 100644
--- a/src/classes.cpp
+++ b/src/classes.cpp
@@ -127,11 +127,14 @@
     {MPH_ANDROIDSIMPLEBUFFERQUEUE, INTERFACE_EXPLICIT, offsetof(CAudioRecorder, mBufferQueue)},
     {MPH_ANDROIDCONFIGURATION, INTERFACE_EXPLICIT_PREREALIZE,
             offsetof(CAudioRecorder, mAndroidConfiguration)},
-    {MPH_ANDROIDACOUSTICECHOCANCELLATION, INTERFACE_OPTIONAL, offsetof(CAudioRecorder,
+    /* marked explicit for Android implementation, not an SL ES explicit interface */
+    {MPH_ANDROIDACOUSTICECHOCANCELLATION, INTERFACE_EXPLICIT, offsetof(CAudioRecorder,
                                                               mAcousticEchoCancellation)},
-    {MPH_ANDROIDAUTOMATICGAINCONTROL, INTERFACE_OPTIONAL, offsetof(CAudioRecorder,
+    /* marked explicit for Android implementation, not an SL ES explicit interface */
+    {MPH_ANDROIDAUTOMATICGAINCONTROL, INTERFACE_EXPLICIT, offsetof(CAudioRecorder,
                                                                    mAutomaticGainControl)},
-    {MPH_ANDROIDNOISESUPPRESSION, INTERFACE_OPTIONAL, offsetof(CAudioRecorder, mNoiseSuppression)},
+    /* marked explicit for Android implementation, not an SL ES explicit interface */
+    {MPH_ANDROIDNOISESUPPRESSION, INTERFACE_EXPLICIT, offsetof(CAudioRecorder, mNoiseSuppression)},
 #endif
 };
 
diff --git a/src/classes.h b/src/classes.h
index c9d0520..6de9047 100644
--- a/src/classes.h
+++ b/src/classes.h
@@ -113,6 +113,7 @@
     float mAmplFromDirectLevel;
     /** FIXME whether to call AudioTrack::start() at the next safe opportunity */
     bool mDeferredStart;
+    SLuint32 mPerformanceMode;
 #endif
 } /*CAudioPlayer*/;
 
@@ -156,6 +157,7 @@
     android::sp<android::AudioRecord> mAudioRecord;
     android::sp<android::CallbackProtector> mCallbackProtector;
     audio_source_t mRecordSource;
+    SLuint32 mPerformanceMode;
 #endif
 } /*CAudioRecorder*/;
 
diff --git a/src/itf/IAcousticEchoCancellation.cpp b/src/itf/IAcousticEchoCancellation.cpp
index 08822fe..e011864 100644
--- a/src/itf/IAcousticEchoCancellation.cpp
+++ b/src/itf/IAcousticEchoCancellation.cpp
@@ -17,8 +17,6 @@
 /* Acoustic Echo Cancellation implementation */
 #include "sles_allinclusive.h"
 
-#include <media/EffectsFactoryApi.h>
-
 #include <audio_effects/effect_aec.h>
 
 /**
@@ -71,43 +69,9 @@
     SL_LEAVE_INTERFACE
 }
 
-SLresult IAndroidAcousticEchoCancellation_IsAvailable(SLAndroidAcousticEchoCancellationItf self,
-                                                      SLboolean *pEnabled)
-{
-    SL_ENTER_INTERFACE
-
-    *pEnabled = false;
-
-    uint32_t numEffects = 0;
-    int ret = EffectQueryNumberEffects(&numEffects);
-    if (ret != 0) {
-        ALOGE("IAndroidAcousticEchoCancellation_IsAvailable() error %d querying number of effects",
-              ret);
-        result = SL_RESULT_FEATURE_UNSUPPORTED;
-   } else {
-        ALOGV("EffectQueryNumberEffects() numEffects=%d", numEffects);
-
-        effect_descriptor_t fxDesc;
-        for (uint32_t i = 0 ; i < numEffects ; i++) {
-            if (EffectQueryEffect(i, &fxDesc) == 0) {
-                ALOGV("effect %d is called %s", i, fxDesc.name);
-                if (memcmp(&fxDesc.type, SL_IID_ANDROIDACOUSTICECHOCANCELLATION,
-                           sizeof(effect_uuid_t)) == 0) {
-                    ALOGI("found effect \"%s\" from %s", fxDesc.name, fxDesc.implementor);
-                    *pEnabled = true;
-                    break;
-                }
-            }
-        }
-        result = SL_RESULT_SUCCESS;
-    }
-    SL_LEAVE_INTERFACE
-}
-
 static const struct SLAndroidAcousticEchoCancellationItf_ IAndroidAcousticEchoCancellation_Itf = {
     IAndroidAcousticEchoCancellation_SetEnabled,
-    IAndroidAcousticEchoCancellation_IsEnabled,
-    IAndroidAcousticEchoCancellation_IsAvailable
+    IAndroidAcousticEchoCancellation_IsEnabled
 };
 
 void IAndroidAcousticEchoCancellation_init(void *self)
diff --git a/src/itf/IAutomaticGainControl.cpp b/src/itf/IAutomaticGainControl.cpp
index f5b2fcb..bad599c 100644
--- a/src/itf/IAutomaticGainControl.cpp
+++ b/src/itf/IAutomaticGainControl.cpp
@@ -17,8 +17,6 @@
 /* Automatic Gain Control implementation */
 #include "sles_allinclusive.h"
 
-#include <media/EffectsFactoryApi.h>
-
 #include <audio_effects/effect_agc.h>
 
 /**
@@ -68,43 +66,9 @@
     SL_LEAVE_INTERFACE
 }
 
-SLresult IAndroidAutomaticGainControl_IsAvailable(SLAndroidAutomaticGainControlItf self,
-                                                  SLboolean *pEnabled)
-{
-    SL_ENTER_INTERFACE
-
-   *pEnabled = false;
-
-    uint32_t numEffects = 0;
-    int ret = EffectQueryNumberEffects(&numEffects);
-    if (ret != 0) {
-        ALOGE("IAndroidAutomaticGainControl_IsAvailable() error %d querying number of effects",
-              ret);
-        result = SL_RESULT_FEATURE_UNSUPPORTED;
-   } else {
-        ALOGV("EffectQueryNumberEffects() numEffects=%d", numEffects);
-
-        effect_descriptor_t fxDesc;
-        for (uint32_t i = 0 ; i < numEffects ; i++) {
-            if (EffectQueryEffect(i, &fxDesc) == 0) {
-                ALOGV("effect %d is called %s", i, fxDesc.name);
-                if (memcmp(&fxDesc.type, SL_IID_ANDROIDAUTOMATICGAINCONTROL,
-                           sizeof(effect_uuid_t)) == 0) {
-                    ALOGI("found effect \"%s\" from %s", fxDesc.name, fxDesc.implementor);
-                    *pEnabled = true;
-                    break;
-                }
-            }
-        }
-        result = SL_RESULT_SUCCESS;
-    }
-    SL_LEAVE_INTERFACE
-}
-
 static const struct SLAndroidAutomaticGainControlItf_ IAndroidAutomaticGainControl_Itf = {
     IAndroidAutomaticGainControl_SetEnabled,
-    IAndroidAutomaticGainControl_IsEnabled,
-    IAndroidAutomaticGainControl_IsAvailable
+    IAndroidAutomaticGainControl_IsEnabled
 };
 
 void IAndroidAutomaticGainControl_init(void *self)
diff --git a/src/itf/INoiseSuppression.cpp b/src/itf/INoiseSuppression.cpp
index dd5051a..88c6659 100644
--- a/src/itf/INoiseSuppression.cpp
+++ b/src/itf/INoiseSuppression.cpp
@@ -17,8 +17,6 @@
 /* Automatic Gain Control implementation */
 #include "sles_allinclusive.h"
 
-#include <media/EffectsFactoryApi.h>
-
 #include <audio_effects/effect_ns.h>
 /**
  * returns true if this interface is not associated with an initialized Noise Suppression effect
@@ -65,42 +63,9 @@
     SL_LEAVE_INTERFACE
 }
 
-SLresult IAndroidNoiseSuppression_IsAvailable(SLAndroidNoiseSuppressionItf self,
-                                              SLboolean *pEnabled)
-{
-    SL_ENTER_INTERFACE
-
-    *pEnabled = false;
-
-    uint32_t numEffects = 0;
-    int ret = EffectQueryNumberEffects(&numEffects);
-    if (ret != 0) {
-        ALOGE("IAndroidNoiseSuppression_IsAvailable() error %d querying number of effects", ret);
-        result = SL_RESULT_FEATURE_UNSUPPORTED;
-   } else {
-        ALOGV("EffectQueryNumberEffects() numEffects=%d", numEffects);
-
-        effect_descriptor_t fxDesc;
-        for (uint32_t i = 0 ; i < numEffects ; i++) {
-            if (EffectQueryEffect(i, &fxDesc) == 0) {
-                ALOGV("effect %d is called %s", i, fxDesc.name);
-                if (memcmp(&fxDesc.type, SL_IID_ANDROIDNOISESUPPRESSION,
-                           sizeof(effect_uuid_t)) == 0) {
-                    ALOGI("found effect \"%s\" from %s", fxDesc.name, fxDesc.implementor);
-                    *pEnabled = true;
-                    break;
-                }
-            }
-        }
-        result = SL_RESULT_SUCCESS;
-    }
-    SL_LEAVE_INTERFACE
-}
-
 static const struct SLAndroidNoiseSuppressionItf_ IAndroidNoiseSuppression_Itf = {
     IAndroidNoiseSuppression_SetEnabled,
-    IAndroidNoiseSuppression_IsEnabled,
-    IAndroidNoiseSuppression_IsAvailable
+    IAndroidNoiseSuppression_IsEnabled
 };
 
 void IAndroidNoiseSuppression_init(void *self)
diff --git a/src/ut/OpenSLESUT.c b/src/ut/OpenSLESUT.c
index f7f6353..f6e736a 100644
--- a/src/ut/OpenSLESUT.c
+++ b/src/ut/OpenSLESUT.c
@@ -17,8 +17,10 @@
 /** \file OpenSLESUT.c OpenSL ES Utility Toolkit */
 
 #include <SLES/OpenSLES.h>
+#include <OMXAL/OpenMAXAL.h>
 #ifdef ANDROID
 #include <SLES/OpenSLES_Android.h>
+#include <OMXAL/OpenMAXAL_Android.h>
 #endif
 #include "OpenSLESUT.h"
 #include <stdio.h>
@@ -36,7 +38,8 @@
 // ## is token concatenation e.g. a##b becomes ab
 // # is stringize operator to convert a symbol to a string constant e.g. #a becomes "a"
 
-#define _(x) { &SL_IID_##x, #x }
+#define _(x) { &SL_IID_##x, "SL_IID_" #x }
+#define _X(x) { (const SLInterfaceID *) &XA_IID_##x, "XA_IID_" #x }
 
 /** \brief Array of mappings from interface IDs to display names */
 
@@ -88,12 +91,15 @@
 #if 0 // ifdef USE_OUTPUTMIXEXT
     _(OUTPUTMIXEXT),
 #endif
+    _X(ENGINE),
+    _X(VIDEODECODERCAPABILITIES),
 #ifdef ANDROID
     _(ANDROIDEFFECT),
     _(ANDROIDEFFECTCAPABILITIES),
     _(ANDROIDEFFECTSEND),
     _(ANDROIDCONFIGURATION),
     _(ANDROIDSIMPLEBUFFERQUEUE),
+    _(ANDROIDBUFFERQUEUESOURCE),
     _(ANDROIDACOUSTICECHOCANCELLATION),
     _(ANDROIDAUTOMATICGAINCONTROL),
     _(ANDROIDNOISESUPPRESSION)
diff --git a/tests/examples/slesTestRecBuffQueue.cpp b/tests/examples/slesTestRecBuffQueue.cpp
index de46296..7ebf139 100644
--- a/tests/examples/slesTestRecBuffQueue.cpp
+++ b/tests/examples/slesTestRecBuffQueue.cpp
@@ -43,6 +43,10 @@
 int channelCount = 1;
 bool useIndexChannelMask = false;
 size_t frameSize;
+uint32_t performanceMode = SL_ANDROID_PERFORMANCE_LATENCY;
+bool aec = false;
+bool agc = false;
+bool ns = false;
 
 /* Preset number to use for recording */
 SLuint32 presetValue = SL_ANDROID_RECORDING_PRESET_NONE;
@@ -208,15 +212,20 @@
      */
     SLAndroidDataFormat_PCM_EX pcm;
 
-    SLboolean required[NUM_EXPLICIT_INTERFACES_FOR_RECORDER];
-    SLInterfaceID iidArray[NUM_EXPLICIT_INTERFACES_FOR_RECORDER];
+    int numInterfaces = NUM_EXPLICIT_INTERFACES_FOR_RECORDER;
+    if (aec) numInterfaces++;
+    if (agc) numInterfaces++;
+    if (ns) numInterfaces++;
+
+    SLboolean required[numInterfaces];
+    SLInterfaceID iidArray[numInterfaces];
 
     /* Get the SL Engine Interface which is implicit */
     result = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void*)&EngineItf);
     ExitOnError(result);
 
     /* Initialize arrays required[] and iidArray[] */
-    for (int i=0 ; i < NUM_EXPLICIT_INTERFACES_FOR_RECORDER ; i++) {
+    for (int i=0 ; i < numInterfaces ; i++) {
         required[i] = SL_BOOLEAN_FALSE;
         iidArray[i] = SL_IID_NULL;
     }
@@ -226,10 +235,20 @@
     /* Configuration of the recorder  */
 
     /* Request the AndroidSimpleBufferQueue and AndroidConfiguration interfaces */
-    required[0] = SL_BOOLEAN_TRUE;
-    iidArray[0] = SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
-    required[1] = SL_BOOLEAN_TRUE;
-    iidArray[1] = SL_IID_ANDROIDCONFIGURATION;
+    int index = 0;
+    required[index] = SL_BOOLEAN_TRUE;
+    iidArray[index++] = SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
+    required[index] = SL_BOOLEAN_TRUE;
+    iidArray[index++] = SL_IID_ANDROIDCONFIGURATION;
+    if (aec) {
+        iidArray[index++] = SL_IID_ANDROIDACOUSTICECHOCANCELLATION;
+    }
+    if (agc) {
+        iidArray[index++] = SL_IID_ANDROIDAUTOMATICGAINCONTROL;
+    }
+    if (ns) {
+        iidArray[index++] = SL_IID_ANDROIDNOISESUPPRESSION;
+    }
 
     /* Setup the data source */
     ioDevice.locatorType = SL_DATALOCATOR_IODEVICE;
@@ -294,7 +313,7 @@
 
     /* Create the audio recorder */
     result = (*EngineItf)->CreateAudioRecorder(EngineItf, &recorder, &recSource, &recDest,
-            NUM_EXPLICIT_INTERFACES_FOR_RECORDER, iidArray, required);
+                                               numInterfaces, iidArray, required);
     ExitOnError(result);
     printf("Recorder created\n");
 
@@ -312,6 +331,15 @@
         printf("Using default record preset\n");
     }
 
+    if (performanceMode != SL_ANDROID_PERFORMANCE_LATENCY) {
+        result = (*configItf)->SetConfiguration(configItf, SL_ANDROID_KEY_PERFORMANCE_MODE,
+                &performanceMode, sizeof(SLuint32));
+        ExitOnError(result);
+        printf("Recorder configured with performance mode %u\n", performanceMode);
+    } else {
+        printf("Using default performance mode\n");
+    }
+
     SLuint32 presetRetrieved = SL_ANDROID_RECORDING_PRESET_NONE;
     SLuint32 presetSize = 2*sizeof(SLuint32); // intentionally too big
     result = (*configItf)->GetConfiguration(configItf, SL_ANDROID_KEY_RECORDING_PRESET,
@@ -330,6 +358,14 @@
     ExitOnError(result);
     printf("Recorder realized\n");
 
+    /* Check actual performance mode granted*/
+    SLuint32 modeRetrieved = SL_ANDROID_PERFORMANCE_NONE;
+    SLuint32 modeSize = sizeof(SLuint32);
+    result = (*configItf)->GetConfiguration(configItf, SL_ANDROID_KEY_PERFORMANCE_MODE,
+            &modeSize, (void*)&modeRetrieved);
+    ExitOnError(result);
+    printf("Actual performance mode is %u\n", modeRetrieved);
+
     /* Get the record interface which is implicit */
     result = (*recorder)->GetInterface(recorder, SL_IID_RECORD, (void*)&recordItf);
     ExitOnError(result);
@@ -346,6 +382,54 @@
     ExitOnError(result);
     printf("Recorder callback registered\n");
 
+    /* Enable AEC if requested */
+    if (aec) {
+        SLAndroidAcousticEchoCancellationItf aecItf;
+        result = (*recorder)->GetInterface(
+                recorder, SL_IID_ANDROIDACOUSTICECHOCANCELLATION, (void*)&aecItf);
+        printf("AEC is %savailable\n", SL_RESULT_SUCCESS == result ? "" : "not ");
+        if (SL_RESULT_SUCCESS == result) {
+            result = (*aecItf)->SetEnabled(aecItf, true);
+            ExitOnError(result);
+            SLboolean enabled;
+            result = (*aecItf)->IsEnabled(aecItf, &enabled);
+            ExitOnError(result);
+            printf("AEC is %s\n", enabled ? "enabled" : "not enabled");
+        }
+    }
+
+    /* Enable AGC if requested */
+    if (agc) {
+        SLAndroidAutomaticGainControlItf agcItf;
+        result = (*recorder)->GetInterface(
+                recorder, SL_IID_ANDROIDAUTOMATICGAINCONTROL, (void*)&agcItf);
+        printf("AGC is %savailable\n", SL_RESULT_SUCCESS == result ? "" : "not ");
+        if (SL_RESULT_SUCCESS == result) {
+            result = (*agcItf)->SetEnabled(agcItf, true);
+            ExitOnError(result);
+            SLboolean enabled;
+            result = (*agcItf)->IsEnabled(agcItf, &enabled);
+            ExitOnError(result);
+            printf("AGC is %s\n", enabled ? "enabled" : "not enabled");
+        }
+    }
+
+    /* Enable NS if requested */
+    if (ns) {
+        SLAndroidNoiseSuppressionItf nsItf;
+        result = (*recorder)->GetInterface(
+                recorder, SL_IID_ANDROIDNOISESUPPRESSION, (void*)&nsItf);
+        printf("NS is %savailable\n", SL_RESULT_SUCCESS == result ? "" : "not ");
+        if (SL_RESULT_SUCCESS == result) {
+            result = (*nsItf)->SetEnabled(nsItf, true);
+            ExitOnError(result);
+            SLboolean enabled;
+            result = (*nsItf)->IsEnabled(nsItf, &enabled);
+            ExitOnError(result);
+            printf("NS is %s\n", enabled ? "enabled" : "not enabled");
+        }
+    }
+
     /* Get the buffer queue interface which was explicitly requested */
     result = (*recorder)->GetInterface(recorder, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
             (void*)&recBuffQueueItf);
@@ -443,6 +527,20 @@
         case '4':
             transferFormat = AUDIO_FORMAT_PCM_32_BIT;
             break;
+        case 'm':
+            performanceMode = atoi(&arg[2]);
+            break;
+        case 'x':
+            if (strstr(arg, "e") != NULL) {
+                aec = true;
+            }
+            if (strstr(arg, "a") != NULL) {
+                agc = true;
+            }
+            if (strstr(arg, "n") != NULL) {
+                ns = true;
+            }
+            break;
         default:
             fprintf(stderr, "%s: unknown option %s\n", prog, arg);
             break;
@@ -474,6 +572,21 @@
         printf("  -r# sample rate in Hz, defaults to 48000\n");
         printf("  -[1/2/4/f] sample format: 8-bit unsigned, 16-bit signed, 32-bit signed, float, "
                 "defaults to 16-bit signed\n");
+        printf("  -m# is the performance mode value which defaults to"
+                " SL_ANDROID_PERFORMANCE_LATENCY\n");
+        printf("  possible values are:\n");
+        printf("    -m%d SL_ANDROID_PERFORMANCE_NONE\n",
+               SL_ANDROID_PERFORMANCE_NONE);
+        printf("    -m%d SL_ANDROID_PERFORMANCE_LATENCY\n",
+               SL_ANDROID_PERFORMANCE_LATENCY);
+        printf("    -m%d SL_ANDROID_PERFORMANCE_LATENCY_EFFECTS\n",
+               SL_ANDROID_PERFORMANCE_LATENCY_EFFECTS);
+        printf("    -m%d SL_ANDROID_PERFORMANCE_POWER_SAVING\n",
+               SL_ANDROID_PERFORMANCE_POWER_SAVING);
+        printf("  -x[e][a][n] for pre processing:\n"
+                " - e: Echo canceler\n"
+                " - a: Automatic Gain Control\n"
+                " - n: Noise Suppression\n");
         printf("Example: \"%s /sdcard/myrec.wav\" \n", prog);
         exit(EXIT_FAILURE);
     }
diff --git a/tests/sandbox/Android.mk b/tests/sandbox/Android.mk
index 4297e91..bd87c0f 100644
--- a/tests/sandbox/Android.mk
+++ b/tests/sandbox/Android.mk
@@ -71,7 +71,8 @@
 
 LOCAL_SHARED_LIBRARIES := \
 	liblog \
-	libOpenSLES
+	libOpenSLES \
+	libOpenMAXAL
 
 LOCAL_STATIC_LIBRARIES := \
     libOpenSLESUT \
@@ -103,7 +104,8 @@
 
 LOCAL_SHARED_LIBRARIES := \
 	liblog \
-	libOpenSLES
+	libOpenSLES \
+	libOpenMAXAL
 
 LOCAL_STATIC_LIBRARIES := \
     libOpenSLESUT \
@@ -224,7 +226,8 @@
 
 LOCAL_SHARED_LIBRARIES := \
 	liblog \
-	libOpenSLES
+	libOpenSLES \
+	libOpenMAXAL
 
 LOCAL_STATIC_LIBRARIES := \
     libOpenSLESUT \
@@ -255,7 +258,8 @@
 
 LOCAL_SHARED_LIBRARIES := \
 	liblog \
-	libOpenSLES
+	libOpenSLES \
+	libOpenMAXAL
 
 LOCAL_STATIC_LIBRARIES := \
     libOpenSLESUT \
@@ -286,7 +290,8 @@
 
 LOCAL_SHARED_LIBRARIES := \
 	liblog \
-	libOpenSLES
+	libOpenSLES \
+	libOpenMAXAL
 
 LOCAL_STATIC_LIBRARIES := \
     libOpenSLESUT \
@@ -317,7 +322,8 @@
 
 LOCAL_SHARED_LIBRARIES := \
 	liblog \
-	libOpenSLES
+	libOpenSLES \
+	libOpenMAXAL
 
 LOCAL_STATIC_LIBRARIES := \
     libOpenSLESUT \
@@ -351,7 +357,8 @@
 	libaudioutils \
 	libnbaio \
 	liblog \
-	libOpenSLES
+	libOpenSLES \
+	libOpenMAXAL
 
 LOCAL_STATIC_LIBRARIES := \
     libOpenSLESUT \
@@ -383,7 +390,8 @@
 
 LOCAL_SHARED_LIBRARIES := \
 	liblog \
-	libOpenSLES
+	libOpenSLES \
+	libOpenMAXAL
 
 LOCAL_STATIC_LIBRARIES := \
     libOpenSLESUT \
@@ -493,6 +501,6 @@
 
 LOCAL_CFLAGS += -UNDEBUG -Wall -Wextra -Werror
 
-LOCAL_MODULE:= xaplay
+LOCAL_MODULE:= slesTest_xaplay
 
 include $(BUILD_EXECUTABLE)
diff --git a/tests/sandbox/engine.c b/tests/sandbox/engine.c
index 2d4acdf..9b17b35 100644
--- a/tests/sandbox/engine.c
+++ b/tests/sandbox/engine.c
@@ -140,7 +140,8 @@
         void *interface = NULL;
         result = (*engineObject)->GetInterface(engineObject, engine_ids[index], &interface);
         assert(SL_RESULT_SUCCESS == result);
-        printf("interface[%u] %p\n", index, interface);
+        printf("interface[%u] %p = ", index, interface);
+        slesutPrintIID(engine_ids[index]);
         // Use a copy of the interface ID to make sure lookup is not purely relying on address
         void *interface_again = NULL;
         struct SLInterfaceID_ copy = *engine_ids[index];
@@ -148,6 +149,8 @@
         assert(SL_RESULT_SUCCESS == result);
         // Calling GetInterface multiple times should return the same interface
         assert(interface_again == interface);
+        printf("copy = ");
+        slesutPrintIID(&copy);
     }
 
     SLObjectItf engineObject2;
diff --git a/tests/sandbox/object.c b/tests/sandbox/object.c
index 95caa38..993134f 100644
--- a/tests/sandbox/object.c
+++ b/tests/sandbox/object.c
@@ -158,7 +158,7 @@
 #ifdef ANDROID
     // whereas the implementation uses PLATFORM_SDK_VERSION, use a hard-coded value here
     // so that we're actually testing for a particular expected value
-    supportedExt = (SLchar *) "ANDROID_SDK_LEVEL_19";
+    supportedExt = (SLchar *) "ANDROID_SDK_LEVEL_25";
 #else
     supportedExt = (SLchar *) "WILHELM_DESKTOP";
 #endif
diff --git a/tests/sandbox/srcsink.c b/tests/sandbox/srcsink.c
index 35980f5..f78e651 100644
--- a/tests/sandbox/srcsink.c
+++ b/tests/sandbox/srcsink.c
@@ -114,7 +114,7 @@
     format_pcm.numChannels = 3;
     result = (*engineEngine)->CreateAudioPlayer(engineEngine, &playerObject, &audioSrc,
             &audioSnk, 1, ids, req);
-    assert(SL_RESULT_CONTENT_UNSUPPORTED == result);
+    assert(SL_RESULT_PARAMETER_INVALID == result);
     assert(NULL == playerObject);
     format_pcm.numChannels = 2;
 
@@ -140,7 +140,7 @@
     format_pcm.bitsPerSample = 24;
     result = (*engineEngine)->CreateAudioPlayer(engineEngine, &playerObject, &audioSrc,
             &audioSnk, 1, ids, req);
-    assert(SL_RESULT_CONTENT_UNSUPPORTED == result);
+    assert(SL_RESULT_PARAMETER_INVALID == result);
     assert(NULL == playerObject);
     format_pcm.bitsPerSample = 16;
 
diff --git a/tests/sandbox/xa.c b/tests/sandbox/xa.c
index 1549ac4..2d8f2a5 100644
--- a/tests/sandbox/xa.c
+++ b/tests/sandbox/xa.c
@@ -73,6 +73,7 @@
     XADataLocator_AndroidBufferQueue locABQ;
     memset(&locABQ, 0, sizeof(locABQ));
     locABQ.locatorType = XA_DATALOCATOR_ANDROIDBUFFERQUEUE;
+    locABQ.numBuffers = 1;
 #else
     XADataLocator_URI locUri;
     locUri.locatorType = XA_DATALOCATOR_URI;
@@ -97,7 +98,7 @@
     audioSnk.pFormat = NULL;
     XADataLocator_NativeDisplay locND;
     locND.locatorType = XA_DATALOCATOR_NATIVEDISPLAY;
-    locND.hWindow = NULL;
+    locND.hWindow = NULL; // FIXME wrong
     locND.hDisplay = NULL;
     XADataSink imageVideoSink;
     imageVideoSink.pLocator = &locND;
diff --git a/tools/hashgen/Makefile b/tools/hashgen/Makefile
index fdd143c..37188a3 100644
--- a/tools/hashgen/Makefile
+++ b/tools/hashgen/Makefile
@@ -1,9 +1,10 @@
-all : IID_to_MPH.c
+all : IID_to_MPH.c run_test
 
 install : IID_to_MPH.c
 	cp IID_to_MPH.c ../../src/autogen
 
 CFLAGS = -I../../include -g -DNDEBUG
+CFLAGS += -Wall -Werror
 
 %.o : %.c
 	gcc -c -o $@ $(CFLAGS) $<
@@ -43,7 +44,7 @@
 	./frag1 > part23in.gperf
 
 frag1 : frag1.o OpenSLES_IID.o
-	gcc -o $@ $(CFLAGS) frag1.o OpenSLES_IID.o
+	gcc -o $@ $(CFLAGS) $^
 
 part5gen.c : frag2.c part23in.c frag3.c
 	$(RM) $@
@@ -54,12 +55,19 @@
 	cat frag3.c >> $@
 
 part5gen : part5gen.o OpenSLES_IID.o interfaces.o
-	gcc -o $@ $(CFLAGS) part5gen.o OpenSLES_IID.o interfaces.o
+	gcc -o $@ $(CFLAGS) $^
+
+run_test : test
+	./test
+
+test : test.o OpenSLES_IID.o IID_to_MPH.o
+	gcc -o $@ $(CFLAGS) $^
 
 clean :
 	$(RM) part5gen frag1 *.o
 	$(RM) part23in.gperf part5gen.c part23in.c
 	$(RM) part2.c part3.c part5.c part7.c
+	$(RM) test
 
 distclean : clean
 	$(RM) IID_to_MPH.c
diff --git a/tools/hashgen/README.txt b/tools/hashgen/README.txt
index 3d801fb..4905bb9 100644
--- a/tools/hashgen/README.txt
+++ b/tools/hashgen/README.txt
@@ -5,18 +5,20 @@
  * GNU make
  * GNU gperf perfect hash generator
    $ gperf --version
-   GNU gperf 3.0.3
+   GNU gperf 3.0.4
  * GNU sed
    $ sed --version
-   GNU sed version 4.2.1
+   GNU sed version 4.2.2
 
 Usage:
 Type 'make'.
 Diff the old file in ../../src/autogen vs. the newly generated IID_to_MPH.c here.
 If the differences look OK, then copy the new IID_to_MPH.c back to
   its stable location in ../../src/autogen using 'make install'.
-Build and test the usage of the new IID.
+Build and test the usage of the new IID on host by "make run_test"
+*and* on the target by tests/sandbox/engine.c.  The host test
+checks all GUIDs, and the target test checks a subset of GUIDs.
 Then do 'make clean' or 'make distclean' here.
 
-hashgen is known to work on Linux with GNU gperf 3.0.3 and GNU sed
-version 4.2.1.  There are reports of problems on Mac OS X.
+hashgen is known to work on Linux with GNU gperf 3.0.4 and GNU sed
+version 4.2.2.  There are reports of problems on Mac OS X.
diff --git a/tools/hashgen/test.c b/tools/hashgen/test.c
new file mode 100644
index 0000000..4fe8ea2
--- /dev/null
+++ b/tools/hashgen/test.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+// Test the minimal perfect hash generator function
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <SLES/OpenSLES.h>
+#include "MPH.h"
+
+extern int IID_to_MPH(const SLInterfaceID iid);
+extern const struct SLInterfaceID_ SL_IID_array[MPH_MAX];
+
+int main(int argc, char **argv)
+{
+    int i;
+    for (i = 0; i < MPH_MAX; i++) {
+        const struct SLInterfaceID_ *original = &SL_IID_array[i];
+        // test the address-based lookup
+        int MPH = IID_to_MPH(original);
+        if (MPH != i) {
+            fprintf(stderr, "error: IID_to_MPH(SL_IID_array) = %d != %d\n", MPH, i);
+            return EXIT_FAILURE;
+        }
+        // test the content-based lookup
+        const struct SLInterfaceID_ copy = *original;
+        MPH = IID_to_MPH(&copy);
+        if (MPH != i) {
+            fprintf(stderr, "error: IID_to_MPH(copy) = %d != %d\n", MPH, i);
+            return EXIT_FAILURE;
+        }
+    }
+    printf("OK\n");
+    return EXIT_SUCCESS;
+}
diff --git a/tools/mphtogen/Makefile b/tools/mphtogen/Makefile
index c6a6fb2..788f412 100644
--- a/tools/mphtogen/Makefile
+++ b/tools/mphtogen/Makefile
@@ -10,7 +10,7 @@
 mphtogen : mphtogen.c MPH_to.c MPH.h MPH_to.h
 # Add -DANDROID if both (a) building for Android, and (b) not
 # using -DUSE_DESIGNATED_INITIALIZERS in ../../src/Android.mk
-	gcc -o $@ -DUSE_DESIGNATED_INITIALIZERS mphtogen.c MPH_to.c
+	gcc -o $@ -DUSE_DESIGNATED_INITIALIZERS -Wall -Werror mphtogen.c MPH_to.c
 
 clean :
 	$(RM) mphtogen
diff --git a/tools/permute/Makefile b/tools/permute/Makefile
index 65ed44d..8a07864 100644
--- a/tools/permute/Makefile
+++ b/tools/permute/Makefile
@@ -1,5 +1,5 @@
 permute : permute.c
-	gcc -o $@ -Wall permute.c -lsndfile
+	gcc -o $@ -Wall -Werror permute.c -lsndfile
 
 clean :
-	$(RM) $@
+	$(RM) permute
diff --git a/tools/permute/permute.c b/tools/permute/permute.c
index 4b6522e..6997552 100644
--- a/tools/permute/permute.c
+++ b/tools/permute/permute.c
@@ -141,6 +141,7 @@
         goto out;
     }
 
+#if 0
     // Must be 16-bit signed or 8-bit unsigned PCM
     unsigned subtype = sfinfo_in.format & SF_FORMAT_SUBMASK;
     unsigned sampleSizeIn = 0;
@@ -155,6 +156,7 @@
         fprintf(stderr, "%s: unsupported subtype 0x%X\n", path_in, subtype);
         goto out;
     }
+#endif
     // always read shorts
     unsigned sampleSizeRead = 2;
 
@@ -185,12 +187,10 @@
     }
 
     // Must be either stereo or mono
-    unsigned frameSizeIn = 0;
     unsigned frameSizeRead = 0;
     switch (sfinfo_in.channels) {
     case 1:
     case 2:
-        frameSizeIn = sampleSizeIn * sfinfo_in.channels;
         frameSizeRead = sampleSizeRead * sfinfo_in.channels;
         break;
     default: