Merge "MTP: work in progress on expanded property support"
diff --git a/include/media/EffectPresetReverbApi.h b/include/media/EffectPresetReverbApi.h
index 53205bb..a3f094c 100644
--- a/include/media/EffectPresetReverbApi.h
+++ b/include/media/EffectPresetReverbApi.h
@@ -43,7 +43,8 @@
     REVERB_PRESET_LARGEROOM,
     REVERB_PRESET_MEDIUMHALL,
     REVERB_PRESET_LARGEHALL,
-    REVERB_PRESET_PLATE
+    REVERB_PRESET_PLATE,
+    REVERB_PRESET_LAST = REVERB_PRESET_PLATE
 } t_reverb_presets;
 
 #if __cplusplus
diff --git a/include/media/stagefright/DataSource.h b/include/media/stagefright/DataSource.h
index 6f7dc38..9d2cff6 100644
--- a/include/media/stagefright/DataSource.h
+++ b/include/media/stagefright/DataSource.h
@@ -28,6 +28,7 @@
 
 namespace android {
 
+struct AMessage;
 class String8;
 
 class DataSource : public RefBase {
@@ -59,10 +60,14 @@
 
     ////////////////////////////////////////////////////////////////////////////
 
-    bool sniff(String8 *mimeType, float *confidence);
+    bool sniff(String8 *mimeType, float *confidence, sp<AMessage> *meta);
 
+    // The sniffer can optionally fill in "meta" with an AMessage containing
+    // a dictionary of values that helps the corresponding extractor initialize
+    // its state without duplicating effort already exerted by the sniffer.
     typedef bool (*SnifferFunc)(
-            const sp<DataSource> &source, String8 *mimeType, float *confidence);
+            const sp<DataSource> &source, String8 *mimeType,
+            float *confidence, sp<AMessage> *meta);
 
     static void RegisterSniffer(SnifferFunc func);
     static void RegisterDefaultSniffers();
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 798271e..d856eb4 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -17,7 +17,7 @@
 
 #define LOG_TAG "Bundle"
 #define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
 
 #include <cutils/log.h>
 #include <assert.h>
diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
index 2043e44..03f1409 100755
--- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
@@ -17,7 +17,7 @@
 
 #define LOG_TAG "Reverb"
 #define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
 
 #include <cutils/log.h>
 #include <assert.h>
@@ -61,42 +61,81 @@
 /* Preset definitions                                                               */
 /*                                                                                  */
 /************************************************************************************/
-LVM_UINT16 RevPreset_Level[]    = {  32,   32,   32,   32,   32,    32,   32,   32,   32,   32};
-LVM_UINT16 RevPreset_LPF[]      = {1298, 1000, 5012, 3542, 3400, 23999, 2536, 1000, 1000, 1000};
-LVM_UINT16 RevPreset_HPF[]      = {  50,   50,   50,   50,   50,    50,   50,   50,   50,   50};
-LVM_UINT16 RevPreset_T60[]      = {1490,  500, 2310, 4230, 3920,  2910, 7000, 1490, 1490,  170};
-LVM_UINT16 RevPreset_Density[]  = { 100,  100,  100,  100,  100,   100,  100,  100,  100,  100};
-LVM_UINT16 RevPreset_Damping[]  = {  54,   10,   64,   59,   70,   100,   33,   54,   21,   10};
-LVM_UINT16 RevPreset_RoomSize[] = { 100,  100,  100,  100,  100,   100,  100,  100,  100,  100};
 
-/************************************************************************************/
-/*                                                                                  */
-/* Preset definitions                                                               */
-/*                                                                                  */
-/************************************************************************************/
-#define REV_PRESET_BATHROOM         0
-#define REV_PRESET_LIVINGROOM       1
-#define REV_PRESET_STONEROOM        2
-#define REV_PRESET_AUDITORIUM       3
-#define REV_PRESET_CONCERTHALL      4
-#define REV_PRESET_CAVE             5
-#define REV_PRESET_ARENA            6
-#define REV_PRESET_FOREST           7
-#define REV_PRESET_MOUNTAINS        8
-#define REV_PRESET_PADDEDCELL       9
+const static t_reverb_settings sReverbPresets[] = {
+        // REVERB_PRESET_NONE: values are unused
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+        // REVERB_PRESET_SMALLROOM
+        {-1000, -600, 1100, 830, -400, 5, 500, 10, 1000, 1000},
+        // REVERB_PRESET_MEDIUMROOM
+        {-1000, -600, 1300, 830, -1000, 20, -200, 20, 1000, 1000},
+        // REVERB_PRESET_LARGEROOM
+        {-1000, -600, 1500, 830, -1600, 5, -1000, 40, 1000, 1000},
+        // REVERB_PRESET_MEDIUMHALL
+        {-1000, -600, 1800, 700, -1300, 15, -800, 30, 1000, 1000},
+        // REVERB_PRESET_LARGEHALL
+        {-1000, -600, 1800, 700, -2000, 30, -1400, 60, 1000, 1000},
+        // REVERB_PRESET_PLATE
+        {-1000, -200, 1300, 900, 0, 2, 0, 10, 1000, 750},
+};
 
-// NXP SW Reverb UUID
-const effect_descriptor_t gReverbDescriptor = {
+
+// NXP SW auxiliary environmental reverb
+const effect_descriptor_t gAuxEnvReverbDescriptor = {
         { 0xc2e5d5f0, 0x94bd, 0x4763, 0x9cac, { 0x4e, 0x23, 0x4d, 0x06, 0x83, 0x9e } },
         { 0x4a387fc0, 0x8ab3, 0x11df, 0x8bad, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } },
         EFFECT_API_VERSION,
-        (EFFECT_FLAG_TYPE_AUXILIARY | EFFECT_FLAG_INSERT_LAST),
+        EFFECT_FLAG_TYPE_AUXILIARY,
         0, // TODO
         1,
-        "Reverb",
+        "Auxiliary Environmental Reverb",
         "NXP Software Ltd.",
 };
 
+// NXP SW insert environmental reverb
+static const effect_descriptor_t gInsertEnvReverbDescriptor = {
+        {0xc2e5d5f0, 0x94bd, 0x4763, 0x9cac, {0x4e, 0x23, 0x4d, 0x06, 0x83, 0x9e}},
+        {0xc7a511a0, 0xa3bb, 0x11df, 0x860e, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+        EFFECT_API_VERSION,
+        EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST,
+        0, // TODO
+        1,
+        "Insert Environmental Reverb",
+        "NXP Software Ltd.",
+};
+
+// NXP SW auxiliary preset reverb
+static const effect_descriptor_t gAuxPresetReverbDescriptor = {
+        {0x47382d60, 0xddd8, 0x11db, 0xbf3a, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+        {0xf29a1400, 0xa3bb, 0x11df, 0x8ddc, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+        EFFECT_API_VERSION,
+        EFFECT_FLAG_TYPE_AUXILIARY,
+        0, // TODO
+        1,
+        "Auxiliary Preset Reverb",
+        "NXP Software Ltd.",
+};
+
+// NXP SW insert preset reverb
+static const effect_descriptor_t gInsertPresetReverbDescriptor = {
+        {0x47382d60, 0xddd8, 0x11db, 0xbf3a, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+        {0x172cdf00, 0xa3bc, 0x11df, 0xa72f, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+        EFFECT_API_VERSION,
+        EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST,
+        0, // TODO
+        1,
+        "Insert Preset Reverb",
+        "NXP Software Ltd.",
+};
+
+// gDescriptors contains pointers to all defined effect descriptor in this library
+static const effect_descriptor_t * const gDescriptors[] = {
+        &gAuxEnvReverbDescriptor,
+        &gInsertEnvReverbDescriptor,
+        &gAuxPresetReverbDescriptor,
+        &gInsertPresetReverbDescriptor
+};
+
 struct ReverbContext{
     const struct effect_interface_s *itfe;
     effect_config_t                 config;
@@ -114,8 +153,14 @@
     FILE                            *PcmOutPtr;
     #endif
     LVM_Fs_en                       SampleRate;
+    bool                            auxiliary;
+    bool                            preset;
+    uint16_t                        curPreset;
+    uint16_t                        nextPreset;
 };
 
+#define REVERB_DEFAULT_PRESET REVERB_PRESET_MEDIUMROOM
+
 //--- local function prototypes
 int  Reverb_init            (ReverbContext *pContext);
 void Reverb_free            (ReverbContext *pContext);
@@ -125,11 +170,12 @@
                              void          *pParam,
                              size_t        *pValueSize,
                              void          *pValue);
+int Reverb_LoadPreset       (ReverbContext   *pContext);
 
 /* Effect Library Interface Implementation */
 extern "C" int EffectQueryNumberEffects(uint32_t *pNumEffects){
     LOGV("\n\tEffectQueryNumberEffects start");
-    *pNumEffects = 1;
+    *pNumEffects = sizeof(gDescriptors) / sizeof(const effect_descriptor_t *);
     LOGV("\tEffectQueryNumberEffects creating %d effects", *pNumEffects);
     LOGV("\tEffectQueryNumberEffects end\n");
     return 0;
@@ -142,11 +188,11 @@
         LOGV("\tLVM_ERROR : EffectQueryEffect was passed NULL pointer");
         return -EINVAL;
     }
-    if (index > 0){
+    if (index >= sizeof(gDescriptors) / sizeof(const effect_descriptor_t *)) {
         LOGV("\tLVM_ERROR : EffectQueryEffect index out of range %d", index);
         return -ENOENT;
     }
-    memcpy(pDescriptor, &gReverbDescriptor, sizeof(effect_descriptor_t));
+    memcpy(pDescriptor, gDescriptors[index], sizeof(effect_descriptor_t));
     LOGV("\tEffectQueryEffect end\n");
     return 0;
 }     /* end EffectQueryEffect */
@@ -157,6 +203,8 @@
                             effect_interface_t  *pInterface){
     int ret;
     int i;
+    int length = sizeof(gDescriptors) / sizeof(const effect_descriptor_t *);
+    const effect_descriptor_t *desc;
 
     LOGV("\t\nEffectCreate start");
 
@@ -165,9 +213,16 @@
         return -EINVAL;
     }
 
-    if (memcmp(uuid, &gReverbDescriptor.uuid, sizeof(effect_uuid_t)) != 0){
-        LOGV("\tLVM_ERROR : EffectCreate() invalid UUID");
-        return -EINVAL;
+    for (i = 0; i < length; i++) {
+        desc = gDescriptors[i];
+        if (memcmp(uuid, &desc->uuid, sizeof(effect_uuid_t))
+                == 0) {
+            break;
+        }
+    }
+
+    if (i == length) {
+        return -ENOENT;
     }
 
     ReverbContext *pContext = new ReverbContext;
@@ -175,6 +230,19 @@
     pContext->itfe      = &gReverbInterface;
     pContext->hInstance = NULL;
 
+    pContext->auxiliary = false;
+    if ((desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY){
+        pContext->auxiliary = true;
+    }
+
+    pContext->preset = false;
+    if (memcmp(&desc->type, SL_IID_PRESETREVERB, sizeof(effect_uuid_t)) == 0) {
+        pContext->preset = true;
+        // force reloading preset at first call to process()
+        pContext->curPreset = REVERB_PRESET_LAST + 1;
+        pContext->nextPreset = REVERB_DEFAULT_PRESET;
+    }
+
     LOGV("\tEffectCreate - Calling Reverb_init");
     ret = Reverb_init(pContext);
 
@@ -288,6 +356,14 @@
 
    return;
 }
+
+static inline int16_t clamp16(int32_t sample)
+{
+    if ((sample>>15) ^ (sample>>31))
+        sample = 0x7FFF ^ (sample>>31);
+    return sample;
+}
+
 //----------------------------------------------------------------------------
 // process()
 //----------------------------------------------------------------------------
@@ -344,6 +420,9 @@
     fflush(pContext->PcmInPtr);
     #endif
 
+    if (pContext->preset && pContext->nextPreset != pContext->curPreset) {
+        Reverb_LoadPreset(pContext);
+    }
     // Convert to Input 32 bits
     for(int i=0; i<frameCount*samplesPerFrame; i++){
         InFrames32[i] = (LVM_INT32)pIn[i]<<8;
@@ -359,18 +438,28 @@
     //frameCount, pContext->config.inputCfg.channels, CHANNEL_MONO,
     //pContext->config.outputCfg.channels, CHANNEL_STEREO);
 
+    if (pContext->preset && pContext->curPreset == REVERB_PRESET_NONE) {
+        memset(OutFrames32, 0, frameCount * sizeof(LVM_INT32) * 2);
+    } else {
     /* Process the samples */
     LvmStatus = LVREV_Process(pContext->hInstance,      /* Instance handle */
                               InFrames32,               /* Input buffer */
                               OutFrames32,              /* Output buffer */
                               frameCount);              /* Number of samples to read */
+    }
+
+    if (!pContext->auxiliary) {
+        for (int i=0; i<frameCount*2; i++){
+            OutFrames32[i] += InFrames32[i];
+        }
+    }
 
     LVM_ERROR_CHECK(LvmStatus, "LVREV_Process", "process")
     if(LvmStatus != LVREV_SUCCESS) return -EINVAL;
 
     // Convert to 16 bits
     for(int i=0; i<frameCount*2; i++){  // Always stereo
-        OutFrames16[i] = (LVM_INT16)(OutFrames32[i]>>8);
+        OutFrames16[i] = clamp16(OutFrames32[i]>>8);
     }
 
     #ifdef LVM_PCM
@@ -382,7 +471,7 @@
     if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE){
         //LOGV("\tBuffer access is ACCUMULATE");
         for (int i=0; i<frameCount*2; i++){
-            pOut[i] +=  OutFrames16[i];
+            pOut[i] = clamp16((int32_t)pOut[i] + (int32_t)OutFrames16[i]);
         }
     }else{
         //LOGV("\tBuffer access is WRITE");
@@ -462,6 +551,8 @@
 
     CHECK_ARG(pConfig->inputCfg.samplingRate == pConfig->outputCfg.samplingRate);
     CHECK_ARG(pConfig->inputCfg.format == pConfig->outputCfg.format);
+    CHECK_ARG((pContext->auxiliary && pConfig->inputCfg.channels == CHANNEL_MONO) ||
+              ((!pContext->auxiliary) && pConfig->inputCfg.channels == CHANNEL_STEREO));
     CHECK_ARG(pConfig->outputCfg.channels == CHANNEL_STEREO);
     CHECK_ARG(pConfig->outputCfg.accessMode == EFFECT_BUFFER_ACCESS_WRITE
               || pConfig->outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE);
@@ -540,18 +631,8 @@
 
 int Reverb_init(ReverbContext *pContext){
     int status;
-    int channel_mode;
 
-    LOGV("\tReverb_init start %d", gReverbDescriptor.flags);
-
-    if((gReverbDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_INSERT){
-        LOGV("\tReverb_init EFFECT_FLAG_TYPE_INSERT");
-        channel_mode = CHANNEL_STEREO;
-    }
-    if((gReverbDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY ){
-        LOGV("\tReverb_init EFFECT_FLAG_TYPE_AUXILIARY");
-        channel_mode = CHANNEL_MONO;
-    }
+    LOGV("\tReverb_init start");
 
     CHECK_ARG(pContext != NULL);
 
@@ -560,7 +641,12 @@
     }
 
     pContext->config.inputCfg.accessMode                    = EFFECT_BUFFER_ACCESS_READ;
-    pContext->config.inputCfg.channels                      = channel_mode;
+    if (pContext->auxiliary) {
+        pContext->config.inputCfg.channels                  = CHANNEL_MONO;
+    } else {
+        pContext->config.inputCfg.channels                  = CHANNEL_STEREO;
+    }
+
     pContext->config.inputCfg.format                        = SAMPLE_FORMAT_PCM_S15;
     pContext->config.inputCfg.samplingRate                  = 44100;
     pContext->config.inputCfg.bufferProvider.getBuffer      = NULL;
@@ -653,11 +739,11 @@
     /* Reverb parameters */
     params.Level          = 0;
     params.LPF            = 23999;
-    params.HPF            = RevPreset_HPF[REV_PRESET_MOUNTAINS];
-    params.T60            = RevPreset_T60[REV_PRESET_MOUNTAINS];
-    params.Density        = RevPreset_Density[REV_PRESET_MOUNTAINS];
-    params.Damping        = RevPreset_Damping[REV_PRESET_MOUNTAINS];
-    params.RoomSize       = RevPreset_RoomSize[REV_PRESET_MOUNTAINS];
+    params.HPF            = 50;
+    params.T60            = 1490;
+    params.Density        = 100;
+    params.Damping        = 21;
+    params.RoomSize       = 100;
 
     /* Saved strength is used to return the exact strength that was used in the set to the get
      * because we map the original strength range of 0:1000 to 1:15, and this will avoid
@@ -1294,6 +1380,44 @@
 }
 
 //----------------------------------------------------------------------------
+// Reverb_LoadPreset()
+//----------------------------------------------------------------------------
+// Purpose:
+// Load a the next preset
+//
+// Inputs:
+//  pContext         - handle to instance data
+//
+// Outputs:
+//
+// Side Effects:
+//
+//----------------------------------------------------------------------------
+int Reverb_LoadPreset(ReverbContext   *pContext)
+{
+    //TODO: add reflections delay, level and reverb delay when early reflections are
+    // implemented
+    pContext->curPreset = pContext->nextPreset;
+
+    if (pContext->curPreset != REVERB_PRESET_NONE) {
+        const t_reverb_settings *preset = &sReverbPresets[pContext->curPreset];
+        ReverbSetRoomLevel(pContext, preset->roomLevel);
+        ReverbSetRoomHfLevel(pContext, preset->roomHFLevel);
+        ReverbSetDecayTime(pContext, preset->decayTime);
+        ReverbSetDecayHfRatio(pContext, preset->decayHFRatio);
+        //reflectionsLevel
+        //reflectionsDelay
+        ReverbSetReverbLevel(pContext, preset->reverbLevel);
+        // reverbDelay
+        ReverbSetDiffusion(pContext, preset->diffusion);
+        ReverbSetDensity(pContext, preset->density);
+    }
+
+    return 0;
+}
+
+
+//----------------------------------------------------------------------------
 // Reverb_getParameter()
 //----------------------------------------------------------------------------
 // Purpose:
@@ -1325,6 +1449,15 @@
     t_reverb_settings *pProperties;
 
     //LOGV("\tReverb_getParameter start");
+    if (pContext->preset) {
+        if (param != REVERB_PARAM_PRESET || *pValueSize < sizeof(uint16_t)) {
+            return -EINVAL;
+        }
+
+        *(uint16_t *)pValue = pContext->nextPreset;
+        LOGV("get REVERB_PARAM_PRESET, preset %d", pContext->nextPreset);
+        return 0;
+    }
 
     switch (param){
         case REVERB_PARAM_ROOM_LEVEL:
@@ -1531,6 +1664,18 @@
     int32_t param = *pParamTemp++;
 
     //LOGV("\tReverb_setParameter start");
+    if (pContext->preset) {
+        if (param != REVERB_PARAM_PRESET) {
+            return -EINVAL;
+        }
+
+        uint16_t preset = *(uint16_t *)pValue;
+        LOGV("set REVERB_PARAM_PRESET, preset %d", preset);
+        if (preset > REVERB_PRESET_LAST) {
+            return -EINVAL;
+        }
+        pContext->nextPreset = preset;
+    }
 
     switch (param){
         case REVERB_PARAM_PROPERTIES:
diff --git a/media/libmedia/fixedfft.cpp b/media/libmedia/fixedfft.cpp
index 28eb05a..9cf05ba 100644
--- a/media/libmedia/fixedfft.cpp
+++ b/media/libmedia/fixedfft.cpp
@@ -26,7 +26,9 @@
 
 #include <stdio.h>
 #include <stdint.h>
+#ifdef __ARM_ARCH__
 #include <machine/cpu-features.h>
+#endif
 
 #define LOG_FFT_SIZE 10
 #define MAX_FFT_SIZE (1 << LOG_FFT_SIZE)
diff --git a/media/libstagefright/AMRExtractor.cpp b/media/libstagefright/AMRExtractor.cpp
index 70af2da..1b05528 100644
--- a/media/libstagefright/AMRExtractor.cpp
+++ b/media/libstagefright/AMRExtractor.cpp
@@ -87,7 +87,7 @@
       mInitCheck(NO_INIT) {
     String8 mimeType;
     float confidence;
-    if (!SniffAMR(mDataSource, &mimeType, &confidence)) {
+    if (!SniffAMR(mDataSource, &mimeType, &confidence, NULL)) {
         return;
     }
 
@@ -276,7 +276,8 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 bool SniffAMR(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence) {
+        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        sp<AMessage> *) {
     char header[9];
 
     if (source->readAt(0, header, sizeof(header)) != sizeof(header)) {
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index e167afa..1ccfa03 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -461,27 +461,34 @@
         return;
     }
 
+    bool eos;
+    size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&eos);
+
     size_t lowWatermark = 400000;
     size_t highWatermark = 1000000;
 
-    off_t size;
-    if (mDurationUs >= 0 && mCachedSource->getSize(&size) == OK) {
-        int64_t bitrate = size * 8000000ll / mDurationUs;  // in bits/sec
+    if (eos) {
+        notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
+    } else {
+        off_t size;
+        if (mDurationUs >= 0 && mCachedSource->getSize(&size) == OK) {
+            int64_t bitrate = size * 8000000ll / mDurationUs;  // in bits/sec
 
-        size_t cachedSize = mCachedSource->cachedSize();
-        int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate;
+            size_t cachedSize = mCachedSource->cachedSize();
+            int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate;
 
-        double percentage = (double)cachedDurationUs / mDurationUs;
+            int percentage = 100.0 * (double)cachedDurationUs / mDurationUs;
+            if (percentage > 100) {
+                percentage = 100;
+            }
 
-        notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage * 100.0);
+            notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
 
-        lowWatermark = 2 * bitrate / 8;  // 2 secs
-        highWatermark = 10 * bitrate / 8;  // 10 secs
+            lowWatermark = 2 * bitrate / 8;  // 2 secs
+            highWatermark = 10 * bitrate / 8;  // 10 secs
+        }
     }
 
-    bool eos;
-    size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&eos);
-
     if ((mFlags & PLAYING) && !eos && (cachedDataRemaining < lowWatermark)) {
         LOGI("cache is running low (< %d) , pausing.", lowWatermark);
         mFlags |= CACHE_UNDERRUN;
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index 90a596c..49eac62 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -25,6 +25,7 @@
 
 #include "matroska/MatroskaExtractor.h"
 
+#include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/FileSource.h>
 #include <media/stagefright/MediaErrors.h>
@@ -56,19 +57,23 @@
 Mutex DataSource::gSnifferMutex;
 List<DataSource::SnifferFunc> DataSource::gSniffers;
 
-bool DataSource::sniff(String8 *mimeType, float *confidence) {
+bool DataSource::sniff(
+        String8 *mimeType, float *confidence, sp<AMessage> *meta) {
     *mimeType = "";
     *confidence = 0.0f;
+    meta->clear();
 
     Mutex::Autolock autoLock(gSnifferMutex);
     for (List<SnifferFunc>::iterator it = gSniffers.begin();
          it != gSniffers.end(); ++it) {
         String8 newMimeType;
         float newConfidence;
-        if ((*it)(this, &newMimeType, &newConfidence)) {
+        sp<AMessage> newMeta;
+        if ((*it)(this, &newMimeType, &newConfidence, &newMeta)) {
             if (newConfidence > *confidence) {
                 *mimeType = newMimeType;
                 *confidence = newConfidence;
+                *meta = newMeta;
             }
         }
     }
@@ -92,13 +97,13 @@
 
 // static
 void DataSource::RegisterDefaultSniffers() {
-    RegisterSniffer(SniffMP3);
     RegisterSniffer(SniffMPEG4);
-    RegisterSniffer(SniffAMR);
-    RegisterSniffer(SniffWAV);
-    RegisterSniffer(SniffOgg);
     RegisterSniffer(SniffMatroska);
+    RegisterSniffer(SniffOgg);
+    RegisterSniffer(SniffWAV);
+    RegisterSniffer(SniffAMR);
     RegisterSniffer(SniffMPEG2TS);
+    RegisterSniffer(SniffMP3);
 }
 
 // static
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
index 4058fbc..2e36968 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -22,6 +22,7 @@
 
 #include "include/ID3.h"
 
+#include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
@@ -456,15 +457,31 @@
     MP3Source &operator=(const MP3Source &);
 };
 
-MP3Extractor::MP3Extractor(const sp<DataSource> &source)
+MP3Extractor::MP3Extractor(
+        const sp<DataSource> &source, const sp<AMessage> &meta)
     : mDataSource(source),
       mFirstFramePos(-1),
       mFixedHeader(0),
       mByteNumber(0) {
     off_t pos = 0;
     uint32_t header;
-    bool success = Resync(mDataSource, 0, &pos, &header);
-    CHECK(success);
+    bool success;
+
+    int64_t meta_offset;
+    uint32_t meta_header;
+    if (meta != NULL
+            && meta->findInt64("offset", &meta_offset)
+            && meta->findInt32("header", (int32_t *)&meta_header)) {
+        // The sniffer has already done all the hard work for us, simply
+        // accept its judgement.
+        pos = (off_t)meta_offset;
+        header = meta_header;
+
+        success = true;
+    } else {
+        success = Resync(mDataSource, 0, &pos, &header);
+        CHECK(success);
+    }
 
     if (success) {
         mFirstFramePos = pos;
@@ -759,15 +776,20 @@
 }
 
 bool SniffMP3(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence) {
+        const sp<DataSource> &source, String8 *mimeType,
+        float *confidence, sp<AMessage> *meta) {
     off_t pos = 0;
     uint32_t header;
     if (!Resync(source, 0, &pos, &header)) {
         return false;
     }
 
+    *meta = new AMessage;
+    (*meta)->setInt64("offset", pos);
+    (*meta)->setInt32("header", header);
+
     *mimeType = MEDIA_MIMETYPE_AUDIO_MPEG;
-    *confidence = 0.3f;
+    *confidence = 0.2f;
 
     return true;
 }
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 12a1e6e..ba90407 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -1738,7 +1738,7 @@
         || !memcmp(header, "ftypM4A ", 8) || !memcmp(header, "ftypf4v ", 8)
         || !memcmp(header, "ftypkddi", 8) || !memcmp(header, "ftypM4VP", 8)) {
         *mimeType = MEDIA_MIMETYPE_CONTAINER_MPEG4;
-        *confidence = 0.1;
+        *confidence = 0.4;
 
         return true;
     }
@@ -1805,13 +1805,14 @@
     }
 
     *mimeType = MEDIA_MIMETYPE_CONTAINER_MPEG4;
-    *confidence = 0.3f;
+    *confidence = 0.4f;
 
     return true;
 }
 
 bool SniffMPEG4(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence) {
+        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        sp<AMessage> *) {
     if (BetterSniffMPEG4(source, mimeType, confidence)) {
         return true;
     }
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index 56e6136..9bc94de 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -27,6 +27,7 @@
 
 #include "matroska/MatroskaExtractor.h"
 
+#include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaExtractor.h>
@@ -46,10 +47,12 @@
 // static
 sp<MediaExtractor> MediaExtractor::Create(
         const sp<DataSource> &source, const char *mime) {
+    sp<AMessage> meta;
+
     String8 tmp;
     if (mime == NULL) {
         float confidence;
-        if (!source->sniff(&tmp, &confidence)) {
+        if (!source->sniff(&tmp, &confidence, &meta)) {
             LOGV("FAILED to autodetect media content.");
 
             return NULL;
@@ -64,7 +67,7 @@
             || !strcasecmp(mime, "audio/mp4")) {
         return new MPEG4Extractor(source);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
-        return new MP3Extractor(source);
+        return new MP3Extractor(source, meta);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)
             || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) {
         return new AMRExtractor(source);
diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
index 9630092..2c1311a 100644
--- a/media/libstagefright/OggExtractor.cpp
+++ b/media/libstagefright/OggExtractor.cpp
@@ -804,7 +804,8 @@
 }
 
 bool SniffOgg(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence) {
+        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        sp<AMessage> *) {
     char tmp[4];
     if (source->readAt(0, tmp, 4) < 4 || memcmp(tmp, "OggS", 4)) {
         return false;
diff --git a/media/libstagefright/WAVExtractor.cpp b/media/libstagefright/WAVExtractor.cpp
index 8d820c0..57c1075 100644
--- a/media/libstagefright/WAVExtractor.cpp
+++ b/media/libstagefright/WAVExtractor.cpp
@@ -404,7 +404,8 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 bool SniffWAV(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence) {
+        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        sp<AMessage> *) {
     char header[12];
     if (source->readAt(0, header, sizeof(header)) < (ssize_t)sizeof(header)) {
         return false;
diff --git a/media/libstagefright/include/AMRExtractor.h b/media/libstagefright/include/AMRExtractor.h
index db49fe4..1cdf36d 100644
--- a/media/libstagefright/include/AMRExtractor.h
+++ b/media/libstagefright/include/AMRExtractor.h
@@ -22,6 +22,7 @@
 
 namespace android {
 
+struct AMessage;
 class String8;
 
 class AMRExtractor : public MediaExtractor {
@@ -49,7 +50,8 @@
 };
 
 bool SniffAMR(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence);
+        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        sp<AMessage> *);
 
 }  // namespace android
 
diff --git a/media/libstagefright/include/MP3Extractor.h b/media/libstagefright/include/MP3Extractor.h
index 3ce6df3..0e6ccde 100644
--- a/media/libstagefright/include/MP3Extractor.h
+++ b/media/libstagefright/include/MP3Extractor.h
@@ -22,13 +22,14 @@
 
 namespace android {
 
+struct AMessage;
 class DataSource;
 class String8;
 
 class MP3Extractor : public MediaExtractor {
 public:
     // Extractor assumes ownership of "source".
-    MP3Extractor(const sp<DataSource> &source);
+    MP3Extractor(const sp<DataSource> &source, const sp<AMessage> &meta);
 
     virtual size_t countTracks();
     virtual sp<MediaSource> getTrack(size_t index);
@@ -52,7 +53,8 @@
 };
 
 bool SniffMP3(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence);
+        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        sp<AMessage> *meta);
 
 }  // namespace android
 
diff --git a/media/libstagefright/include/MPEG2TSExtractor.h b/media/libstagefright/include/MPEG2TSExtractor.h
index c96973b..1bf4cd1 100644
--- a/media/libstagefright/include/MPEG2TSExtractor.h
+++ b/media/libstagefright/include/MPEG2TSExtractor.h
@@ -9,6 +9,7 @@
 
 namespace android {
 
+struct AMessage;
 struct AnotherPacketSource;
 struct ATSParser;
 struct DataSource;
@@ -47,7 +48,8 @@
 };
 
 bool SniffMPEG2TS(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence);
+        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        sp<AMessage> *);
 
 }  // namespace android
 
diff --git a/media/libstagefright/include/MPEG4Extractor.h b/media/libstagefright/include/MPEG4Extractor.h
index c8663d5..1c9cc7e 100644
--- a/media/libstagefright/include/MPEG4Extractor.h
+++ b/media/libstagefright/include/MPEG4Extractor.h
@@ -23,6 +23,7 @@
 
 namespace android {
 
+struct AMessage;
 class DataSource;
 class SampleTable;
 class String8;
@@ -75,7 +76,8 @@
 };
 
 bool SniffMPEG4(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence);
+        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        sp<AMessage> *);
 
 }  // namespace android
 
diff --git a/media/libstagefright/include/OggExtractor.h b/media/libstagefright/include/OggExtractor.h
index 7066669..1eda025 100644
--- a/media/libstagefright/include/OggExtractor.h
+++ b/media/libstagefright/include/OggExtractor.h
@@ -22,6 +22,7 @@
 
 namespace android {
 
+struct AMessage;
 class DataSource;
 class String8;
 
@@ -53,7 +54,8 @@
 };
 
 bool SniffOgg(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence);
+        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        sp<AMessage> *);
 
 }  // namespace android
 
diff --git a/media/libstagefright/include/WAVExtractor.h b/media/libstagefright/include/WAVExtractor.h
index 3e847b9..df6d3e7 100644
--- a/media/libstagefright/include/WAVExtractor.h
+++ b/media/libstagefright/include/WAVExtractor.h
@@ -22,6 +22,7 @@
 
 namespace android {
 
+struct AMessage;
 class DataSource;
 class String8;
 
@@ -58,7 +59,8 @@
 };
 
 bool SniffWAV(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence);
+        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        sp<AMessage> *);
 
 }  // namespace android
 
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index 71f6587..7c7d69e 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -579,7 +579,8 @@
 }
 
 bool SniffMatroska(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence) {
+        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        sp<AMessage> *) {
     DataSourceReader reader(source);
     mkvparser::EBMLHeader ebmlHeader;
     long long pos;
diff --git a/media/libstagefright/matroska/MatroskaExtractor.h b/media/libstagefright/matroska/MatroskaExtractor.h
index 7471848..fa20b84 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.h
+++ b/media/libstagefright/matroska/MatroskaExtractor.h
@@ -27,6 +27,7 @@
 
 namespace android {
 
+struct AMessage;
 class String8;
 
 struct DataSourceReader;
@@ -69,7 +70,8 @@
 };
 
 bool SniffMatroska(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence);
+        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        sp<AMessage> *);
 
 }  // namespace android
 
diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
index b287c95..56ca375 100644
--- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
@@ -174,7 +174,8 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 bool SniffMPEG2TS(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence) {
+        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        sp<AMessage> *) {
 #if 0
     char header;
     if (source->readAt(0, &header, 1) != 1 || header != 0x47) {