Merge "AMRNB: use Frame_Type_3GPP defined in frame_type_3gpp.h instead." into gingerbread
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 8b54871..f55b746 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -46,6 +46,7 @@
 #include <media/mediametadataretriever.h>
 
 #include <media/stagefright/foundation/hexdump.h>
+#include <media/stagefright/MPEG2TSWriter.h>
 #include <media/stagefright/MPEG4Writer.h>
 
 #include <fcntl.h>
@@ -366,8 +367,13 @@
 
 static void writeSourcesToMP4(
         Vector<sp<MediaSource> > &sources, bool syncInfoPresent) {
+#if 0
     sp<MPEG4Writer> writer =
         new MPEG4Writer(gWriteMP4Filename.string());
+#else
+    sp<MPEG2TSWriter> writer =
+        new MPEG2TSWriter(gWriteMP4Filename.string());
+#endif
 
     // at most one minute.
     writer->setMaxFileDuration(60000000ll);
diff --git a/include/media/stagefright/AudioPlayer.h b/include/media/stagefright/AudioPlayer.h
index 9a09586..ed2f7d7 100644
--- a/include/media/stagefright/AudioPlayer.h
+++ b/include/media/stagefright/AudioPlayer.h
@@ -27,6 +27,7 @@
 
 class MediaSource;
 class AudioTrack;
+class AwesomePlayer;
 
 class AudioPlayer : public TimeSource {
 public:
@@ -35,7 +36,9 @@
         SEEK_COMPLETE
     };
 
-    AudioPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink);
+    AudioPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink,
+                AwesomePlayer *audioObserver = NULL);
+
     virtual ~AudioPlayer();
 
     // Caller retains ownership of "source".
@@ -91,6 +94,7 @@
     MediaBuffer *mFirstBuffer;
 
     sp<MediaPlayerBase::AudioSink> mAudioSink;
+    AwesomePlayer *mObserver;
 
     static void AudioCallback(int event, void *user, void *info);
     void AudioCallback(int event, void *info);
diff --git a/include/media/stagefright/MPEG2TSWriter.h b/include/media/stagefright/MPEG2TSWriter.h
new file mode 100644
index 0000000..551ca01
--- /dev/null
+++ b/include/media/stagefright/MPEG2TSWriter.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef MPEG2TS_WRITER_H_
+
+#define MPEG2TS_WRITER_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/foundation/AHandlerReflector.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/MediaWriter.h>
+
+namespace android {
+
+struct MPEG2TSWriter : public MediaWriter {
+    MPEG2TSWriter(const char *filename);
+
+    virtual status_t addSource(const sp<MediaSource> &source);
+    virtual status_t start(MetaData *param = NULL);
+    virtual status_t stop();
+    virtual status_t pause();
+    virtual bool reachedEOS();
+    virtual status_t dump(int fd, const Vector<String16>& args);
+
+    void onMessageReceived(const sp<AMessage> &msg);
+
+protected:
+    virtual ~MPEG2TSWriter();
+
+private:
+    enum {
+        kWhatSourceNotify = 'noti'
+    };
+
+    struct SourceInfo;
+
+    FILE *mFile;
+    sp<ALooper> mLooper;
+    sp<AHandlerReflector<MPEG2TSWriter> > mReflector;
+
+    bool mStarted;
+
+    Vector<sp<SourceInfo> > mSources;
+    size_t mNumSourcesDone;
+
+    int64_t mNumTSPacketsWritten;
+    int64_t mNumTSPacketsBeforeMeta;
+
+    void writeTS();
+    void writeProgramAssociationTable();
+    void writeProgramMap();
+    void writeAccessUnit(int32_t sourceIndex, const sp<ABuffer> &buffer);
+
+    DISALLOW_EVIL_CONSTRUCTORS(MPEG2TSWriter);
+};
+
+}  // namespace android
+
+#endif  // MPEG2TS_WRITER_H_
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index 1594e31..ab2f11d 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -95,6 +95,8 @@
 
     // Ogg files can be tagged to be automatically looping...
     kKeyAutoLoop          = 'autL',  // bool (int32_t)
+
+    kKeyValidSamples      = 'valD',  // int32_t
 };
 
 enum {
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 8f40130..ebe3302 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -63,7 +63,6 @@
 
 // Flag to allow a one time init of global memory, only happens on first call ever
 int LvmInitFlag = LVM_FALSE;
-int LvmSessionsActive = 0;
 SessionContext GlobalSessionMemory[LVM_MAX_SESSIONS];
 
 int SessionIndex[LVM_MAX_SESSIONS];
@@ -189,16 +188,19 @@
                             int32_t             sessionId,
                             int32_t             ioId,
                             effect_interface_t  *pInterface){
-    int ret;
+    int ret = 0;
     int sessionNo;
     int i;
-    EffectContext *pContext = new EffectContext;
+    EffectContext *pContext = NULL;
+    bool newBundle = false;
+    SessionContext *pSessionContext;
 
     LOGV("\n\tEffectCreate start session %d", sessionId);
 
     if (pInterface == NULL || uuid == NULL){
         LOGV("\tLVM_ERROR : EffectCreate() called with NULL pointer");
-        return -EINVAL;
+        ret = -EINVAL;
+        goto exit;
     }
 
     if(LvmInitFlag == LVM_FALSE){
@@ -207,8 +209,6 @@
         LvmGlobalBundle_init();
     }
 
-    LOGV("\tEffectCreate: There are %d LVM sessions acive\n", LvmSessionsActive);
-
     // Find next available sessionNo
     for(i=0; i<LVM_MAX_SESSIONS; i++){
         if((SessionIndex[i] == LVM_UNUSED_SESSION)||(SessionIndex[i] == sessionId)){
@@ -221,23 +221,20 @@
 
     if(i==LVM_MAX_SESSIONS){
         LOGV("\tLVM_ERROR : Cannot find memory to allocate for current session");
-        return -EINVAL;
+        ret = -EINVAL;
+        goto exit;
     }
+
+    pContext = new EffectContext;
+
     // If this is the first create in this session
     if(GlobalSessionMemory[sessionNo].bBundledEffectsEnabled == LVM_FALSE){
         LOGV("\tEffectCreate - This is the first effect in current sessionId %d sessionNo %d",
                 sessionId, sessionNo);
 
-        LvmSessionsActive++;
-
-        if(LvmSessionsActive >= LVM_MAX_SESSIONS){
-            LOGV("\tLVM_ERROR : Number of active session is greater than LVM_MAX_SESSIONS (%d)",
-                  LVM_MAX_SESSIONS);
-            return -EINVAL;
-        }
-
         GlobalSessionMemory[sessionNo].bBundledEffectsEnabled = LVM_TRUE;
         GlobalSessionMemory[sessionNo].pBundledContext        = new BundledEffectContext;
+        newBundle = true;
 
         pContext->pBundledContext = GlobalSessionMemory[sessionNo].pBundledContext;
         pContext->pBundledContext->SessionNo                = sessionNo;
@@ -251,17 +248,16 @@
         pContext->pBundledContext->bVirtualizerTempDisabled = LVM_FALSE;
         pContext->pBundledContext->NumberEffectsEnabled     = 0;
         pContext->pBundledContext->NumberEffectsCalled      = 0;
-        pContext->pBundledContext->frameCount               = 0;
         pContext->pBundledContext->firstVolume              = LVM_TRUE;
 
         #ifdef LVM_PCM
-
         char fileName[256];
         snprintf(fileName, 256, "/data/tmp/bundle_%p_pcm_in.pcm", pContext->pBundledContext);
         pContext->pBundledContext->PcmInPtr = fopen(fileName, "w");
         if (pContext->pBundledContext->PcmInPtr == NULL) {
             LOGV("cannot open %s", fileName);
-           return -EINVAL;
+            ret = -EINVAL;
+            goto exit;
         }
 
         snprintf(fileName, 256, "/data/tmp/bundle_%p_pcm_out.pcm", pContext->pBundledContext);
@@ -270,7 +266,8 @@
             LOGV("cannot open %s", fileName);
             fclose(pContext->pBundledContext->PcmInPtr);
            pContext->pBundledContext->PcmInPtr = NULL;
-           return -EINVAL;
+           ret = -EINVAL;
+           goto exit;
         }
         #endif
 
@@ -285,15 +282,18 @@
         pContext->pBundledContext->bMuteEnabled             = LVM_FALSE;
         pContext->pBundledContext->bStereoPositionEnabled   = LVM_FALSE;
         pContext->pBundledContext->positionSaved            = 0;
+        pContext->pBundledContext->workBuffer               = NULL;
+        pContext->pBundledContext->frameCount               = -1;
+        pContext->pBundledContext->SamplesToExitCountVirt   = 0;
+        pContext->pBundledContext->SamplesToExitCountBb     = 0;
+        pContext->pBundledContext->SamplesToExitCountEq     = 0;
 
         LOGV("\tEffectCreate - Calling LvmBundle_init");
         ret = LvmBundle_init(pContext);
 
         if (ret < 0){
             LOGV("\tLVM_ERROR : EffectCreate() Bundle init failed");
-            delete pContext->pBundledContext;
-            delete pContext;
-            return ret;
+            goto exit;
         }
     }
     else{
@@ -304,13 +304,14 @@
     }
     LOGV("\tEffectCreate - pBundledContext is %p", pContext->pBundledContext);
 
-    SessionContext *pSessionContext = &GlobalSessionMemory[pContext->pBundledContext->SessionNo];
+    pSessionContext = &GlobalSessionMemory[pContext->pBundledContext->SessionNo];
 
     // Create each Effect
     if (memcmp(uuid, &gBassBoostDescriptor.uuid, sizeof(effect_uuid_t)) == 0){
         // Create Bass Boost
         LOGV("\tEffectCreate - Effect to be created is LVM_BASS_BOOST");
         pSessionContext->bBassInstantiated = LVM_TRUE;
+        pContext->pBundledContext->SamplesToExitCountBb = 0;
 
         pContext->itfe       = &gLvmEffectInterface;
         pContext->EffectType = LVM_BASS_BOOST;
@@ -318,6 +319,7 @@
         // Create Virtualizer
         LOGV("\tEffectCreate - Effect to be created is LVM_VIRTUALIZER");
         pSessionContext->bVirtualizerInstantiated=LVM_TRUE;
+        pContext->pBundledContext->SamplesToExitCountVirt = 0;
 
         pContext->itfe       = &gLvmEffectInterface;
         pContext->EffectType = LVM_VIRTUALIZER;
@@ -325,6 +327,7 @@
         // Create Equalizer
         LOGV("\tEffectCreate - Effect to be created is LVM_EQUALIZER");
         pSessionContext->bEqualizerInstantiated = LVM_TRUE;
+        pContext->pBundledContext->SamplesToExitCountEq = 0;
 
         pContext->itfe       = &gLvmEffectInterface;
         pContext->EffectType = LVM_EQUALIZER;
@@ -338,46 +341,77 @@
     }
     else{
         LOGV("\tLVM_ERROR : EffectCreate() invalid UUID");
-        return -EINVAL;
+        ret = -EINVAL;
+        goto exit;
     }
 
-    *pInterface = (effect_interface_t)pContext;
+exit:
+    if (ret != 0) {
+        if (pContext != NULL) {
+            if (newBundle) {
+                GlobalSessionMemory[sessionNo].bBundledEffectsEnabled = LVM_FALSE;
+                SessionIndex[sessionNo] = LVM_UNUSED_SESSION;
+                delete pContext->pBundledContext;
+            }
+            delete pContext;
+        }
+        *pInterface = (effect_interface_t)NULL;
+    } else {
+        *pInterface = (effect_interface_t)pContext;
+    }
     LOGV("\tEffectCreate end..\n\n");
-    return 0;
+    return ret;
 } /* end EffectCreate */
 
 extern "C" int EffectRelease(effect_interface_t interface){
     LOGV("\n\tEffectRelease start %p", interface);
     EffectContext * pContext = (EffectContext *)interface;
 
-    LOGV("\n\tEffectRelease start interface: %p, context %p", interface, pContext->pBundledContext);
+    LOGV("\tEffectRelease start interface: %p, context %p", interface, pContext->pBundledContext);
     if (pContext == NULL){
         LOGV("\tLVM_ERROR : EffectRelease called with NULL pointer");
         return -EINVAL;
     }
 
-
-    Effect_setEnabled(pContext, LVM_FALSE);
-
     SessionContext *pSessionContext = &GlobalSessionMemory[pContext->pBundledContext->SessionNo];
 
     // Clear the instantiated flag for the effect
+    // protect agains the case where an effect is un-instantiated without being disabled
     if(pContext->EffectType == LVM_BASS_BOOST) {
         LOGV("\tEffectRelease LVM_BASS_BOOST Clearing global intstantiated flag");
         pSessionContext->bBassInstantiated = LVM_FALSE;
+        if(pContext->pBundledContext->SamplesToExitCountBb > 0){
+            pContext->pBundledContext->NumberEffectsEnabled--;
+        }
+        pContext->pBundledContext->SamplesToExitCountBb = 0;
     } else if(pContext->EffectType == LVM_VIRTUALIZER) {
         LOGV("\tEffectRelease LVM_VIRTUALIZER Clearing global intstantiated flag");
         pSessionContext->bVirtualizerInstantiated = LVM_FALSE;
+        if(pContext->pBundledContext->SamplesToExitCountVirt > 0){
+            pContext->pBundledContext->NumberEffectsEnabled--;
+        }
+        pContext->pBundledContext->SamplesToExitCountVirt = 0;
     } else if(pContext->EffectType == LVM_EQUALIZER) {
         LOGV("\tEffectRelease LVM_EQUALIZER Clearing global intstantiated flag");
         pSessionContext->bEqualizerInstantiated =LVM_FALSE;
+        if(pContext->pBundledContext->SamplesToExitCountEq > 0){
+            pContext->pBundledContext->NumberEffectsEnabled--;
+        }
+        pContext->pBundledContext->SamplesToExitCountEq = 0;
     } else if(pContext->EffectType == LVM_VOLUME) {
         LOGV("\tEffectRelease LVM_VOLUME Clearing global intstantiated flag");
         pSessionContext->bVolumeInstantiated = LVM_FALSE;
+        if (pContext->pBundledContext->bVolumeEnabled == LVM_TRUE){
+            pContext->pBundledContext->NumberEffectsEnabled--;
+        }
     } else {
         LOGV("\tLVM_ERROR : EffectRelease : Unsupported effect\n\n\n\n\n\n\n");
     }
 
+    // Disable effect, in this case ignore errors (return codes)
+    // if an effect has already been disabled
+    Effect_setEnabled(pContext, LVM_FALSE);
+
     // if all effects are no longer instantiaed free the lvm memory and delete BundledEffectContext
     if ((pSessionContext->bBassInstantiated == LVM_FALSE) &&
             (pSessionContext->bVolumeInstantiated == LVM_FALSE) &&
@@ -395,8 +429,6 @@
         }
         #endif
 
-        LvmSessionsActive--;
-        LOGV("\tEffectRelease: There are %d LVM sessions remaining\n", LvmSessionsActive);
 
         // Clear the SessionIndex
         for(int i=0; i<LVM_MAX_SESSIONS; i++){
@@ -409,11 +441,14 @@
         }
 
         LOGV("\tEffectRelease: All effects are no longer instantiated\n");
-        pSessionContext->bBundledEffectsEnabled =LVM_FALSE;
+        pSessionContext->bBundledEffectsEnabled = LVM_FALSE;
         pSessionContext->pBundledContext = LVM_NULL;
         LOGV("\tEffectRelease: Freeing LVM Bundle memory\n");
         LvmEffect_free(pContext);
         LOGV("\tEffectRelease: Deleting LVM Bundle context %p\n", pContext->pBundledContext);
+        if (pContext->pBundledContext->workBuffer != NULL) {
+            free(pContext->pBundledContext->workBuffer);
+        }
         delete pContext->pBundledContext;
         pContext->pBundledContext = LVM_NULL;
     }
@@ -643,6 +678,14 @@
     return 0;
 }   /* end LvmBundle_init */
 
+
+static inline int16_t clamp16(int32_t sample)
+{
+    if ((sample>>15) ^ (sample>>31))
+        sample = 0x7FFF ^ (sample>>31);
+    return sample;
+}
+
 //----------------------------------------------------------------------------
 // LvmBundle_process()
 //----------------------------------------------------------------------------
@@ -668,39 +711,25 @@
 
     LVM_ControlParams_t     ActiveParams;                           /* Current control Parameters */
     LVM_ReturnStatus_en     LvmStatus = LVM_SUCCESS;                /* Function call status */
-
     LVM_INT16               *pOutTmp;
+
     if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_WRITE){
         pOutTmp = pOut;
     }else if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE){
-        pOutTmp = (LVM_INT16 *)malloc(frameCount * sizeof(LVM_INT16) * 2);
-        if(pOutTmp == NULL){
-            LOGV("\tLVM_ERROR : LvmBundle_process failed to allocate memory for "
-            "EFFECT_BUFFER_ACCESS_ACCUMULATE mode");
-            return -EINVAL;
+        if (pContext->pBundledContext->frameCount != frameCount) {
+            if (pContext->pBundledContext->workBuffer != NULL) {
+                free(pContext->pBundledContext->workBuffer);
+            }
+            pContext->pBundledContext->workBuffer =
+                    (LVM_INT16 *)malloc(frameCount * sizeof(LVM_INT16) * 2);
+            pContext->pBundledContext->frameCount = frameCount;
         }
+        pOutTmp = pContext->pBundledContext->workBuffer;
     }else{
         LOGV("LVM_ERROR : LvmBundle_process invalid access mode");
         return -EINVAL;
     }
 
-    /* Get the current settings */
-    LvmStatus = LVM_GetControlParameters(pContext->pBundledContext->hInstance,
-                                         &ActiveParams);
-
-    LVM_ERROR_CHECK(LvmStatus, "LVM_GetControlParameters", "LvmBundle_process")
-    if(LvmStatus != LVM_SUCCESS) return -EINVAL;
-
-    pContext->pBundledContext->frameCount++;
-    if(pContext->pBundledContext->frameCount == 100)
-    {
-        //LOGV("\tBB: %d VIRT: %d EQ: %d, session (%d), context is %p\n",
-        //ActiveParams.BE_OperatingMode,
-        //ActiveParams.VirtualizerOperatingMode, ActiveParams.EQNB_OperatingMode,
-        //pContext->pBundledContext->SessionNo, pContext->pBundledContext);
-        pContext->pBundledContext->frameCount = 0;
-    }
-
     #ifdef LVM_PCM
     fwrite(pIn, frameCount*sizeof(LVM_INT16)*2, 1, pContext->pBundledContext->PcmInPtr);
     fflush(pContext->pBundledContext->PcmInPtr);
@@ -725,9 +754,8 @@
 
     if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE){
         for (int i=0; i<frameCount*2; i++){
-            pOut[i] +=  pOutTmp[i];
+            pOut[i] = clamp16((LVM_INT32)pOut[i] + (LVM_INT32)pOutTmp[i]);
         }
-        free(pOutTmp);
     }
     return 0;
 }    /* end LvmBundle_process */
@@ -813,15 +841,15 @@
         ActiveParams.BE_OperatingMode       = LVM_BE_OFF;
     }
     if(pContext->EffectType == LVM_VIRTUALIZER) {
-        LOGV("\tLvmEffect_disable : Enabling LVM_VIRTUALIZER");
+        LOGV("\tLvmEffect_disable : Disabling LVM_VIRTUALIZER");
         ActiveParams.VirtualizerOperatingMode   = LVM_MODE_OFF;
     }
     if(pContext->EffectType == LVM_EQUALIZER) {
-        LOGV("\tLvmEffect_disable : Enabling LVM_EQUALIZER");
+        LOGV("\tLvmEffect_disable : Disabling LVM_EQUALIZER");
         ActiveParams.EQNB_OperatingMode     = LVM_EQNB_OFF;
     }
     if(pContext->EffectType == LVM_VOLUME) {
-        LOGV("\tLvmEffect_disable : Enabling LVM_VOLUME");
+        LOGV("\tLvmEffect_disable : Disabling LVM_VOLUME");
     }
 
     LvmStatus = LVM_SetControlParameters(pContext->pBundledContext->hInstance, &ActiveParams);
@@ -2406,85 +2434,114 @@
         switch (pContext->EffectType) {
             case LVM_BASS_BOOST:
                 if (pContext->pBundledContext->bBassEnabled == LVM_TRUE) {
-                     LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_BASS_BOOST is already enabled");
+                     LOGV("\tEffect_setEnabled() LVM_BASS_BOOST is already enabled");
                      return -EINVAL;
                 }
+                if(pContext->pBundledContext->SamplesToExitCountBb <= 0){
+                    pContext->pBundledContext->NumberEffectsEnabled++;
+                }
                 pContext->pBundledContext->SamplesToExitCountBb =
                      (LVM_INT32)(pContext->pBundledContext->SamplesPerSecond*0.1);
                 pContext->pBundledContext->bBassEnabled = LVM_TRUE;
                 break;
             case LVM_EQUALIZER:
                 if (pContext->pBundledContext->bEqualizerEnabled == LVM_TRUE) {
-                    LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_EQUALIZER is already enabled");
+                    LOGV("\tEffect_setEnabled() LVM_EQUALIZER is already enabled");
                     return -EINVAL;
                 }
+                if(pContext->pBundledContext->SamplesToExitCountEq <= 0){
+                    pContext->pBundledContext->NumberEffectsEnabled++;
+                }
                 pContext->pBundledContext->SamplesToExitCountEq =
                      (LVM_INT32)(pContext->pBundledContext->SamplesPerSecond*0.1);
                 pContext->pBundledContext->bEqualizerEnabled = LVM_TRUE;
                 break;
             case LVM_VIRTUALIZER:
                 if (pContext->pBundledContext->bVirtualizerEnabled == LVM_TRUE) {
-                    LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_VIRTUALIZER is already enabled");
+                    LOGV("\tEffect_setEnabled() LVM_VIRTUALIZER is already enabled");
                     return -EINVAL;
                 }
+                if(pContext->pBundledContext->SamplesToExitCountVirt <= 0){
+                    pContext->pBundledContext->NumberEffectsEnabled++;
+                }
                 pContext->pBundledContext->SamplesToExitCountVirt =
                      (LVM_INT32)(pContext->pBundledContext->SamplesPerSecond*0.1);
                 pContext->pBundledContext->bVirtualizerEnabled = LVM_TRUE;
                 break;
             case LVM_VOLUME:
                 if (pContext->pBundledContext->bVolumeEnabled == LVM_TRUE) {
-                    LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_VOLUME is already enabled");
+                    LOGV("\tEffect_setEnabled() LVM_VOLUME is already enabled");
                     return -EINVAL;
                 }
+                pContext->pBundledContext->NumberEffectsEnabled++;
                 pContext->pBundledContext->bVolumeEnabled = LVM_TRUE;
                 break;
             default:
-                LOGV("\tLVM_ERROR : Effect_setEnabled() invalid effect type");
+                LOGV("\tEffect_setEnabled() invalid effect type");
                 return -EINVAL;
         }
-        pContext->pBundledContext->NumberEffectsEnabled++;
         LvmEffect_enable(pContext);
     } else {
         switch (pContext->EffectType) {
             case LVM_BASS_BOOST:
                 if (pContext->pBundledContext->bBassEnabled == LVM_FALSE) {
-                    LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_BASS_BOOST is already disabled");
+                    LOGV("\tEffect_setEnabled() LVM_BASS_BOOST is already disabled");
                     return -EINVAL;
                 }
                 pContext->pBundledContext->bBassEnabled = LVM_FALSE;
                 break;
             case LVM_EQUALIZER:
                 if (pContext->pBundledContext->bEqualizerEnabled == LVM_FALSE) {
-                    LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_EQUALIZER is already disabled");
+                    LOGV("\tEffect_setEnabled() LVM_EQUALIZER is already disabled");
                     return -EINVAL;
                 }
                 pContext->pBundledContext->bEqualizerEnabled = LVM_FALSE;
                 break;
             case LVM_VIRTUALIZER:
                 if (pContext->pBundledContext->bVirtualizerEnabled == LVM_FALSE) {
-                    LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_VIRTUALIZER is already disabled");
+                    LOGV("\tEffect_setEnabled() LVM_VIRTUALIZER is already disabled");
                     return -EINVAL;
                 }
                 pContext->pBundledContext->bVirtualizerEnabled = LVM_FALSE;
                 break;
             case LVM_VOLUME:
                 if (pContext->pBundledContext->bVolumeEnabled == LVM_FALSE) {
-                    LOGV("\tLVM_ERROR : Effect_setEnabled() LVM_VOLUME is already disabled");
+                    LOGV("\tEffect_setEnabled() LVM_VOLUME is already disabled");
                     return -EINVAL;
                 }
                 pContext->pBundledContext->bVolumeEnabled = LVM_FALSE;
                 break;
             default:
-                LOGV("\tLVM_ERROR : Effect_setEnabled() invalid effect type");
+                LOGV("\tEffect_setEnabled() invalid effect type");
                 return -EINVAL;
         }
-        pContext->pBundledContext->NumberEffectsEnabled--;
         LvmEffect_disable(pContext);
     }
 
     return 0;
 }
 
+//----------------------------------------------------------------------------
+// LVC_Convert_VolToDb()
+//----------------------------------------------------------------------------
+// Purpose:
+// Convery volume in Q24 to dB
+//
+// Inputs:
+//  vol:   Q.24 volume dB
+//
+//-----------------------------------------------------------------------
+
+int16_t LVC_Convert_VolToDb(uint32_t vol){
+    int16_t  dB;
+
+    dB = LVC_ToDB_s32Tos16(vol <<7);
+    dB = (dB +8)>>4;
+    dB = (dB <-96) ? -96 : dB ;
+
+    return dB;
+}
+
 } // namespace
 } // namespace
 
@@ -2493,32 +2550,31 @@
                               audio_buffer_t         *inBuffer,
                               audio_buffer_t         *outBuffer){
     EffectContext * pContext = (EffectContext *) self;
-    LVM_ControlParams_t     ActiveParams;                           /* Current control Parameters */
     LVM_ReturnStatus_en     LvmStatus = LVM_SUCCESS;                /* Function call status */
     int    status = 0;
-    int    status2Sec = 0;
     int    lvmStatus = 0;
     LVM_INT16   *in  = (LVM_INT16 *)inBuffer->raw;
     LVM_INT16   *out = (LVM_INT16 *)outBuffer->raw;
 
-//LOGV("\tEffect_process Start : Enabled = %d     Called = %d",
-//pContext->pBundledContext->NumberEffectsEnabled,pContext->pBundledContext->NumberEffectsCalled);
-//    LOGV("\tEffect_process Start : Samples left %d %d %d",
+//LOGV("\tEffect_process Start : Enabled = %d     Called = %d (%8d %8d %8d)",
+//pContext->pBundledContext->NumberEffectsEnabled,pContext->pBundledContext->NumberEffectsCalled,
 //    pContext->pBundledContext->SamplesToExitCountBb,
 //    pContext->pBundledContext->SamplesToExitCountVirt,
 //    pContext->pBundledContext->SamplesToExitCountEq);
 
-//    LvmStatus = LVM_GetControlParameters(pContext->pBundledContext->hInstance, &ActiveParams);
-//    LVM_ERROR_CHECK(LvmStatus, "LVM_GetControlParameters", "VolumeGetStereoPosition")
-//    if(LvmStatus != LVM_SUCCESS) return -EINVAL;
-//    LOGV("\tEffect_process Internal Operating Modes: BB %d   VIRT %d    EQ %d",
-//        ActiveParams.BE_OperatingMode, ActiveParams.VirtualizerOperatingMode,
-//        ActiveParams.EQNB_OperatingMode);
-
     if (pContext == NULL){
         LOGV("\tLVM_ERROR : Effect_process() ERROR pContext == NULL");
         return -EINVAL;
     }
+
+    //if(pContext->EffectType == LVM_BASS_BOOST){
+    //  LOGV("\tEffect_process: Effect type is BASS_BOOST");
+    //}else if(pContext->EffectType == LVM_EQUALIZER){
+    //  LOGV("\tEffect_process: Effect type is LVM_EQUALIZER");
+    //}else if(pContext->EffectType == LVM_VIRTUALIZER){
+    //  LOGV("\tEffect_process: Effect type is LVM_VIRTUALIZER");
+    //}
+
     if (inBuffer == NULL  || inBuffer->raw == NULL  ||
             outBuffer == NULL || outBuffer->raw == NULL ||
             inBuffer->frameCount != outBuffer->frameCount){
@@ -2529,70 +2585,57 @@
         (pContext->EffectType == LVM_BASS_BOOST)){
         //LOGV("\tEffect_process() LVM_BASS_BOOST Effect is not enabled");
         if(pContext->pBundledContext->SamplesToExitCountBb > 0){
-            status2Sec = -ENODATA;
             pContext->pBundledContext->SamplesToExitCountBb -= outBuffer->frameCount * 2; // STEREO
             //LOGV("\tEffect_process: Waiting to turn off BASS_BOOST, %d samples left",
             //    pContext->pBundledContext->SamplesToExitCountBb);
         } else {
             status = -ENODATA;
+            pContext->pBundledContext->NumberEffectsEnabled--;
         }
     }
     if ((pContext->pBundledContext->bVolumeEnabled == LVM_FALSE)&&
         (pContext->EffectType == LVM_VOLUME)){
         //LOGV("\tEffect_process() LVM_VOLUME Effect is not enabled");
         status = -ENODATA;
+        pContext->pBundledContext->NumberEffectsEnabled--;
     }
     if ((pContext->pBundledContext->bEqualizerEnabled == LVM_FALSE)&&
         (pContext->EffectType == LVM_EQUALIZER)){
         //LOGV("\tEffect_process() LVM_EQUALIZER Effect is not enabled");
         if(pContext->pBundledContext->SamplesToExitCountEq > 0){
-            status2Sec = -ENODATA;
             pContext->pBundledContext->SamplesToExitCountEq -= outBuffer->frameCount * 2; // STEREO
-            //LOGV("\tEffect_process: Waiting for 2 secs to turn off EQUALIZER, %d samples left",
+            //LOGV("\tEffect_process: Waiting to turn off EQUALIZER, %d samples left",
             //    pContext->pBundledContext->SamplesToExitCountEq);
         } else {
             status = -ENODATA;
+            pContext->pBundledContext->NumberEffectsEnabled--;
         }
     }
     if ((pContext->pBundledContext->bVirtualizerEnabled == LVM_FALSE)&&
         (pContext->EffectType == LVM_VIRTUALIZER)){
         //LOGV("\tEffect_process() LVM_VIRTUALIZER Effect is not enabled");
         if(pContext->pBundledContext->SamplesToExitCountVirt > 0){
-            status2Sec = -ENODATA;
             pContext->pBundledContext->SamplesToExitCountVirt -= outBuffer->frameCount * 2;// STEREO
-            //LOGV("\tEffect_process: Waiting for 2 secs to turn off VIRTUALIZER, %d samples left",
+            //LOGV("\tEffect_process: Waiting for to turn off VIRTUALIZER, %d samples left",
             //    pContext->pBundledContext->SamplesToExitCountVirt);
         } else {
             status = -ENODATA;
+            pContext->pBundledContext->NumberEffectsEnabled--;
         }
     }
 
-    // If this is the last frame of an effect process its output with no effect
-    if(status == -ENODATA){
-        if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE){
-            //LOGV("\tLVM_ERROR : Effect_process() accumulating last frame into output buffer");
-            //LOGV("\tLVM_ERROR : Effect_process() trying copying last frame into output buffer");
-            //LOGV("\tLVM_ERROR : Enabled = %d     Called = %d",
-            //pContext->pBundledContext->NumberEffectsEnabled,
-            //pContext->pBundledContext->NumberEffectsCalled);
-
-        }else{
-            //LOGV("\tLVM_ERROR : Effect_process() copying last frame into output buffer");
-        }
-    }
-
-    if((status2Sec != -ENODATA)&&(status != -ENODATA)){
+    if(status != -ENODATA){
         pContext->pBundledContext->NumberEffectsCalled++;
     }
 
     if(pContext->pBundledContext->NumberEffectsCalled ==
        pContext->pBundledContext->NumberEffectsEnabled){
-        //LOGV("\tEffect_process Calling process with %d effects enabled, %d called: Effect %d",
+        //LOGV("\tEffect_process     Calling process with %d effects enabled, %d called: Effect %d",
         //pContext->pBundledContext->NumberEffectsEnabled,
         //pContext->pBundledContext->NumberEffectsCalled, pContext->EffectType);
 
         if(status == -ENODATA){
-            //LOGV("\tLVM_ERROR : Effect_process() actually processing last frame");
+            LOGV("\tEffect_process() processing last frame");
         }
         pContext->pBundledContext->NumberEffectsCalled = 0;
         /* Process all the available frames, block processing is
@@ -2836,10 +2879,10 @@
         case EFFECT_CMD_SET_PARAM:{
             //LOGV("\tEffect_command cmdCode Case: EFFECT_CMD_SET_PARAM start");
             if(pContext->EffectType == LVM_BASS_BOOST){
-                //LOGV("\tBassBoost_command EFFECT_CMD_SET_PARAM param %d, *replySize %d, value %d ",
-                //        *(int32_t *)((char *)pCmdData + sizeof(effect_param_t)),
-                //        *replySize,
-                //        *(int16_t *)((char *)pCmdData + sizeof(effect_param_t) + sizeof(int32_t)));
+                //LOGV("\tBassBoost_command EFFECT_CMD_SET_PARAM param %d, *replySize %d, value %d",
+                //       *(int32_t *)((char *)pCmdData + sizeof(effect_param_t)),
+                //       *replySize,
+                //       *(int16_t *)((char *)pCmdData + sizeof(effect_param_t) + sizeof(int32_t)));
 
                 if (pCmdData   == NULL||
                     cmdSize    != (int)(sizeof(effect_param_t) + sizeof(int32_t) +sizeof(int16_t))||
@@ -3038,30 +3081,71 @@
         }
         case EFFECT_CMD_SET_VOLUME:
         {
-            int32_t vol     = *(int32_t *)pCmdData;
-            int16_t dB;
-            int32_t vol_ret[2] = {1<<24,1<<24}; // Apply no volume
+            uint32_t leftVolume, rightVolume;
+            int16_t  leftdB, rightdB;
+            int16_t  maxdB, pandB;
+            int32_t  vol_ret[2] = {1<<24,1<<24}; // Apply no volume
+            int      status = 0;
+            LVM_ControlParams_t     ActiveParams;           /* Current control Parameters */
+            LVM_ReturnStatus_en     LvmStatus=LVM_SUCCESS;  /* Function call status */
 
             // if pReplyData is NULL, VOL_CTRL is delegated to another effect
             if(pReplyData == LVM_NULL){
                 break;
             }
 
-            if(vol==0x1000000){
-                vol -= 1;
+            if (pCmdData == NULL ||
+                cmdSize != 2 * sizeof(uint32_t)) {
+                LOGV("\tLVM_ERROR : Effect_command cmdCode Case: "
+                        "EFFECT_CMD_SET_VOLUME: ERROR");
+                return -EINVAL;
             }
-            // Convert volume linear (Q8.24) to volume dB (0->-96)
-            dB = android::LVC_ToDB_s32Tos16(vol <<7);
-            dB = (dB +8)>>4;
-            dB = (dB <-96) ? -96 : dB ;
 
-            LOGV("\tEFFECT_CMD_SET_VOLUME Session: %d, SessionID: %d VOLUME is %d dB (%d), "
-                  "effect is %d",
-            pContext->pBundledContext->SessionNo, pContext->pBundledContext->SessionId,
-            (int32_t)dB, vol<<7, pContext->EffectType);
+            leftVolume  = ((*(uint32_t *)pCmdData));
+            rightVolume = ((*((uint32_t *)pCmdData + 1)));
+
+            if(leftVolume == 0x1000000){
+                leftVolume -= 1;
+            }
+            if(rightVolume == 0x1000000){
+                rightVolume -= 1;
+            }
+
+            // Convert volume to dB
+            leftdB  = android::LVC_Convert_VolToDb(leftVolume);
+            rightdB = android::LVC_Convert_VolToDb(rightVolume);
+
+            pandB = rightdB - leftdB;
+
+            // Calculate max volume in dB
+            maxdB = leftdB;
+            if(rightdB > maxdB){
+                maxdB = rightdB;
+            }
+            //LOGV("\tEFFECT_CMD_SET_VOLUME Session: %d, SessionID: %d VOLUME is %d dB (%d), "
+            //      "effect is %d",
+            //pContext->pBundledContext->SessionNo, pContext->pBundledContext->SessionId,
+            //(int32_t)maxdB, maxVol<<7, pContext->EffectType);
+            //LOGV("\tEFFECT_CMD_SET_VOLUME: Left is %d, Right is %d", leftVolume, rightVolume);
+            //LOGV("\tEFFECT_CMD_SET_VOLUME: Left %ddB, Right %ddB, Position %ddB",
+            //        leftdB, rightdB, pandB);
 
             memcpy(pReplyData, vol_ret, sizeof(int32_t)*2);
-            android::VolumeSetVolumeLevel(pContext, (int16_t)(dB*100));
+            android::VolumeSetVolumeLevel(pContext, (int16_t)(maxdB*100));
+
+            /* Get the current settings */
+            LvmStatus =LVM_GetControlParameters(pContext->pBundledContext->hInstance,&ActiveParams);
+            LVM_ERROR_CHECK(LvmStatus, "LVM_GetControlParameters", "VolumeSetStereoPosition")
+            if(LvmStatus != LVM_SUCCESS) return -EINVAL;
+
+            /* Volume parameters */
+            ActiveParams.VC_Balance  = pandB;
+            LOGV("\t\tVolumeSetStereoPosition() (-96dB -> +96dB)-> %d\n", ActiveParams.VC_Balance );
+
+            /* Activate the initial settings */
+            LvmStatus =LVM_SetControlParameters(pContext->pBundledContext->hInstance,&ActiveParams);
+            LVM_ERROR_CHECK(LvmStatus, "LVM_SetControlParameters", "VolumeSetStereoPosition")
+            if(LvmStatus != LVM_SUCCESS) return -EINVAL;
             break;
          }
         case EFFECT_CMD_SET_AUDIO_MODE:
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
index 91963af..2b51029 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
@@ -88,12 +88,13 @@
     int                             positionSaved;
     bool                            bMuteEnabled;   /* Must store as mute = -96dB level */
     bool                            bStereoPositionEnabled;
-    int                             frameCount;
     LVM_Fs_en                       SampleRate;
     int                             SamplesPerSecond;
     int                             SamplesToExitCountEq;
     int                             SamplesToExitCountBb;
     int                             SamplesToExitCountVirt;
+    LVM_INT16                       *workBuffer;
+    int                             frameCount;
     #ifdef LVM_PCM
     FILE                            *PcmInPtr;
     FILE                            *PcmOutPtr;
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index aba5f52..d975cb9 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -534,8 +534,9 @@
         if (f) {
             while (!feof(f)) {
                 fgets(buffer, SIZE, f);
-                if (strstr(buffer, " /sdcard/") ||
+                if (strstr(buffer, " /mnt/sdcard/") ||
                     strstr(buffer, " /system/sounds/") ||
+                    strstr(buffer, " /data/") ||
                     strstr(buffer, " /system/media/")) {
                     result.append("  ");
                     result.append(buffer);
@@ -569,8 +570,9 @@
                                 } else {
                                     linkto[len] = 0;
                                 }
-                                if (strstr(linkto, "/sdcard/") == linkto ||
+                                if (strstr(linkto, "/mnt/sdcard/") == linkto ||
                                     strstr(linkto, "/system/sounds/") == linkto ||
+                                    strstr(linkto, "/data/") == linkto ||
                                     strstr(linkto, "/system/media/") == linkto) {
                                     result.append("  ");
                                     result.append(buffer);
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index e0321a5..3e17a7e 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -16,6 +16,7 @@
         HTTPStream.cpp                    \
         JPEGSource.cpp                    \
         MP3Extractor.cpp                  \
+        MPEG2TSWriter.cpp                 \
         MPEG4Extractor.cpp                \
         MPEG4Writer.cpp                   \
         MediaBuffer.cpp                   \
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index c27cfc8..b314114 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -27,9 +27,13 @@
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 
+#include "include/AwesomePlayer.h"
+
 namespace android {
 
-AudioPlayer::AudioPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink)
+AudioPlayer::AudioPlayer(
+        const sp<MediaPlayerBase::AudioSink> &audioSink,
+        AwesomePlayer *observer)
     : mAudioTrack(NULL),
       mInputBuffer(NULL),
       mSampleRate(0),
@@ -45,7 +49,8 @@
       mIsFirstBuffer(false),
       mFirstBufferResult(OK),
       mFirstBuffer(NULL),
-      mAudioSink(audioSink) {
+      mAudioSink(audioSink),
+      mObserver(observer) {
 }
 
 AudioPlayer::~AudioPlayer() {
@@ -301,6 +306,9 @@
                 }
 
                 mSeeking = false;
+                if (mObserver) {
+                    mObserver->postAudioSeekComplete();
+                }
             }
         }
 
@@ -323,6 +331,10 @@
             Mutex::Autolock autoLock(mLock);
 
             if (err != OK) {
+                if (mObserver && !mReachedEOS) {
+                    mObserver->postAudioEOS();
+                }
+
                 mReachedEOS = true;
                 mFinalStatus = err;
                 break;
@@ -411,6 +423,12 @@
     mReachedEOS = false;
     mSeekTimeUs = time_us;
 
+    if (mAudioSink != NULL) {
+        mAudioSink->flush();
+    } else {
+        mAudioTrack->flush();
+    }
+
     return OK;
 }
 
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 8507afc..12022bd 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -639,7 +639,7 @@
     if (mAudioSource != NULL) {
         if (mAudioPlayer == NULL) {
             if (mAudioSink != NULL) {
-                mAudioPlayer = new AudioPlayer(mAudioSink);
+                mAudioPlayer = new AudioPlayer(mAudioSink, this);
                 mAudioPlayer->setSource(mAudioSource);
 
                 // We've already started the MediaSource in order to enable
@@ -666,8 +666,6 @@
         } else {
             mAudioPlayer->resume();
         }
-
-        postCheckAudioStatusEvent_l();
     }
 
     if (mTimeSource == NULL && mAudioPlayer == NULL) {
@@ -1169,7 +1167,7 @@
         return;
     }
     mAudioStatusEventPending = true;
-    mQueue.postEventWithDelay(mCheckAudioStatusEvent, 100000ll);
+    mQueue.postEvent(mCheckAudioStatusEvent);
 }
 
 void AwesomePlayer::onCheckAudioStatus() {
@@ -1200,8 +1198,6 @@
         mFlags |= FIRST_FRAME;
         postStreamDoneEvent_l(finalStatus);
     }
-
-    postCheckAudioStatusEvent_l();
 }
 
 status_t AwesomePlayer::prepare() {
@@ -1662,5 +1658,13 @@
     return mExtractorFlags;
 }
 
+void AwesomePlayer::postAudioEOS() {
+    postCheckAudioStatusEvent_l();
+}
+
+void AwesomePlayer::postAudioSeekComplete() {
+    postCheckAudioStatusEvent_l();
+}
+
 }  // namespace android
 
diff --git a/media/libstagefright/MPEG2TSWriter.cpp b/media/libstagefright/MPEG2TSWriter.cpp
new file mode 100644
index 0000000..ee74b88
--- /dev/null
+++ b/media/libstagefright/MPEG2TSWriter.cpp
@@ -0,0 +1,758 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MPEG2TSWriter"
+#include <media/stagefright/foundation/ADebug.h>
+
+#include <media/stagefright/foundation/hexdump.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/MPEG2TSWriter.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
+
+#include "include/ESDS.h"
+
+namespace android {
+
+struct MPEG2TSWriter::SourceInfo : public AHandler {
+    SourceInfo(const sp<MediaSource> &source);
+
+    void start(const sp<AMessage> &notify);
+    void stop();
+
+    unsigned streamType() const;
+    unsigned incrementContinuityCounter();
+
+    enum {
+        kNotifyStartFailed,
+        kNotifyBuffer,
+        kNotifyReachedEOS,
+    };
+
+protected:
+    virtual void onMessageReceived(const sp<AMessage> &msg);
+
+    virtual ~SourceInfo();
+
+private:
+    enum {
+        kWhatStart = 'strt',
+        kWhatRead  = 'read',
+    };
+
+    sp<MediaSource> mSource;
+    sp<ALooper> mLooper;
+    sp<AMessage> mNotify;
+
+    sp<ABuffer> mAACBuffer;
+
+    unsigned mStreamType;
+    unsigned mContinuityCounter;
+
+    void extractCodecSpecificData();
+
+    void appendAACFrames(MediaBuffer *buffer);
+    void flushAACFrames();
+
+    void postAVCFrame(MediaBuffer *buffer);
+
+    DISALLOW_EVIL_CONSTRUCTORS(SourceInfo);
+};
+
+MPEG2TSWriter::SourceInfo::SourceInfo(const sp<MediaSource> &source)
+    : mSource(source),
+      mLooper(new ALooper),
+      mStreamType(0),
+      mContinuityCounter(0) {
+    mLooper->setName("MPEG2TSWriter source");
+
+    sp<MetaData> meta = mSource->getFormat();
+    const char *mime;
+    CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+    if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
+        mStreamType = 0x0f;
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
+        mStreamType = 0x1b;
+    } else {
+        TRESPASS();
+    }
+}
+
+MPEG2TSWriter::SourceInfo::~SourceInfo() {
+}
+
+unsigned MPEG2TSWriter::SourceInfo::streamType() const {
+    return mStreamType;
+}
+
+unsigned MPEG2TSWriter::SourceInfo::incrementContinuityCounter() {
+    if (++mContinuityCounter == 16) {
+        mContinuityCounter = 0;
+    }
+
+    return mContinuityCounter;
+}
+
+void MPEG2TSWriter::SourceInfo::start(const sp<AMessage> &notify) {
+    mLooper->registerHandler(this);
+    mLooper->start();
+
+    mNotify = notify;
+
+    (new AMessage(kWhatStart, id()))->post();
+}
+
+void MPEG2TSWriter::SourceInfo::stop() {
+    mLooper->unregisterHandler(id());
+    mLooper->stop();
+}
+
+void MPEG2TSWriter::SourceInfo::extractCodecSpecificData() {
+    sp<MetaData> meta = mSource->getFormat();
+
+    const char *mime;
+    CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+    if (strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
+        return;
+    }
+
+    sp<ABuffer> out = new ABuffer(1024);
+    out->setRange(0, 0);
+
+    uint32_t type;
+    const void *data;
+    size_t size;
+    CHECK(meta->findData(kKeyAVCC, &type, &data, &size));
+
+    const uint8_t *ptr = (const uint8_t *)data;
+
+    size_t numSeqParameterSets = ptr[5] & 31;
+
+    ptr += 6;
+    size -= 6;
+
+    for (size_t i = 0; i < numSeqParameterSets; ++i) {
+        CHECK(size >= 2);
+        size_t length = U16_AT(ptr);
+
+        ptr += 2;
+        size -= 2;
+
+        CHECK(size >= length);
+
+        CHECK_LE(out->size() + 4 + length, out->capacity());
+        memcpy(out->data() + out->size(), "\x00\x00\x00\x01", 4);
+        memcpy(out->data() + out->size() + 4, ptr, length);
+        out->setRange(0, out->size() + length + 4);
+
+        ptr += length;
+        size -= length;
+    }
+
+    CHECK(size >= 1);
+    size_t numPictureParameterSets = *ptr;
+    ++ptr;
+    --size;
+
+    for (size_t i = 0; i < numPictureParameterSets; ++i) {
+        CHECK(size >= 2);
+        size_t length = U16_AT(ptr);
+
+        ptr += 2;
+        size -= 2;
+
+        CHECK(size >= length);
+
+        CHECK_LE(out->size() + 4 + length, out->capacity());
+        memcpy(out->data() + out->size(), "\x00\x00\x00\x01", 4);
+        memcpy(out->data() + out->size() + 4, ptr, length);
+        out->setRange(0, out->size() + length + 4);
+
+        ptr += length;
+        size -= length;
+    }
+
+    out->meta()->setInt64("timeUs", 0ll);
+
+    sp<AMessage> notify = mNotify->dup();
+    notify->setInt32("what", kNotifyBuffer);
+    notify->setObject("buffer", out);
+    notify->post();
+}
+
+void MPEG2TSWriter::SourceInfo::postAVCFrame(MediaBuffer *buffer) {
+    sp<AMessage> notify = mNotify->dup();
+    notify->setInt32("what", kNotifyBuffer);
+
+    sp<ABuffer> copy =
+        new ABuffer(buffer->range_length());
+    memcpy(copy->data(),
+           (const uint8_t *)buffer->data()
+            + buffer->range_offset(),
+           buffer->range_length());
+
+    int64_t timeUs;
+    CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
+    copy->meta()->setInt64("timeUs", timeUs);
+
+    int32_t isSync;
+    if (buffer->meta_data()->findInt32(kKeyIsSyncFrame, &isSync)
+            && isSync != 0) {
+        copy->meta()->setInt32("isSync", true);
+    }
+
+    notify->setObject("buffer", copy);
+    notify->post();
+}
+
+void MPEG2TSWriter::SourceInfo::appendAACFrames(MediaBuffer *buffer) {
+    if (mAACBuffer != NULL
+            && mAACBuffer->size() + 7 + buffer->range_length()
+                    > mAACBuffer->capacity()) {
+        flushAACFrames();
+    }
+
+    if (mAACBuffer == NULL) {
+        size_t alloc = 4096;
+        if (buffer->range_length() + 7 > alloc) {
+            alloc = 7 + buffer->range_length();
+        }
+
+        mAACBuffer = new ABuffer(alloc);
+
+        int64_t timeUs;
+        CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
+
+        mAACBuffer->meta()->setInt64("timeUs", timeUs);
+        mAACBuffer->meta()->setInt32("isSync", true);
+
+        mAACBuffer->setRange(0, 0);
+    }
+
+    sp<MetaData> meta = mSource->getFormat();
+    uint32_t type;
+    const void *data;
+    size_t size;
+    CHECK(meta->findData(kKeyESDS, &type, &data, &size));
+
+    ESDS esds((const char *)data, size);
+    CHECK_EQ(esds.InitCheck(), (status_t)OK);
+
+    const uint8_t *codec_specific_data;
+    size_t codec_specific_data_size;
+    esds.getCodecSpecificInfo(
+            (const void **)&codec_specific_data, &codec_specific_data_size);
+
+    CHECK_GE(codec_specific_data_size, 2u);
+
+    unsigned profile = (codec_specific_data[0] >> 3) - 1;
+
+    unsigned sampling_freq_index =
+        ((codec_specific_data[0] & 7) << 1)
+        | (codec_specific_data[1] >> 7);
+
+    unsigned channel_configuration =
+        (codec_specific_data[1] >> 3) & 0x0f;
+
+    uint8_t *ptr = mAACBuffer->data() + mAACBuffer->size();
+
+    const uint32_t aac_frame_length = buffer->range_length() + 7;
+
+    *ptr++ = 0xff;
+    *ptr++ = 0xf1;  // b11110001, ID=0, layer=0, protection_absent=1
+
+    *ptr++ =
+        profile << 6
+        | sampling_freq_index << 2
+        | ((channel_configuration >> 2) & 1);  // private_bit=0
+
+    // original_copy=0, home=0, copyright_id_bit=0, copyright_id_start=0
+    *ptr++ =
+        (channel_configuration & 3) << 6
+        | aac_frame_length >> 11;
+    *ptr++ = (aac_frame_length >> 3) & 0xff;
+    *ptr++ = (aac_frame_length & 7) << 5;
+
+    // adts_buffer_fullness=0, number_of_raw_data_blocks_in_frame=0
+    *ptr++ = 0;
+
+    memcpy(ptr,
+           (const uint8_t *)buffer->data() + buffer->range_offset(),
+           buffer->range_length());
+
+    ptr += buffer->range_length();
+
+    mAACBuffer->setRange(0, ptr - mAACBuffer->data());
+}
+
+void MPEG2TSWriter::SourceInfo::flushAACFrames() {
+    if (mAACBuffer == NULL) {
+        return;
+    }
+
+    sp<AMessage> notify = mNotify->dup();
+    notify->setInt32("what", kNotifyBuffer);
+    notify->setObject("buffer", mAACBuffer);
+    notify->post();
+
+    mAACBuffer.clear();
+}
+
+void MPEG2TSWriter::SourceInfo::onMessageReceived(const sp<AMessage> &msg) {
+    switch (msg->what()) {
+        case kWhatStart:
+        {
+            status_t err = mSource->start();
+            if (err != OK) {
+                sp<AMessage> notify = mNotify->dup();
+                notify->setInt32("what", kNotifyStartFailed);
+                notify->post();
+                break;
+            }
+
+            extractCodecSpecificData();
+
+            (new AMessage(kWhatRead, id()))->post();
+            break;
+        }
+
+        case kWhatRead:
+        {
+            MediaBuffer *buffer;
+            status_t err = mSource->read(&buffer);
+
+            if (err != OK && err != INFO_FORMAT_CHANGED) {
+                if (mStreamType == 0x0f) {
+                    flushAACFrames();
+                }
+
+                sp<AMessage> notify = mNotify->dup();
+                notify->setInt32("what", kNotifyReachedEOS);
+                notify->setInt32("status", err);
+                notify->post();
+                break;
+            }
+
+            if (err == OK) {
+                if (buffer->range_length() > 0) {
+                    if (mStreamType == 0x0f) {
+                        appendAACFrames(buffer);
+                    } else {
+                        postAVCFrame(buffer);
+                    }
+                }
+
+                buffer->release();
+                buffer = NULL;
+            }
+
+            msg->post();
+            break;
+        }
+
+        default:
+            TRESPASS();
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+MPEG2TSWriter::MPEG2TSWriter(const char *filename)
+    : mFile(fopen(filename, "wb")),
+      mStarted(false),
+      mNumSourcesDone(0),
+      mNumTSPacketsWritten(0),
+      mNumTSPacketsBeforeMeta(0) {
+    CHECK(mFile != NULL);
+
+    mLooper = new ALooper;
+    mLooper->setName("MPEG2TSWriter");
+
+    mReflector = new AHandlerReflector<MPEG2TSWriter>(this);
+
+    mLooper->registerHandler(mReflector);
+    mLooper->start();
+}
+
+MPEG2TSWriter::~MPEG2TSWriter() {
+    mLooper->unregisterHandler(mReflector->id());
+    mLooper->stop();
+
+    fclose(mFile);
+    mFile = NULL;
+}
+
+status_t MPEG2TSWriter::addSource(const sp<MediaSource> &source) {
+    CHECK(!mStarted);
+
+    sp<MetaData> meta = source->getFormat();
+    const char *mime;
+    CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+    if (strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)
+            && strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
+        return ERROR_UNSUPPORTED;
+    }
+
+    sp<SourceInfo> info = new SourceInfo(source);
+
+    mSources.push(info);
+
+    return OK;
+}
+
+status_t MPEG2TSWriter::start(MetaData *param) {
+    CHECK(!mStarted);
+
+    mStarted = true;
+    mNumSourcesDone = 0;
+    mNumTSPacketsWritten = 0;
+    mNumTSPacketsBeforeMeta = 0;
+
+    for (size_t i = 0; i < mSources.size(); ++i) {
+        sp<AMessage> notify =
+            new AMessage(kWhatSourceNotify, mReflector->id());
+
+        notify->setInt32("source-index", i);
+
+        mSources.editItemAt(i)->start(notify);
+    }
+
+    return OK;
+}
+
+status_t MPEG2TSWriter::stop() {
+    CHECK(mStarted);
+
+    for (size_t i = 0; i < mSources.size(); ++i) {
+        mSources.editItemAt(i)->stop();
+    }
+    mStarted = false;
+
+    return OK;
+}
+
+status_t MPEG2TSWriter::pause() {
+    CHECK(mStarted);
+
+    return OK;
+}
+
+bool MPEG2TSWriter::reachedEOS() {
+    return !mStarted || (mNumSourcesDone == mSources.size() ? true : false);
+}
+
+status_t MPEG2TSWriter::dump(int fd, const Vector<String16> &args) {
+    return OK;
+}
+
+void MPEG2TSWriter::onMessageReceived(const sp<AMessage> &msg) {
+    switch (msg->what()) {
+        case kWhatSourceNotify:
+        {
+            int32_t sourceIndex;
+            CHECK(msg->findInt32("source-index", &sourceIndex));
+
+            int32_t what;
+            CHECK(msg->findInt32("what", &what));
+
+            if (what == SourceInfo::kNotifyReachedEOS
+                    || what == SourceInfo::kNotifyStartFailed) {
+                ++mNumSourcesDone;
+            } else if (what == SourceInfo::kNotifyBuffer) {
+                sp<RefBase> obj;
+                CHECK(msg->findObject("buffer", &obj));
+
+                writeTS();
+
+                sp<ABuffer> buffer = static_cast<ABuffer *>(obj.get());
+                writeAccessUnit(sourceIndex, buffer);
+            }
+            break;
+        }
+
+        default:
+            TRESPASS();
+    }
+}
+
+void MPEG2TSWriter::writeProgramAssociationTable() {
+    // 0x47
+    // transport_error_indicator = b0
+    // payload_unit_start_indicator = b1
+    // transport_priority = b0
+    // PID = b0000000000000 (13 bits)
+    // transport_scrambling_control = b00
+    // adaptation_field_control = b01 (no adaptation field, payload only)
+    // continuity_counter = b????
+    // skip = 0x00
+    // --- payload follows
+    // table_id = 0x00
+    // section_syntax_indicator = b1
+    // must_be_zero = b0
+    // reserved = b11
+    // section_length = 0x00d
+    // transport_stream_id = 0x0000
+    // reserved = b11
+    // version_number = b00001
+    // current_next_indicator = b1
+    // section_number = 0x00
+    // last_section_number = 0x00
+    //   one program follows:
+    //   program_number = 0x0001
+    //   reserved = b111
+    //   program_map_PID = 0x01e0 (13 bits!)
+    // CRC = 0x????????
+
+    static const uint8_t kData[] = {
+        0x47,
+        0x40, 0x00, 0x10, 0x00,  // b0100 0000 0000 0000 0001 ???? 0000 0000
+        0x00, 0xb0, 0x0d, 0x00,  // b0000 0000 1011 0000 0000 1101 0000 0000
+        0x00, 0xc3, 0x00, 0x00,  // b0000 0000 1100 0011 0000 0000 0000 0000
+        0x00, 0x01, 0xe1, 0xe0,  // b0000 0000 0000 0001 1110 0001 1110 0000
+        0x00, 0x00, 0x00, 0x00   // b???? ???? ???? ???? ???? ???? ???? ????
+    };
+
+    sp<ABuffer> buffer = new ABuffer(188);
+    memset(buffer->data(), 0, buffer->size());
+    memcpy(buffer->data(), kData, sizeof(kData));
+
+    static const unsigned kContinuityCounter = 5;
+    buffer->data()[3] |= kContinuityCounter;
+
+    CHECK_EQ(fwrite(buffer->data(), 1, buffer->size(), mFile), buffer->size());
+}
+
+void MPEG2TSWriter::writeProgramMap() {
+    // 0x47
+    // transport_error_indicator = b0
+    // payload_unit_start_indicator = b1
+    // transport_priority = b0
+    // PID = b0 0001 1110 0000 (13 bits) [0x1e0]
+    // transport_scrambling_control = b00
+    // adaptation_field_control = b01 (no adaptation field, payload only)
+    // continuity_counter = b????
+    // skip = 0x00
+    // -- payload follows
+    // table_id = 0x02
+    // section_syntax_indicator = b1
+    // must_be_zero = b0
+    // reserved = b11
+    // section_length = 0x???
+    // program_number = 0x0001
+    // reserved = b11
+    // version_number = b00001
+    // current_next_indicator = b1
+    // section_number = 0x00
+    // last_section_number = 0x00
+    // reserved = b111
+    // PCR_PID = b? ???? ???? ???? (13 bits)
+    // reserved = b1111
+    // program_info_length = 0x000
+    //   one or more elementary stream descriptions follow:
+    //   stream_type = 0x??
+    //   reserved = b111
+    //   elementary_PID = b? ???? ???? ???? (13 bits)
+    //   reserved = b1111
+    //   ES_info_length = 0x000
+    // CRC = 0x????????
+
+    static const uint8_t kData[] = {
+        0x47,
+        0x41, 0xe0, 0x10, 0x00,  // b0100 0001 1110 0000 0001 ???? 0000 0000
+        0x02, 0xb0, 0x00, 0x00,  // b0000 0010 1011 ???? ???? ???? 0000 0000
+        0x01, 0xc3, 0x00, 0x00,  // b0000 0001 1100 0011 0000 0000 0000 0000
+        0xe0, 0x00, 0xf0, 0x00   // b111? ???? ???? ???? 1111 0000 0000 0000
+    };
+
+    sp<ABuffer> buffer = new ABuffer(188);
+    memset(buffer->data(), 0, buffer->size());
+    memcpy(buffer->data(), kData, sizeof(kData));
+
+    static const unsigned kContinuityCounter = 5;
+    buffer->data()[3] |= kContinuityCounter;
+
+    size_t section_length = 5 * mSources.size() + 4 + 9;
+    buffer->data()[6] |= section_length >> 8;
+    buffer->data()[7] = section_length & 0xff;
+
+    static const unsigned kPCR_PID = 0x1e1;
+    buffer->data()[13] |= (kPCR_PID >> 8) & 0x1f;
+    buffer->data()[14] = kPCR_PID & 0xff;
+
+    uint8_t *ptr = &buffer->data()[sizeof(kData)];
+    for (size_t i = 0; i < mSources.size(); ++i) {
+        *ptr++ = mSources.editItemAt(i)->streamType();
+
+        const unsigned ES_PID = 0x1e0 + i + 1;
+        *ptr++ = 0xe0 | (ES_PID >> 8);
+        *ptr++ = ES_PID & 0xff;
+        *ptr++ = 0xf0;
+        *ptr++ = 0x00;
+    }
+
+    *ptr++ = 0x00;
+    *ptr++ = 0x00;
+    *ptr++ = 0x00;
+    *ptr++ = 0x00;
+
+    CHECK_EQ(fwrite(buffer->data(), 1, buffer->size(), mFile), buffer->size());
+}
+
+void MPEG2TSWriter::writeAccessUnit(
+        int32_t sourceIndex, const sp<ABuffer> &accessUnit) {
+    // 0x47
+    // transport_error_indicator = b0
+    // payload_unit_start_indicator = b1
+    // transport_priority = b0
+    // PID = b0 0001 1110 ???? (13 bits) [0x1e0 + 1 + sourceIndex]
+    // transport_scrambling_control = b00
+    // adaptation_field_control = b01 (no adaptation field, payload only)
+    // continuity_counter = b????
+    // -- payload follows
+    // packet_startcode_prefix = 0x000001
+    // stream_id = 0x?? (0xe0 for avc video, 0xc0 for aac audio)
+    // PES_packet_length = 0x????
+    // reserved = b10
+    // PES_scrambling_control = b00
+    // PES_priority = b0
+    // data_alignment_indicator = b1
+    // copyright = b0
+    // original_or_copy = b0
+    // PTS_DTS_flags = b10  (PTS only)
+    // ESCR_flag = b0
+    // ES_rate_flag = b0
+    // DSM_trick_mode_flag = b0
+    // additional_copy_info_flag = b0
+    // PES_CRC_flag = b0
+    // PES_extension_flag = b0
+    // PES_header_data_length = 0x05
+    // reserved = b0010 (PTS)
+    // PTS[32..30] = b???
+    // reserved = b1
+    // PTS[29..15] = b??? ???? ???? ???? (15 bits)
+    // reserved = b1
+    // PTS[14..0] = b??? ???? ???? ???? (15 bits)
+    // reserved = b1
+    // the first fragment of "buffer" follows
+
+    sp<ABuffer> buffer = new ABuffer(188);
+    memset(buffer->data(), 0, buffer->size());
+
+    const unsigned PID = 0x1e0 + sourceIndex + 1;
+
+    const unsigned continuity_counter =
+        mSources.editItemAt(sourceIndex)->incrementContinuityCounter();
+
+    // XXX if there are multiple streams of a kind (more than 1 audio or
+    // more than 1 video) they need distinct stream_ids.
+    const unsigned stream_id =
+        mSources.editItemAt(sourceIndex)->streamType() == 0x0f ? 0xc0 : 0xe0;
+
+    int64_t timeUs;
+    CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
+
+    uint32_t PTS = (timeUs * 9ll) / 100ll;
+
+    size_t PES_packet_length = accessUnit->size() + 8;
+
+    uint8_t *ptr = buffer->data();
+    *ptr++ = 0x47;
+    *ptr++ = 0x40 | (PID >> 8);
+    *ptr++ = PID & 0xff;
+    *ptr++ = 0x10 | continuity_counter;
+    *ptr++ = 0x00;
+    *ptr++ = 0x00;
+    *ptr++ = 0x01;
+    *ptr++ = stream_id;
+    *ptr++ = PES_packet_length >> 8;
+    *ptr++ = PES_packet_length & 0xff;
+    *ptr++ = 0x84;
+    *ptr++ = 0x80;
+    *ptr++ = 0x05;
+    *ptr++ = 0x20 | (((PTS >> 30) & 7) << 1) | 1;
+    *ptr++ = (PTS >> 22) & 0xff;
+    *ptr++ = (((PTS >> 15) & 0x7f) << 1) | 1;
+    *ptr++ = (PTS >> 7) & 0xff;
+    *ptr++ = ((PTS & 0x7f) << 1) | 1;
+
+    size_t sizeLeft = buffer->data() + buffer->size() - ptr;
+    size_t copy = accessUnit->size();
+    if (copy > sizeLeft) {
+        copy = sizeLeft;
+    }
+
+    memcpy(ptr, accessUnit->data(), copy);
+
+    CHECK_EQ(fwrite(buffer->data(), 1, buffer->size(), mFile), buffer->size());
+
+    size_t offset = copy;
+    while (offset < accessUnit->size()) {
+        // for subsequent fragments of "buffer":
+        // 0x47
+        // transport_error_indicator = b0
+        // payload_unit_start_indicator = b0
+        // transport_priority = b0
+        // PID = b0 0001 1110 ???? (13 bits) [0x1e0 + 1 + sourceIndex]
+        // transport_scrambling_control = b00
+        // adaptation_field_control = b01 (no adaptation field, payload only)
+        // continuity_counter = b????
+        // the fragment of "buffer" follows.
+
+        memset(buffer->data(), 0, buffer->size());
+
+        const unsigned continuity_counter =
+            mSources.editItemAt(sourceIndex)->incrementContinuityCounter();
+
+        ptr = buffer->data();
+        *ptr++ = 0x47;
+        *ptr++ = 0x00 | (PID >> 8);
+        *ptr++ = PID & 0xff;
+        *ptr++ = 0x10 | continuity_counter;
+
+        size_t sizeLeft = buffer->data() + buffer->size() - ptr;
+        size_t copy = accessUnit->size() - offset;
+        if (copy > sizeLeft) {
+            copy = sizeLeft;
+        }
+
+        memcpy(ptr, accessUnit->data() + offset, copy);
+        CHECK_EQ(fwrite(buffer->data(), 1, buffer->size(), mFile),
+                 buffer->size());
+
+        offset += copy;
+    }
+}
+
+void MPEG2TSWriter::writeTS() {
+    if (mNumTSPacketsWritten >= mNumTSPacketsBeforeMeta) {
+        writeProgramAssociationTable();
+        writeProgramMap();
+
+        mNumTSPacketsBeforeMeta = mNumTSPacketsWritten + 2500;
+    }
+}
+
+}  // namespace android
+
diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
index 7a8cf32..43938b2 100644
--- a/media/libstagefright/OggExtractor.cpp
+++ b/media/libstagefright/OggExtractor.cpp
@@ -93,7 +93,10 @@
     sp<DataSource> mSource;
     off_t mOffset;
     Page mCurrentPage;
+    uint64_t mPrevGranulePosition;
     size_t mCurrentPageSize;
+    bool mFirstPacketInPage;
+    uint64_t mCurrentPageSamples;
     size_t mNextLaceIndex;
 
     off_t mFirstDataOffset;
@@ -113,6 +116,8 @@
     void parseFileMetaData();
     void extractAlbumArt(const void *data, size_t size);
 
+    uint64_t findPrevGranulePosition(off_t pageOffset);
+
     MyVorbisExtractor(const MyVorbisExtractor &);
     MyVorbisExtractor &operator=(const MyVorbisExtractor &);
 };
@@ -193,7 +198,10 @@
 MyVorbisExtractor::MyVorbisExtractor(const sp<DataSource> &source)
     : mSource(source),
       mOffset(0),
+      mPrevGranulePosition(0),
       mCurrentPageSize(0),
+      mFirstPacketInPage(true),
+      mCurrentPageSamples(0),
       mNextLaceIndex(0),
       mFirstDataOffset(-1) {
     mCurrentPage.mNumSegments = 0;
@@ -238,6 +246,52 @@
     }
 }
 
+// Given the offset of the "current" page, find the page immediately preceding
+// it (if any) and return its granule position.
+// To do this we back up from the "current" page's offset until we find any
+// page preceding it and then scan forward to just before the current page.
+uint64_t MyVorbisExtractor::findPrevGranulePosition(off_t pageOffset) {
+    off_t prevPageOffset = 0;
+    off_t prevGuess = pageOffset;
+    for (;;) {
+        if (prevGuess >= 5000) {
+            prevGuess -= 5000;
+        } else {
+            prevGuess = 0;
+        }
+
+        LOGV("backing up %ld bytes", pageOffset - prevGuess);
+
+        CHECK_EQ(findNextPage(prevGuess, &prevPageOffset), (status_t)OK);
+
+        if (prevPageOffset < pageOffset || prevGuess == 0) {
+            break;
+        }
+    }
+
+    if (prevPageOffset == pageOffset) {
+        // We did not find a page preceding this one.
+        return 0;
+    }
+
+    LOGV("prevPageOffset at %ld, pageOffset at %ld", prevPageOffset, pageOffset);
+
+    for (;;) {
+        Page prevPage;
+        ssize_t n = readPage(prevPageOffset, &prevPage);
+
+        if (n <= 0) {
+            return 0;
+        }
+
+        prevPageOffset += n;
+
+        if (prevPageOffset == pageOffset) {
+            return prevPage.mGranulePosition;
+        }
+    }
+}
+
 status_t MyVorbisExtractor::seekToOffset(off_t offset) {
     if (mFirstDataOffset >= 0 && offset < mFirstDataOffset) {
         // Once we know where the actual audio data starts (past the headers)
@@ -252,9 +306,16 @@
         return err;
     }
 
+    // We found the page we wanted to seek to, but we'll also need
+    // the page preceding it to determine how many valid samples are on
+    // this page.
+    mPrevGranulePosition = findPrevGranulePosition(pageOffset);
+
     mOffset = pageOffset;
 
     mCurrentPageSize = 0;
+    mFirstPacketInPage = true;
+    mCurrentPageSamples = 0;
     mCurrentPage.mNumSegments = 0;
     mNextLaceIndex = 0;
 
@@ -399,6 +460,12 @@
                     buffer->meta_data()->setInt64(kKeyTime, timeUs);
                 }
 
+                if (mFirstPacketInPage) {
+                    buffer->meta_data()->setInt32(
+                            kKeyValidSamples, mCurrentPageSamples);
+                    mFirstPacketInPage = false;
+                }
+
                 *out = buffer;
 
                 return OK;
@@ -423,6 +490,12 @@
             return n < 0 ? n : (status_t)ERROR_END_OF_STREAM;
         }
 
+        mCurrentPageSamples =
+            mCurrentPage.mGranulePosition - mPrevGranulePosition;
+        mFirstPacketInPage = true;
+
+        mPrevGranulePosition = mCurrentPage.mGranulePosition;
+
         mCurrentPageSize = n;
         mNextLaceIndex = 0;
 
@@ -435,6 +508,10 @@
                     buffer->meta_data()->setInt64(kKeyTime, timeUs);
                 }
 
+                buffer->meta_data()->setInt32(
+                        kKeyValidSamples, mCurrentPageSamples);
+                mFirstPacketInPage = false;
+
                 *out = buffer;
 
                 return OK;
diff --git a/media/libstagefright/codecs/aacdec/AACDecoder.cpp b/media/libstagefright/codecs/aacdec/AACDecoder.cpp
index e4ed5e6..f58c16d 100644
--- a/media/libstagefright/codecs/aacdec/AACDecoder.cpp
+++ b/media/libstagefright/codecs/aacdec/AACDecoder.cpp
@@ -171,6 +171,10 @@
             mInputBuffer->release();
             mInputBuffer = NULL;
         }
+
+        // Make sure that the next buffer output does not still
+        // depend on fragments from the last one decoded.
+        PVMP4AudioDecoderResetBuffer(mDecoderBuf);
     } else {
         seekTimeUs = -1;
     }
diff --git a/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp b/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp
index c4a8280..59dd740 100644
--- a/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp
+++ b/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp
@@ -132,6 +132,10 @@
             mInputBuffer->release();
             mInputBuffer = NULL;
         }
+
+        // Make sure that the next buffer output does not still
+        // depend on fragments from the last one decoded.
+        pvmp3_InitDecoder(mConfig, mDecoderBuf);
     } else {
         seekTimeUs = -1;
     }
diff --git a/media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp b/media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp
index 53f0638..703b41e 100644
--- a/media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp
+++ b/media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+//#define LOG_NDEBUG 0
+#define LOG_TAG "VorbisDecoder"
+#include <utils/Log.h>
+
 #include "VorbisDecoder.h"
 
 #include <media/stagefright/MediaBufferGroup.h>
@@ -108,6 +112,7 @@
 
     mAnchorTimeUs = 0;
     mNumFramesOutput = 0;
+    mNumFramesLeftOnPage = 0;
     mStarted = true;
 
     return OK;
@@ -188,6 +193,13 @@
         }
     }
 
+    if (numFrames > mNumFramesLeftOnPage) {
+        LOGV("discarding %d frames at end of page",
+             numFrames - mNumFramesLeftOnPage);
+        numFrames = mNumFramesLeftOnPage;
+    }
+    mNumFramesLeftOnPage -= numFrames;
+
     out->set_range(0, numFrames * sizeof(int16_t) * mNumChannels);
 
     return numFrames;
@@ -226,6 +238,12 @@
         CHECK(seekTimeUs < 0);
     }
 
+    int32_t numPageSamples;
+    if (inputBuffer->meta_data()->findInt32(
+                kKeyValidSamples, &numPageSamples)) {
+        mNumFramesLeftOnPage = numPageSamples;
+    }
+
     MediaBuffer *outputBuffer;
     CHECK_EQ(mBufferGroup->acquire_buffer(&outputBuffer), OK);
 
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 1f3946c..600faca 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -92,6 +92,9 @@
     // This is a mask of MediaExtractor::Flags.
     uint32_t flags() const;
 
+    void postAudioEOS();
+    void postAudioSeekComplete();
+
 private:
     friend struct AwesomeEvent;
 
diff --git a/media/libstagefright/include/VorbisDecoder.h b/media/libstagefright/include/VorbisDecoder.h
index e9a488a..13e8b77 100644
--- a/media/libstagefright/include/VorbisDecoder.h
+++ b/media/libstagefright/include/VorbisDecoder.h
@@ -55,6 +55,7 @@
     int32_t mSampleRate;
     int64_t mAnchorTimeUs;
     int64_t mNumFramesOutput;
+    int32_t mNumFramesLeftOnPage;
 
     vorbis_dsp_state *mState;
     vorbis_info *mVi;
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index 9952783..47cca80 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -389,20 +389,23 @@
 
         // ES data follows.
 
-        onPayloadData(
-                PTS_DTS_flags, PTS, DTS,
-                br->data(), br->numBitsLeft() / 8);
-
         if (PES_packet_length != 0) {
             CHECK_GE(PES_packet_length, PES_header_data_length + 3);
 
             unsigned dataLength =
                 PES_packet_length - 3 - PES_header_data_length;
 
-            CHECK_EQ(br->numBitsLeft(), dataLength * 8);
+            CHECK_GE(br->numBitsLeft(), dataLength * 8);
+
+            onPayloadData(
+                    PTS_DTS_flags, PTS, DTS, br->data(), dataLength);
 
             br->skipBits(dataLength * 8);
         } else {
+            onPayloadData(
+                    PTS_DTS_flags, PTS, DTS,
+                    br->data(), br->numBitsLeft() / 8);
+
             size_t payloadSizeBits = br->numBitsLeft();
             CHECK((payloadSizeBits % 8) == 0);
 
@@ -491,7 +494,7 @@
     CHECK(picParamSet != NULL);
 
     buffer->setRange(stopOffset, size - stopOffset);
-    LOGI("buffer has %d bytes left.", buffer->size());
+    LOGV("buffer has %d bytes left.", buffer->size());
 
     size_t csdSize =
         1 + 3 + 1 + 1
@@ -527,6 +530,8 @@
     const uint8_t *data = *_data;
     size_t size = *_size;
 
+    // hexdump(data, size);
+
     *nalStart = NULL;
     *nalSize = 0;
 
@@ -572,18 +577,23 @@
         ++offset;
     }
 
-    CHECK_LT(offset + 2, size);
-
     *nalStart = &data[startOffset];
     *nalSize = endOffset - startOffset;
 
-    *_data = &data[offset];
-    *_size = size - offset;
+    if (offset + 2 < size) {
+        *_data = &data[offset];
+        *_size = size - offset;
+    } else {
+        *_data = NULL;
+        *_size = 0;
+    }
 
     return true;
 }
 
 sp<ABuffer> MakeCleanAVCData(const uint8_t *data, size_t size) {
+    // hexdump(data, size);
+
     const uint8_t *tmpData = data;
     size_t tmpSize = size;
 
@@ -591,6 +601,7 @@
     const uint8_t *nalStart;
     size_t nalSize;
     while (getNextNALUnit(&tmpData, &tmpSize, &nalStart, &nalSize)) {
+        // hexdump(nalStart, nalSize);
         totalSize += 4 + nalSize;
     }
 
@@ -615,15 +626,15 @@
     CHECK_EQ(br.getBits(2), 0u);
     br.getBits(1);  // protection_absent
     unsigned profile = br.getBits(2);
-    LOGI("profile = %u", profile);
+    LOGV("profile = %u", profile);
     CHECK_NE(profile, 3u);
     unsigned sampling_freq_index = br.getBits(4);
     br.getBits(1);  // private_bit
     unsigned channel_configuration = br.getBits(3);
     CHECK_NE(channel_configuration, 0u);
 
-    LOGI("sampling_freq_index = %u", sampling_freq_index);
-    LOGI("channel_configuration = %u", channel_configuration);
+    LOGV("sampling_freq_index = %u", sampling_freq_index);
+    LOGV("channel_configuration = %u", channel_configuration);
 
     CHECK_LE(sampling_freq_index, 11u);
     static const int32_t kSamplingFreq[] = {
@@ -707,8 +718,8 @@
             sp<ABuffer> csd =
                 FindMPEG2ADTSConfig(buffer, &sampleRate, &channelCount);
 
-            LOGI("sampleRate = %d", sampleRate);
-            LOGI("channelCount = %d", channelCount);
+            LOGV("sampleRate = %d", sampleRate);
+            LOGV("channelCount = %d", channelCount);
 
             meta->setInt32(kKeySampleRate, sampleRate);
             meta->setInt32(kKeyChannelCount, channelCount);
@@ -716,7 +727,7 @@
             meta->setData(kKeyESDS, 0, csd->data(), csd->size());
         }
 
-        LOGI("created source!");
+        LOGV("created source!");
         mSource = new AnotherPacketSource(meta);
 
         // fall through
@@ -915,7 +926,10 @@
     unsigned adaptation_field_control = br->getBits(2);
     LOGV("adaptation_field_control = %u", adaptation_field_control);
 
-    MY_LOGV("continuity_counter = %u", br->getBits(4));
+    unsigned continuity_counter = br->getBits(4);
+    LOGV("continuity_counter = %u", continuity_counter);
+
+    // LOGI("PID = 0x%04x, continuity_counter = %u", PID, continuity_counter);
 
     if (adaptation_field_control == 2 || adaptation_field_control == 3) {
         parseAdaptationField(br);
diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
index 56ca375..2417305 100644
--- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
@@ -32,6 +32,8 @@
 
 namespace android {
 
+static const size_t kTSPacketSize = 188;
+
 struct MPEG2TSSource : public MediaSource {
     MPEG2TSSource(
             const sp<MPEG2TSExtractor> &extractor,
@@ -126,27 +128,37 @@
 void MPEG2TSExtractor::init() {
     bool haveAudio = false;
     bool haveVideo = false;
+    int numPacketsParsed = 0;
 
     while (feedMore() == OK) {
         ATSParser::SourceType type;
         if (haveAudio && haveVideo) {
             break;
         }
-        if (haveVideo) {
-            type = ATSParser::MPEG2ADTS_AUDIO;
-        } else {
-            type = ATSParser::AVC_VIDEO;
-        }
-        sp<AnotherPacketSource> impl =
-            (AnotherPacketSource *)mParser->getSource(type).get();
+        if (!haveVideo) {
+            sp<AnotherPacketSource> impl =
+                (AnotherPacketSource *)mParser->getSource(
+                        ATSParser::AVC_VIDEO).get();
 
-        if (impl != NULL) {
-            if (type == ATSParser::MPEG2ADTS_AUDIO) {
-                haveAudio = true;
-            } else {
+            if (impl != NULL) {
                 haveVideo = true;
+                mSourceImpls.push(impl);
             }
-            mSourceImpls.push(impl);
+        }
+
+        if (!haveAudio) {
+            sp<AnotherPacketSource> impl =
+                (AnotherPacketSource *)mParser->getSource(
+                        ATSParser::MPEG2ADTS_AUDIO).get();
+
+            if (impl != NULL) {
+                haveAudio = true;
+                mSourceImpls.push(impl);
+            }
+        }
+
+        if (++numPacketsParsed > 1500) {
+            break;
         }
     }
 
@@ -156,8 +168,6 @@
 status_t MPEG2TSExtractor::feedMore() {
     Mutex::Autolock autoLock(mLock);
 
-    static const size_t kTSPacketSize = 188;
-
     uint8_t packet[kTSPacketSize];
     ssize_t n = mDataSource->readAt(mOffset, packet, kTSPacketSize);
 
@@ -176,23 +186,18 @@
 bool SniffMPEG2TS(
         const sp<DataSource> &source, String8 *mimeType, float *confidence,
         sp<AMessage> *) {
-#if 0
-    char header;
-    if (source->readAt(0, &header, 1) != 1 || header != 0x47) {
-        return false;
+    for (int i = 0; i < 5; ++i) {
+        char header;
+        if (source->readAt(kTSPacketSize * i, &header, 1) != 1
+                || header != 0x47) {
+            return false;
+        }
     }
 
-    *confidence = 0.05f;
+    *confidence = 0.1f;
     mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
 
     return true;
-#else
-    // For now we're going to never identify this type of stream, since we'd
-    // just base our decision on a single byte...
-    // Instead you can instantiate an MPEG2TSExtractor by explicitly stating
-    // its proper mime type in the call to MediaExtractor::Create(...).
-    return false;
-#endif
 }
 
 }  // namespace android
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 8a732ed..97b8086 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -5332,6 +5332,15 @@
         }
     }
 
+    // Release effect engine here so that it is done immediately. Otherwise it will be released
+    // by the destructor when the last strong reference on the this object is released which can
+    // happen after next process is called on this effect.
+    if (size == 0 && mEffectInterface != NULL) {
+        // release effect engine
+        EffectRelease(mEffectInterface);
+        mEffectInterface = NULL;
+    }
+
     return size;
 }
 
@@ -6145,21 +6154,36 @@
 // Must be called with EffectChain::mLock locked
 void AudioFlinger::EffectChain::process_l()
 {
+    sp<ThreadBase> thread = mThread.promote();
+    if (thread == 0) {
+        LOGW("process_l(): cannot promote mixer thread");
+        return;
+    }
+    PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
+    bool isGlobalSession = (mSessionId == AudioSystem::SESSION_OUTPUT_MIX) ||
+            (mSessionId == AudioSystem::SESSION_OUTPUT_STAGE);
+    bool tracksOnSession = false;
+    if (!isGlobalSession) {
+        tracksOnSession =
+                playbackThread->hasAudioSession(mSessionId) & PlaybackThread::TRACK_SESSION;
+    }
+
     size_t size = mEffects.size();
-    for (size_t i = 0; i < size; i++) {
-        mEffects[i]->process();
+    // do not process effect if no track is present in same audio session
+    if (isGlobalSession || tracksOnSession) {
+        for (size_t i = 0; i < size; i++) {
+            mEffects[i]->process();
+        }
     }
     for (size_t i = 0; i < size; i++) {
         mEffects[i]->updateState();
     }
     // if no track is active, input buffer must be cleared here as the mixer process
     // will not do it
-    if (mSessionId > 0 && activeTracks() == 0) {
-        sp<ThreadBase> thread = mThread.promote();
-        if (thread != 0) {
-            size_t numSamples = thread->frameCount() * thread->channelCount();
-            memset(mInBuffer, 0, numSamples * sizeof(int16_t));
-        }
+    if (tracksOnSession &&
+        activeTracks() == 0) {
+        size_t numSamples = playbackThread->frameCount() * playbackThread->channelCount();
+        memset(mInBuffer, 0, numSamples * sizeof(int16_t));
     }
 }