Merge "FINAL ATTEMPT: HTTP services are now provided from JAVA and made available to media code"
diff --git a/include/media/EffectsFactoryApi.h b/include/media/EffectsFactoryApi.h
index b1143b9..b1ed7b0 100644
--- a/include/media/EffectsFactoryApi.h
+++ b/include/media/EffectsFactoryApi.h
@@ -171,30 +171,6 @@
 ////////////////////////////////////////////////////////////////////////////////
 int EffectIsNullUuid(const effect_uuid_t *pEffectUuid);
 
-////////////////////////////////////////////////////////////////////////////////
-//
-//    Function:       EffectGetSubEffects
-//
-//    Description:    Returns the descriptors of the sub effects of the effect
-//                    whose uuid is pointed to by first argument.
-//
-//    Input:
-//          pEffectUuid:    pointer to the effect uuid.
-//          size:           size of the buffer pointed by pDescriptor.
-//
-//    Input/Output:
-//          pDescriptor:    address where to return the sub effect descriptors.
-//
-//    Output:
-//        returned value:    0          successful operation.
-//                          -ENODEV     factory failed to initialize
-//                          -EINVAL     invalid pEffectUuid or pDescriptor
-//                          -ENOENT     no effect with this uuid found
-//        *pDescriptor:     updated with the sub effect descriptors.
-//
-////////////////////////////////////////////////////////////////////////////////
-int EffectGetSubEffects(const effect_uuid_t *pEffectUuid, effect_descriptor_t *pDescriptors, size_t size);
-
 #if __cplusplus
 }  // extern "C"
 #endif
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index 9c8451c..6643736 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -142,6 +142,7 @@
     enum InternalOptionType {
         INTERNAL_OPTION_SUSPEND,  // data is a bool
         INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY,  // data is an int64_t
+        INTERNAL_OPTION_MAX_TIMESTAMP_GAP, // data is int64_t
     };
     virtual status_t setInternalOption(
             node_id node,
diff --git a/include/media/nbaio/AudioBufferProviderSource.h b/include/media/nbaio/AudioBufferProviderSource.h
index 2c4aaff..b16e20a 100644
--- a/include/media/nbaio/AudioBufferProviderSource.h
+++ b/include/media/nbaio/AudioBufferProviderSource.h
@@ -27,7 +27,7 @@
 class AudioBufferProviderSource : public NBAIO_Source {
 
 public:
-    AudioBufferProviderSource(AudioBufferProvider *provider, NBAIO_Format format);
+    AudioBufferProviderSource(AudioBufferProvider *provider, const NBAIO_Format& format);
     virtual ~AudioBufferProviderSource();
 
     // NBAIO_Port interface
diff --git a/include/media/nbaio/MonoPipe.h b/include/media/nbaio/MonoPipe.h
index d3802fe..b09b35f 100644
--- a/include/media/nbaio/MonoPipe.h
+++ b/include/media/nbaio/MonoPipe.h
@@ -41,7 +41,7 @@
     // Note: whatever shares this object with another thread needs to do so in an SMP-safe way (like
     // creating it the object before creating the other thread, or storing the object with a
     // release_store). Otherwise the other thread could see a partially-constructed object.
-    MonoPipe(size_t reqFrames, NBAIO_Format format, bool writeCanBlock = false);
+    MonoPipe(size_t reqFrames, const NBAIO_Format& format, bool writeCanBlock = false);
     virtual ~MonoPipe();
 
     // NBAIO_Port interface
diff --git a/include/media/nbaio/NBAIO.h b/include/media/nbaio/NBAIO.h
index 1da0c73..9c9721a 100644
--- a/include/media/nbaio/NBAIO.h
+++ b/include/media/nbaio/NBAIO.h
@@ -53,24 +53,23 @@
 // too large, then this decision should be re-visited.
 // Sample rate and channel count are explicit, PCM interleaved 16-bit is assumed.
 typedef unsigned NBAIO_Format;
-enum {
-    Format_Invalid
-};
+
+extern const NBAIO_Format Format_Invalid;
 
 // Return the frame size of an NBAIO_Format in bytes
-size_t Format_frameSize(NBAIO_Format format);
+size_t Format_frameSize(const NBAIO_Format& format);
 
 // Return the frame size of an NBAIO_Format as a bit shift
-size_t Format_frameBitShift(NBAIO_Format format);
+size_t Format_frameBitShift(const NBAIO_Format& format);
 
 // Convert a sample rate in Hz and channel count to an NBAIO_Format
 NBAIO_Format Format_from_SR_C(unsigned sampleRate, unsigned channelCount);
 
 // Return the sample rate in Hz of an NBAIO_Format
-unsigned Format_sampleRate(NBAIO_Format format);
+unsigned Format_sampleRate(const NBAIO_Format& format);
 
 // Return the channel count of an NBAIO_Format
-unsigned Format_channelCount(NBAIO_Format format);
+unsigned Format_channelCount(const NBAIO_Format& format);
 
 // Callbacks used by NBAIO_Sink::writeVia() and NBAIO_Source::readVia() below.
 typedef ssize_t (*writeVia_t)(void *user, void *buffer, size_t count);
@@ -115,8 +114,8 @@
     virtual NBAIO_Format format() const { return mNegotiated ? mFormat : Format_Invalid; }
 
 protected:
-    NBAIO_Port(NBAIO_Format format) : mNegotiated(false), mFormat(format),
-                                      mBitShift(Format_frameBitShift(format)) { }
+    NBAIO_Port(const NBAIO_Format& format) : mNegotiated(false), mFormat(format),
+                                             mBitShift(Format_frameBitShift(format)) { }
     virtual ~NBAIO_Port() { }
 
     // Implementations are free to ignore these if they don't need them
@@ -220,7 +219,7 @@
     virtual status_t getTimestamp(AudioTimestamp& timestamp) { return INVALID_OPERATION; }
 
 protected:
-    NBAIO_Sink(NBAIO_Format format = Format_Invalid) : NBAIO_Port(format), mFramesWritten(0) { }
+    NBAIO_Sink(const NBAIO_Format& format = Format_Invalid) : NBAIO_Port(format), mFramesWritten(0) { }
     virtual ~NBAIO_Sink() { }
 
     // Implementations are free to ignore these if they don't need them
@@ -311,7 +310,7 @@
     virtual void    onTimestamp(const AudioTimestamp& timestamp) { }
 
 protected:
-    NBAIO_Source(NBAIO_Format format = Format_Invalid) : NBAIO_Port(format), mFramesRead(0) { }
+    NBAIO_Source(const NBAIO_Format& format = Format_Invalid) : NBAIO_Port(format), mFramesRead(0) { }
     virtual ~NBAIO_Source() { }
 
     // Implementations are free to ignore these if they don't need them
diff --git a/include/media/nbaio/Pipe.h b/include/media/nbaio/Pipe.h
index 79a4eee..c784129 100644
--- a/include/media/nbaio/Pipe.h
+++ b/include/media/nbaio/Pipe.h
@@ -30,7 +30,7 @@
 
 public:
     // maxFrames will be rounded up to a power of 2, and all slots are available. Must be >= 2.
-    Pipe(size_t maxFrames, NBAIO_Format format);
+    Pipe(size_t maxFrames, const NBAIO_Format& format);
     virtual ~Pipe();
 
     // NBAIO_Port interface
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index f1636e6..7ba5acc 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -67,6 +67,8 @@
 
     void signalRequestIDRFrame();
 
+    bool isConfiguredForAdaptivePlayback() { return mIsConfiguredForAdaptivePlayback; }
+
     struct PortDescription : public RefBase {
         size_t countBuffers();
         IOMX::buffer_id bufferIDAt(size_t index) const;
@@ -187,6 +189,7 @@
     bool mIsEncoder;
     bool mUseMetadataOnEncoderOutput;
     bool mShutdownInProgress;
+    bool mIsConfiguredForAdaptivePlayback;
 
     // If "mKeepComponentAllocated" we only transition back to Loaded state
     // and do not release the component instance.
@@ -202,6 +205,7 @@
     int32_t mMetaDataBuffersToSubmit;
 
     int64_t mRepeatFrameDelayUs;
+    int64_t mMaxPtsGapUs;
 
     status_t setCyclicIntraMacroblockRefresh(const sp<AMessage> &msg, int32_t mode);
     status_t allocateBuffersOnPort(OMX_U32 portIndex);
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index b5a4c0b..3901e79 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -65,7 +65,9 @@
 struct AudioTrackSharedStatic {
     StaticAudioTrackSingleStateQueue::Shared
                     mSingleStateQueue;
-    size_t          mBufferPosition;    // updated asynchronously by server,
+    // This field should be a size_t, but since it is located in shared memory we
+    // force to 32-bit.  The client and server may have different typedefs for size_t.
+    uint32_t        mBufferPosition;    // updated asynchronously by server,
                                         // "for entertainment purposes only"
 };
 
@@ -104,7 +106,9 @@
 
 private:
 
-                size_t      mMinimum;       // server wakes up client if available >= mMinimum
+                // This field should be a size_t, but since it is located in shared memory we
+                // force to 32-bit.  The client and server may have different typedefs for size_t.
+                uint32_t    mMinimum;       // server wakes up client if available >= mMinimum
 
                 // Channel volumes are fixed point U4.12, so 0x1000 means 1.0.
                 // Left channel is in [0:15], right channel is in [16:31].
@@ -241,7 +245,11 @@
     }
 
     void        setMinimum(size_t minimum) {
-        mCblk->mMinimum = minimum;
+        // This can only happen on a 64-bit client
+        if (minimum > UINT32_MAX) {
+            minimum = UINT32_MAX;
+        }
+        mCblk->mMinimum = (uint32_t) minimum;
     }
 
     // Return the number of frames that would need to be obtained and released
diff --git a/include/private/media/StaticAudioTrackState.h b/include/private/media/StaticAudioTrackState.h
index 46a5946..d483061 100644
--- a/include/private/media/StaticAudioTrackState.h
+++ b/include/private/media/StaticAudioTrackState.h
@@ -25,9 +25,13 @@
 // state is wrapped by a SingleStateQueue.
 struct StaticAudioTrackState {
     // do not define constructors, destructors, or virtual methods
-    size_t  mLoopStart;
-    size_t  mLoopEnd;
-    int     mLoopCount;
+
+    // These fields should both be size_t, but since they are located in shared memory we
+    // force to 32-bit.  The client and server may have different typedefs for size_t.
+    uint32_t    mLoopStart;
+    uint32_t    mLoopEnd;
+
+    int         mLoopCount;
 };
 
 }   // namespace android
diff --git a/media/libeffects/factory/EffectsFactory.c b/media/libeffects/factory/EffectsFactory.c
index f8d6041..6d30d64 100644
--- a/media/libeffects/factory/EffectsFactory.c
+++ b/media/libeffects/factory/EffectsFactory.c
@@ -368,27 +368,21 @@
     }
     if (e1 == NULL) {
         ret = -ENOENT;
-        pthread_mutex_unlock(&gLibLock);
         goto exit;
     }
 
     // release effect in library
     if (fx->lib == NULL) {
         ALOGW("EffectRelease() fx %p library already unloaded", handle);
-        pthread_mutex_unlock(&gLibLock);
     } else {
         pthread_mutex_lock(&fx->lib->lock);
-        // Releasing the gLibLock here as the list access is over as the
-        // effect is removed from the list.
-        // If the gLibLock is not released, we will have a deadlock situation
-        // since we call the sub effect release inside the EffectRelease of Proxy
-        pthread_mutex_unlock(&gLibLock);
         fx->lib->desc->release_effect(fx->subItfe);
         pthread_mutex_unlock(&fx->lib->lock);
     }
     free(fx);
 
 exit:
+    pthread_mutex_unlock(&gLibLock);
     return ret;
 }
 
@@ -404,8 +398,8 @@
 // is pointed by the first argument. It searches the gSubEffectList for the
 // matching uuid and then copies the corresponding sub effect descriptors
 // to the inout param
-int EffectGetSubEffects(const effect_uuid_t *uuid,
-                        effect_descriptor_t *pDescriptors, size_t size)
+int EffectGetSubEffects(const effect_uuid_t *uuid, sub_effect_entry_t **pSube,
+                        size_t size)
 {
    ALOGV("EffectGetSubEffects() UUID: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X"
           "%02X\n",uuid->timeLow, uuid->timeMid, uuid->timeHiAndVersion,
@@ -413,8 +407,7 @@
           uuid->node[3],uuid->node[4],uuid->node[5]);
 
    // Check if the size of the desc buffer is large enough for 2 subeffects
-   if ((uuid == NULL) || (pDescriptors == NULL) ||
-       (size < 2*sizeof(effect_descriptor_t))) {
+   if ((uuid == NULL) || (pSube == NULL) || (size < 2)) {
        ALOGW("NULL pointer or insufficient memory. Cannot query subeffects");
        return -EINVAL;
    }
@@ -432,11 +425,10 @@
            list_elem_t *subefx = e->sub_elem;
            while (subefx != NULL) {
                subeffect = (sub_effect_entry_t*)subefx->object;
-               d = (effect_descriptor_t*)(subeffect->object);
-               pDescriptors[count++] = *d;
+               pSube[count++] = subeffect;
                subefx = subefx->next;
            }
-           ALOGV("EffectGetSubEffects end - copied the sub effect descriptors");
+           ALOGV("EffectGetSubEffects end - copied the sub effect structures");
            return count;
        }
        e = e->next;
diff --git a/media/libeffects/factory/EffectsFactory.h b/media/libeffects/factory/EffectsFactory.h
index 147ff18..560b485 100644
--- a/media/libeffects/factory/EffectsFactory.h
+++ b/media/libeffects/factory/EffectsFactory.h
@@ -20,7 +20,7 @@
 #include <cutils/log.h>
 #include <pthread.h>
 #include <dirent.h>
-#include <media/EffectsFactoryApi.h>
+#include <hardware/audio_effect.h>
 
 #if __cplusplus
 extern "C" {
@@ -66,6 +66,32 @@
     void *object;
 } sub_effect_entry_t;
 
+
+////////////////////////////////////////////////////////////////////////////////
+//
+//    Function:       EffectGetSubEffects
+//
+//    Description:    Returns the descriptors of the sub effects of the effect
+//                    whose uuid is pointed to by first argument.
+//
+//    Input:
+//          pEffectUuid:    pointer to the effect uuid.
+//          size:           max number of sub_effect_entry_t * in pSube.
+//
+//    Input/Output:
+//          pSube:          address where to return the sub effect structures.
+//    Output:
+//        returned value:    0          successful operation.
+//                          -ENODEV     factory failed to initialize
+//                          -EINVAL     invalid pEffectUuid or pDescriptor
+//                          -ENOENT     no effect with this uuid found
+//        *pDescriptor:     updated with the sub effect descriptors.
+//
+////////////////////////////////////////////////////////////////////////////////
+int EffectGetSubEffects(const effect_uuid_t *pEffectUuid,
+                        sub_effect_entry_t **pSube,
+                        size_t size);
+
 #if __cplusplus
 }  // extern "C"
 #endif
diff --git a/media/libeffects/proxy/Android.mk b/media/libeffects/proxy/Android.mk
index d6d6c1e..b438796 100644
--- a/media/libeffects/proxy/Android.mk
+++ b/media/libeffects/proxy/Android.mk
@@ -28,7 +28,8 @@
 
 LOCAL_C_INCLUDES := \
         system/media/audio_effects/include \
-        bionic/libc/include
+        bionic/libc/include \
+        frameworks/av/media/libeffects/factory
 
 include $(BUILD_SHARED_LIBRARY)
 
diff --git a/media/libeffects/proxy/EffectProxy.cpp b/media/libeffects/proxy/EffectProxy.cpp
index e6faaaf..62d3fd3 100644
--- a/media/libeffects/proxy/EffectProxy.cpp
+++ b/media/libeffects/proxy/EffectProxy.cpp
@@ -56,6 +56,8 @@
                            effect_handle_t  *pHandle) {
 
     effect_descriptor_t* desc;
+    audio_effect_library_t** aeli;
+    sub_effect_entry_t** sube;
     EffectContext* pContext;
     if (pHandle == NULL || uuid == NULL) {
         ALOGE("EffectProxyCreate() called with NULL pointer");
@@ -74,31 +76,52 @@
 
     // Get the HW and SW sub effect descriptors from the effects factory
     desc = new effect_descriptor_t[SUB_FX_COUNT];
+    aeli = new audio_effect_library_t*[SUB_FX_COUNT];
+    sube = new sub_effect_entry_t*[SUB_FX_COUNT];
+    pContext->sube = new sub_effect_entry_t*[SUB_FX_COUNT];
     pContext->desc = new effect_descriptor_t[SUB_FX_COUNT];
-    int retValue = EffectGetSubEffects(uuid, desc,
-                                sizeof(effect_descriptor_t) * SUB_FX_COUNT);
+    pContext->aeli = new audio_effect_library_t*[SUB_FX_COUNT];
+    int retValue = EffectGetSubEffects(uuid, sube, SUB_FX_COUNT);
     // EffectGetSubEffects returns the number of sub-effects copied.
     if (retValue != SUB_FX_COUNT) {
        ALOGE("EffectCreate() could not get the sub effects");
-       delete desc;
-       delete pContext->desc;
+       delete[] sube;
+       delete[] desc;
+       delete[] aeli;
+       delete[] pContext->sube;
+       delete[] pContext->desc;
+       delete[] pContext->aeli;
        return -EINVAL;
     }
     // Check which is the HW descriptor and copy the descriptors
     // to the Context desc array
     // Also check if there is only one HW and one SW descriptor.
     // HW descriptor alone has the HW_TUNNEL flag.
+    desc[0] = *(effect_descriptor_t*)(sube[0])->object;
+    desc[1] = *(effect_descriptor_t*)(sube[1])->object;
+    aeli[0] = sube[0]->lib->desc;
+    aeli[1] = sube[1]->lib->desc;
     if ((desc[0].flags & EFFECT_FLAG_HW_ACC_TUNNEL) &&
        !(desc[1].flags & EFFECT_FLAG_HW_ACC_TUNNEL)) {
+        pContext->sube[SUB_FX_OFFLOAD] = sube[0];
         pContext->desc[SUB_FX_OFFLOAD] = desc[0];
+        pContext->aeli[SUB_FX_OFFLOAD] = aeli[0];
+        pContext->sube[SUB_FX_HOST] = sube[1];
         pContext->desc[SUB_FX_HOST] = desc[1];
+        pContext->aeli[SUB_FX_HOST] = aeli[1];
     }
     else if ((desc[1].flags & EFFECT_FLAG_HW_ACC_TUNNEL) &&
              !(desc[0].flags & EFFECT_FLAG_HW_ACC_TUNNEL)) {
+        pContext->sube[SUB_FX_HOST] = sube[0];
         pContext->desc[SUB_FX_HOST] = desc[0];
+        pContext->aeli[SUB_FX_HOST] = aeli[0];
+        pContext->sube[SUB_FX_OFFLOAD] = sube[1];
         pContext->desc[SUB_FX_OFFLOAD] = desc[1];
+        pContext->aeli[SUB_FX_OFFLOAD] = aeli[1];
     }
-    delete desc;
+    delete[] desc;
+    delete[] aeli;
+    delete[] sube;
 #if (LOG_NDEBUG == 0)
     effect_uuid_t uuid_print = pContext->desc[SUB_FX_HOST].uuid;
     ALOGV("EffectCreate() UUID of HOST: %08X-%04X-%04X-%04X-%02X%02X%02X%02X"
@@ -128,13 +151,15 @@
         return -EINVAL;
     }
     ALOGV("EffectRelease");
-    delete pContext->desc;
+    delete[] pContext->desc;
     free(pContext->replyData);
 
     if (pContext->eHandle[SUB_FX_HOST])
-       EffectRelease(pContext->eHandle[SUB_FX_HOST]);
+       pContext->aeli[SUB_FX_HOST]->release_effect(pContext->eHandle[SUB_FX_HOST]);
     if (pContext->eHandle[SUB_FX_OFFLOAD])
-       EffectRelease(pContext->eHandle[SUB_FX_OFFLOAD]);
+       pContext->aeli[SUB_FX_OFFLOAD]->release_effect(pContext->eHandle[SUB_FX_OFFLOAD]);
+    delete[] pContext->aeli;
+    delete[] pContext->sube;
     delete pContext;
     pContext = NULL;
     return 0;
@@ -187,7 +212,8 @@
     }
     if (pContext->eHandle[SUB_FX_HOST] == NULL) {
         ALOGV("Effect_command() Calling HOST EffectCreate");
-        status = EffectCreate(&pContext->desc[SUB_FX_HOST].uuid,
+        status = pContext->aeli[SUB_FX_HOST]->create_effect(
+                              &pContext->desc[SUB_FX_HOST].uuid,
                               pContext->sessionId, pContext->ioId,
                               &(pContext->eHandle[SUB_FX_HOST]));
         if (status != NO_ERROR || (pContext->eHandle[SUB_FX_HOST] == NULL)) {
@@ -197,11 +223,13 @@
     }
     if (pContext->eHandle[SUB_FX_OFFLOAD] == NULL) {
         ALOGV("Effect_command() Calling OFFLOAD EffectCreate");
-        status = EffectCreate(&pContext->desc[SUB_FX_OFFLOAD].uuid,
+        status = pContext->aeli[SUB_FX_OFFLOAD]->create_effect(
+                              &pContext->desc[SUB_FX_OFFLOAD].uuid,
                               pContext->sessionId, pContext->ioId,
                               &(pContext->eHandle[SUB_FX_OFFLOAD]));
         if (status != NO_ERROR || (pContext->eHandle[SUB_FX_OFFLOAD] == NULL)) {
             ALOGV("Effect_command() Error creating HW effect");
+            pContext->eHandle[SUB_FX_OFFLOAD] = NULL;
             // Do not return error here as SW effect is created
             // Return error if the CMD_OFFLOAD sends the index as OFFLOAD
         }
@@ -233,11 +261,17 @@
         // Update the DSP wrapper with the new ioHandle.
         // Pass the OFFLOAD command to the wrapper.
         // The DSP wrapper needs to handle this CMD
-        if (pContext->eHandle[SUB_FX_OFFLOAD])
-            status = (*pContext->eHandle[SUB_FX_OFFLOAD])->command(
-                             pContext->eHandle[SUB_FX_OFFLOAD], cmdCode, cmdSize,
-                             pCmdData, replySize, pReplyData);
-        return status;
+        if (pContext->eHandle[SUB_FX_OFFLOAD]) {
+            ALOGV("Effect_command: Calling OFFLOAD command");
+            return (*pContext->eHandle[SUB_FX_OFFLOAD])->command(
+                           pContext->eHandle[SUB_FX_OFFLOAD], cmdCode, cmdSize,
+                           pCmdData, replySize, pReplyData);
+        }
+        *(int*)pReplyData = NO_ERROR;
+        ALOGV("Effect_command OFFLOAD return 0, replyData %d",
+                                                *(int*)pReplyData);
+
+        return NO_ERROR;
     }
 
     int index = pContext->index;
diff --git a/media/libeffects/proxy/EffectProxy.h b/media/libeffects/proxy/EffectProxy.h
index acbe17e..046b93e 100644
--- a/media/libeffects/proxy/EffectProxy.h
+++ b/media/libeffects/proxy/EffectProxy.h
@@ -16,6 +16,8 @@
 
 #include <hardware/audio.h>
 #include <hardware/audio_effect.h>
+#include "EffectsFactory.h"
+
 namespace android {
 enum {
     SUB_FX_HOST,       // Index of HOST in the descriptor and handle arrays
@@ -62,7 +64,9 @@
 
 struct EffectContext {
   const struct effect_interface_s  *common_itfe; // Holds the itfe of the Proxy
+  sub_effect_entry_t** sube;                     // Points to the sub effects
   effect_descriptor_t*  desc;                    // Points to the sub effect descriptors
+  audio_effect_library_t**  aeli;                // Points to the sub effect aeli
   effect_handle_t       eHandle[SUB_FX_COUNT];   // The effect handles of the sub effects
   int                   index;       // The index that is currently active - HOST or OFFLOAD
   int32_t               sessionId;   // The sessiond in which the effect is created.
diff --git a/media/libmedia/AudioEffect.cpp b/media/libmedia/AudioEffect.cpp
index 8dfffb3..35f6557 100644
--- a/media/libmedia/AudioEffect.cpp
+++ b/media/libmedia/AudioEffect.cpp
@@ -380,9 +380,9 @@
 }
 
 void AudioEffect::commandExecuted(uint32_t cmdCode,
-                                  uint32_t cmdSize,
+                                  uint32_t cmdSize __unused,
                                   void *cmdData,
-                                  uint32_t replySize,
+                                  uint32_t replySize __unused,
                                   void *replyData)
 {
     if (cmdData == NULL || replyData == NULL) {
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index b69e3ae..286096e 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -87,7 +87,7 @@
         int notificationFrames,
         int sessionId,
         transfer_type transferType,
-        audio_input_flags_t flags)
+        audio_input_flags_t flags __unused)
     : mStatus(NO_INIT), mSessionId(AUDIO_SESSION_ALLOCATE),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
       mPreviousSchedulingGroup(SP_DEFAULT),
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index dcb72f8..1ab94fa 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -333,7 +333,7 @@
 }
 
 status_t AudioSystem::getLatency(audio_io_handle_t output,
-                                 audio_stream_type_t streamType,
+                                 audio_stream_type_t streamType __unused,
                                  uint32_t* latency)
 {
     OutputDescriptor *outputDesc;
diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp
index 21018a0..fdd1a12 100644
--- a/media/libmedia/AudioTrackShared.cpp
+++ b/media/libmedia/AudioTrackShared.cpp
@@ -475,9 +475,14 @@
 
 void StaticAudioTrackClientProxy::setLoop(size_t loopStart, size_t loopEnd, int loopCount)
 {
+    // This can only happen on a 64-bit client
+    if (loopStart > UINT32_MAX || loopEnd > UINT32_MAX) {
+        // FIXME Should return an error status
+        return;
+    }
     StaticAudioTrackState newState;
-    newState.mLoopStart = loopStart;
-    newState.mLoopEnd = loopEnd;
+    newState.mLoopStart = (uint32_t) loopStart;
+    newState.mLoopEnd = (uint32_t) loopEnd;
     newState.mLoopCount = loopCount;
     mBufferPosition = loopStart;
     (void) mMutator.push(newState);
@@ -487,7 +492,7 @@
 {
     size_t bufferPosition;
     if (mMutator.ack()) {
-        bufferPosition = mCblk->u.mStatic.mBufferPosition;
+        bufferPosition = (size_t) mCblk->u.mStatic.mBufferPosition;
         if (bufferPosition > mFrameCount) {
             bufferPosition = mFrameCount;
         }
@@ -622,7 +627,7 @@
     if (half == 0) {
         half = 1;
     }
-    size_t minimum = cblk->mMinimum;
+    size_t minimum = (size_t) cblk->mMinimum;
     if (minimum == 0) {
         minimum = mIsOut ? half : 1;
     } else if (minimum > half) {
@@ -760,7 +765,8 @@
             mIsShutdown = true;
             return (ssize_t) NO_INIT;
         }
-        mCblk->u.mStatic.mBufferPosition = position;
+        // This may overflow, but client is not supposed to rely on it
+        mCblk->u.mStatic.mBufferPosition = (uint32_t) position;
     }
     return (ssize_t) position;
 }
@@ -836,7 +842,8 @@
     mPosition = newPosition;
 
     cblk->mServer += stepCount;
-    cblk->u.mStatic.mBufferPosition = newPosition;
+    // This may overflow, but client is not supposed to rely on it
+    cblk->u.mStatic.mBufferPosition = (uint32_t) newPosition;
     if (setFlags != 0) {
         (void) android_atomic_or(setFlags, &cblk->mFlags);
         // this would be a good place to wake a futex
diff --git a/media/libnbaio/AudioBufferProviderSource.cpp b/media/libnbaio/AudioBufferProviderSource.cpp
index 74a6fdb..e952a00 100644
--- a/media/libnbaio/AudioBufferProviderSource.cpp
+++ b/media/libnbaio/AudioBufferProviderSource.cpp
@@ -24,7 +24,7 @@
 namespace android {
 
 AudioBufferProviderSource::AudioBufferProviderSource(AudioBufferProvider *provider,
-                                                     NBAIO_Format format) :
+                                                     const NBAIO_Format& format) :
     NBAIO_Source(format), mProvider(provider), mConsumed(0)
 {
     ALOG_ASSERT(provider != NULL);
diff --git a/media/libnbaio/MonoPipe.cpp b/media/libnbaio/MonoPipe.cpp
index 3c61b60..b23967b 100644
--- a/media/libnbaio/MonoPipe.cpp
+++ b/media/libnbaio/MonoPipe.cpp
@@ -30,7 +30,7 @@
 
 namespace android {
 
-MonoPipe::MonoPipe(size_t reqFrames, NBAIO_Format format, bool writeCanBlock) :
+MonoPipe::MonoPipe(size_t reqFrames, const NBAIO_Format& format, bool writeCanBlock) :
         NBAIO_Sink(format),
         mUpdateSeq(0),
         mReqFrames(reqFrames),
diff --git a/media/libnbaio/NBAIO.cpp b/media/libnbaio/NBAIO.cpp
index e0d2c21..8a8155d 100644
--- a/media/libnbaio/NBAIO.cpp
+++ b/media/libnbaio/NBAIO.cpp
@@ -22,17 +22,19 @@
 
 namespace android {
 
-size_t Format_frameSize(NBAIO_Format format)
+size_t Format_frameSize(const NBAIO_Format& format)
 {
     return Format_channelCount(format) * sizeof(short);
 }
 
-size_t Format_frameBitShift(NBAIO_Format format)
+size_t Format_frameBitShift(const NBAIO_Format& format)
 {
     // sizeof(short) == 2, so frame size == 1 << channels
     return Format_channelCount(format);
 }
 
+const NBAIO_Format Format_Invalid = { 0 };
+
 enum {
     Format_SR_8000,
     Format_SR_11025,
@@ -51,7 +53,7 @@
     Format_C_Mask = 0x18
 };
 
-unsigned Format_sampleRate(NBAIO_Format format)
+unsigned Format_sampleRate(const NBAIO_Format& format)
 {
     if (format == Format_Invalid) {
         return 0;
@@ -78,7 +80,7 @@
     }
 }
 
-unsigned Format_channelCount(NBAIO_Format format)
+unsigned Format_channelCount(const NBAIO_Format& format)
 {
     if (format == Format_Invalid) {
         return 0;
diff --git a/media/libnbaio/Pipe.cpp b/media/libnbaio/Pipe.cpp
index 1c21f9c..115f311 100644
--- a/media/libnbaio/Pipe.cpp
+++ b/media/libnbaio/Pipe.cpp
@@ -25,7 +25,7 @@
 
 namespace android {
 
-Pipe::Pipe(size_t maxFrames, NBAIO_Format format) :
+Pipe::Pipe(size_t maxFrames, const NBAIO_Format& format) :
         NBAIO_Sink(format),
         mMaxFrames(roundup(maxFrames)),
         mBuffer(malloc(mMaxFrames * Format_frameSize(format))),
diff --git a/media/libnbaio/PipeReader.cpp b/media/libnbaio/PipeReader.cpp
index d786b84..24da1bd 100644
--- a/media/libnbaio/PipeReader.cpp
+++ b/media/libnbaio/PipeReader.cpp
@@ -59,7 +59,7 @@
     return avail;
 }
 
-ssize_t PipeReader::read(void *buffer, size_t count, int64_t readPTS)
+ssize_t PipeReader::read(void *buffer, size_t count, int64_t readPTS __unused)
 {
     ssize_t avail = availableToRead();
     if (CC_UNLIKELY(avail <= 0)) {
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index eb274a8..c9f89fc 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -365,6 +365,7 @@
       mIsEncoder(false),
       mUseMetadataOnEncoderOutput(false),
       mShutdownInProgress(false),
+      mIsConfiguredForAdaptivePlayback(false),
       mEncoderDelay(0),
       mEncoderPadding(0),
       mChannelMaskPresent(false),
@@ -372,7 +373,8 @@
       mDequeueCounter(0),
       mStoreMetaDataInOutputBuffers(false),
       mMetaDataBuffersToSubmit(0),
-      mRepeatFrameDelayUs(-1ll) {
+      mRepeatFrameDelayUs(-1ll),
+      mMaxPtsGapUs(-1l) {
     mUninitializedState = new UninitializedState(this);
     mLoadedState = new LoadedState(this);
     mLoadedToIdleState = new LoadedToIdleState(this);
@@ -1114,6 +1116,10 @@
                     &mRepeatFrameDelayUs)) {
             mRepeatFrameDelayUs = -1ll;
         }
+
+        if (!msg->findInt64("max-pts-gap-to-encoder", &mMaxPtsGapUs)) {
+            mMaxPtsGapUs = -1l;
+        }
     }
 
     // Always try to enable dynamic output buffers on native surface
@@ -1121,6 +1127,7 @@
     int32_t haveNativeWindow = msg->findObject("native-window", &obj) &&
             obj != NULL;
     mStoreMetaDataInOutputBuffers = false;
+    mIsConfiguredForAdaptivePlayback = false;
     if (!encoder && video && haveNativeWindow) {
         err = mOMX->storeMetaDataInBuffers(mNode, kPortIndexOutput, OMX_TRUE);
         if (err != OK) {
@@ -1165,12 +1172,14 @@
                 ALOGW_IF(err != OK,
                         "[%s] prepareForAdaptivePlayback failed w/ err %d",
                         mComponentName.c_str(), err);
+                mIsConfiguredForAdaptivePlayback = (err == OK);
             }
             // allow failure
             err = OK;
         } else {
             ALOGV("[%s] storeMetaDataInBuffers succeeded", mComponentName.c_str());
             mStoreMetaDataInOutputBuffers = true;
+            mIsConfiguredForAdaptivePlayback = true;
         }
 
         int32_t push;
@@ -3318,11 +3327,11 @@
                 mCodec->mInputEOSResult = err;
             }
             break;
-
-            default:
-                CHECK_EQ((int)mode, (int)FREE_BUFFERS);
-                break;
         }
+
+        default:
+            CHECK_EQ((int)mode, (int)FREE_BUFFERS);
+            break;
     }
 }
 
@@ -3498,7 +3507,7 @@
     int32_t render;
     if (mCodec->mNativeWindow != NULL
             && msg->findInt32("render", &render) && render != 0
-            && (info->mData == NULL || info->mData->size() != 0)) {
+            && info->mData != NULL && info->mData->size() != 0) {
         // The client wants this buffer to be rendered.
 
         status_t err;
@@ -3773,6 +3782,7 @@
     mCodec->mDequeueCounter = 0;
     mCodec->mMetaDataBuffersToSubmit = 0;
     mCodec->mRepeatFrameDelayUs = -1ll;
+    mCodec->mIsConfiguredForAdaptivePlayback = false;
 
     if (mCodec->mShutdownInProgress) {
         bool keepComponentAllocated = mCodec->mKeepComponentAllocated;
@@ -3921,6 +3931,21 @@
         }
     }
 
+    if (err == OK && mCodec->mMaxPtsGapUs > 0l) {
+        err = mCodec->mOMX->setInternalOption(
+                mCodec->mNode,
+                kPortIndexInput,
+                IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP,
+                &mCodec->mMaxPtsGapUs,
+                sizeof(mCodec->mMaxPtsGapUs));
+
+        if (err != OK) {
+            ALOGE("[%s] Unable to configure max timestamp gap (err %d)",
+                  mCodec->mComponentName.c_str(),
+                  err);
+        }
+    }
+
     if (err == OK) {
         notify->setObject("input-surface",
                 new BufferProducerWrapper(bufferProducer));
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index a0f17b5..b7a4b75 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -972,13 +972,16 @@
     if (param && param->findInt32(kKeyFileType, &fileType) &&
         fileType != OUTPUT_FORMAT_MPEG_4) {
         writeFourcc("3gp4");
-    } else {
+        writeInt32(0);
         writeFourcc("isom");
+        writeFourcc("3gp4");
+    } else {
+        writeFourcc("mp42");
+        writeInt32(0);
+        writeFourcc("isom");
+        writeFourcc("mp42");
     }
 
-    writeInt32(0);
-    writeFourcc("isom");
-    writeFourcc("3gp4");
     endBox();
 }
 
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 8af1aaf..c4c47b3 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -1680,7 +1680,7 @@
         return -EACCES;
     }
 
-    if (render && (info->mData == NULL || info->mData->size() != 0)) {
+    if (render && info->mData != NULL && info->mData->size() != 0) {
         info->mNotify->setInt32("render", true);
 
         if (mSoftRenderer != NULL) {
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index d260d0f..dcb1cda 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -716,41 +716,61 @@
     return mIsLiveStreaming;
 }
 
+static int bytesForSize(size_t size) {
+    // use at most 28 bits (4 times 7)
+    CHECK(size <= 0xfffffff);
+
+    if (size > 0x1fffff) {
+        return 4;
+    } else if (size > 0x3fff) {
+        return 3;
+    } else if (size > 0x7f) {
+        return 2;
+    }
+    return 1;
+}
+
+static void storeSize(uint8_t *data, size_t &idx, size_t size) {
+    int numBytes = bytesForSize(size);
+    idx += numBytes;
+
+    data += idx;
+    size_t next = 0;
+    while (numBytes--) {
+        *--data = (size & 0x7f) | next;
+        size >>= 7;
+        next = 0x80;
+    }
+}
+
 static void addESDSFromCodecPrivate(
         const sp<MetaData> &meta,
         bool isAudio, const void *priv, size_t privSize) {
-    static const uint8_t kStaticESDS[] = {
-        0x03, 22,
-        0x00, 0x00,     // ES_ID
-        0x00,           // streamDependenceFlag, URL_Flag, OCRstreamFlag
 
-        0x04, 17,
-        0x40,           // ObjectTypeIndication
-        0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00,
-
-        0x05,
-        // CodecSpecificInfo (with size prefix) follows
-    };
-
-    // Make sure all sizes can be coded in a single byte.
-    CHECK(privSize + 22 - 2 < 128);
-    size_t esdsSize = sizeof(kStaticESDS) + privSize + 1;
+    int privSizeBytesRequired = bytesForSize(privSize);
+    int esdsSize2 = 14 + privSizeBytesRequired + privSize;
+    int esdsSize2BytesRequired = bytesForSize(esdsSize2);
+    int esdsSize1 = 4 + esdsSize2BytesRequired + esdsSize2;
+    int esdsSize1BytesRequired = bytesForSize(esdsSize1);
+    size_t esdsSize = 1 + esdsSize1BytesRequired + esdsSize1;
     uint8_t *esds = new uint8_t[esdsSize];
-    memcpy(esds, kStaticESDS, sizeof(kStaticESDS));
-    uint8_t *ptr = esds + sizeof(kStaticESDS);
-    *ptr++ = privSize;
-    memcpy(ptr, priv, privSize);
 
-    // Increment by codecPrivateSize less 2 bytes that are accounted for
-    // already in lengths of 22/17
-    esds[1] += privSize - 2;
-    esds[6] += privSize - 2;
-
-    // Set ObjectTypeIndication.
-    esds[7] = isAudio ? 0x40   // Audio ISO/IEC 14496-3
-                      : 0x20;  // Visual ISO/IEC 14496-2
+    size_t idx = 0;
+    esds[idx++] = 0x03;
+    storeSize(esds, idx, esdsSize1);
+    esds[idx++] = 0x00; // ES_ID
+    esds[idx++] = 0x00; // ES_ID
+    esds[idx++] = 0x00; // streamDependenceFlag, URL_Flag, OCRstreamFlag
+    esds[idx++] = 0x04;
+    storeSize(esds, idx, esdsSize2);
+    esds[idx++] = isAudio ? 0x40   // Audio ISO/IEC 14496-3
+                          : 0x20;  // Visual ISO/IEC 14496-2
+    for (int i = 0; i < 12; i++) {
+        esds[idx++] = 0x00;
+    }
+    esds[idx++] = 0x05;
+    storeSize(esds, idx, privSize);
+    memcpy(esds + idx, priv, privSize);
 
     meta->setData(kKeyESDS, 0, esds, esdsSize);
 
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index 7492577..20fa7ce 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -42,7 +42,11 @@
     mEndOfStream(false),
     mEndOfStreamSent(false),
     mRepeatAfterUs(-1ll),
+    mMaxTimestampGapUs(-1ll),
+    mPrevOriginalTimeUs(-1ll),
+    mPrevModifiedTimeUs(-1ll),
     mRepeatLastFrameGeneration(0),
+    mRepeatLastFrameTimestamp(-1ll),
     mLatestSubmittedBufferId(-1),
     mLatestSubmittedBufferFrameNum(0),
     mLatestSubmittedBufferUseCount(0),
@@ -299,6 +303,32 @@
     return;
 }
 
+void GraphicBufferSource::codecBufferFilled(OMX_BUFFERHEADERTYPE* header) {
+    Mutex::Autolock autoLock(mMutex);
+
+    if (mMaxTimestampGapUs > 0ll
+            && !(header->nFlags & OMX_BUFFERFLAG_CODECCONFIG)) {
+        ssize_t index = mOriginalTimeUs.indexOfKey(header->nTimeStamp);
+        if (index >= 0) {
+            ALOGV("OUT timestamp: %lld -> %lld",
+                    header->nTimeStamp, mOriginalTimeUs[index]);
+            header->nTimeStamp = mOriginalTimeUs[index];
+            mOriginalTimeUs.removeItemsAt(index);
+        } else {
+            // giving up the effort as encoder doesn't appear to preserve pts
+            ALOGW("giving up limiting timestamp gap (pts = %lld)",
+                    header->nTimeStamp);
+            mMaxTimestampGapUs = -1ll;
+        }
+        if (mOriginalTimeUs.size() > BufferQueue::NUM_BUFFER_SLOTS) {
+            // something terribly wrong must have happened, giving up...
+            ALOGE("mOriginalTimeUs has too many entries (%d)",
+                    mOriginalTimeUs.size());
+            mMaxTimestampGapUs = -1ll;
+        }
+    }
+}
+
 void GraphicBufferSource::suspend(bool suspend) {
     Mutex::Autolock autoLock(mMutex);
 
@@ -431,6 +461,7 @@
     BufferQueue::BufferItem item;
     item.mBuf = mLatestSubmittedBufferId;
     item.mFrameNumber = mLatestSubmittedBufferFrameNum;
+    item.mTimestamp = mRepeatLastFrameTimestamp;
 
     status_t err = submitBuffer_l(item, cbi);
 
@@ -440,6 +471,20 @@
 
     ++mLatestSubmittedBufferUseCount;
 
+    /* repeat last frame up to kRepeatLastFrameCount times.
+     * in case of static scene, a single repeat might not get rid of encoder
+     * ghosting completely, refresh a couple more times to get better quality
+     */
+    if (--mRepeatLastFrameCount > 0) {
+        mRepeatLastFrameTimestamp = item.mTimestamp + mRepeatAfterUs * 1000;
+
+        if (mReflector != NULL) {
+            sp<AMessage> msg = new AMessage(kWhatRepeatLastFrame, mReflector->id());
+            msg->setInt32("generation", ++mRepeatLastFrameGeneration);
+            msg->post(mRepeatAfterUs);
+        }
+    }
+
     return true;
 }
 
@@ -460,8 +505,11 @@
 
     mLatestSubmittedBufferId = item.mBuf;
     mLatestSubmittedBufferFrameNum = item.mFrameNumber;
+    mRepeatLastFrameTimestamp = item.mTimestamp + mRepeatAfterUs * 1000;
+
     mLatestSubmittedBufferUseCount = 1;
     mRepeatBufferDeferred = false;
+    mRepeatLastFrameCount = kRepeatLastFrameCount;
 
     if (mReflector != NULL) {
         sp<AMessage> msg = new AMessage(kWhatRepeatLastFrame, mReflector->id());
@@ -497,6 +545,39 @@
     return OK;
 }
 
+int64_t GraphicBufferSource::getTimestamp(const BufferQueue::BufferItem &item) {
+    int64_t timeUs = item.mTimestamp / 1000;
+
+    if (mMaxTimestampGapUs > 0ll) {
+        /* Cap timestamp gap between adjacent frames to specified max
+         *
+         * In the scenario of cast mirroring, encoding could be suspended for
+         * prolonged periods. Limiting the pts gap to workaround the problem
+         * where encoder's rate control logic produces huge frames after a
+         * long period of suspension.
+         */
+
+        int64_t originalTimeUs = timeUs;
+        if (mPrevOriginalTimeUs >= 0ll) {
+            if (originalTimeUs < mPrevOriginalTimeUs) {
+                // Drop the frame if it's going backward in time. Bad timestamp
+                // could disrupt encoder's rate control completely.
+                ALOGV("Dropping frame that's going backward in time");
+                return -1;
+            }
+            int64_t timestampGapUs = originalTimeUs - mPrevOriginalTimeUs;
+            timeUs = (timestampGapUs < mMaxTimestampGapUs ?
+                    timestampGapUs : mMaxTimestampGapUs) + mPrevModifiedTimeUs;
+        }
+        mPrevOriginalTimeUs = originalTimeUs;
+        mPrevModifiedTimeUs = timeUs;
+        mOriginalTimeUs.add(timeUs, originalTimeUs);
+        ALOGV("IN  timestamp: %lld -> %lld", originalTimeUs, timeUs);
+    }
+
+    return timeUs;
+}
+
 status_t GraphicBufferSource::submitBuffer_l(
         const BufferQueue::BufferItem &item, int cbi) {
     ALOGV("submitBuffer_l cbi=%d", cbi);
@@ -513,9 +594,15 @@
     memcpy(data, &type, 4);
     memcpy(data + 4, &handle, sizeof(buffer_handle_t));
 
+    int64_t timeUs = getTimestamp(item);
+    if (timeUs < 0ll) {
+        ALOGE("Dropping frame with bad timestamp");
+        return UNKNOWN_ERROR;
+    }
+
     status_t err = mNodeInstance->emptyDirectBuffer(header, 0,
             4 + sizeof(buffer_handle_t), OMX_BUFFERFLAG_ENDOFFRAME,
-            item.mTimestamp / 1000);
+            timeUs);
     if (err != OK) {
         ALOGW("WARNING: emptyDirectBuffer failed: 0x%x", err);
         codecBuffer.mGraphicBuffer = NULL;
@@ -664,6 +751,17 @@
     return OK;
 }
 
+status_t GraphicBufferSource::setMaxTimestampGapUs(int64_t maxGapUs) {
+    Mutex::Autolock autoLock(mMutex);
+
+    if (mExecuting || maxGapUs <= 0ll) {
+        return INVALID_OPERATION;
+    }
+
+    mMaxTimestampGapUs = maxGapUs;
+
+    return OK;
+}
 void GraphicBufferSource::onMessageReceived(const sp<AMessage> &msg) {
     switch (msg->what()) {
         case kWhatRepeatLastFrame:
diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h
index 9e5eee6..3b0e454 100644
--- a/media/libstagefright/omx/GraphicBufferSource.h
+++ b/media/libstagefright/omx/GraphicBufferSource.h
@@ -87,6 +87,10 @@
     // fill it with a new frame of data; otherwise, just mark it as available.
     void codecBufferEmptied(OMX_BUFFERHEADERTYPE* header);
 
+    // Called when omx_message::FILL_BUFFER_DONE is received. (Currently the
+    // buffer source will fix timestamp in the header if needed.)
+    void codecBufferFilled(OMX_BUFFERHEADERTYPE* header);
+
     // This is called after the last input frame has been submitted.  We
     // need to submit an empty buffer with the EOS flag set.  If we don't
     // have a codec buffer ready, we just set the mEndOfStream flag.
@@ -105,6 +109,15 @@
     // state and once this behaviour is specified it cannot be reset.
     status_t setRepeatPreviousFrameDelayUs(int64_t repeatAfterUs);
 
+    // When set, the timestamp fed to the encoder will be modified such that
+    // the gap between two adjacent frames is capped at maxGapUs. Timestamp
+    // will be restored to the original when the encoded frame is returned to
+    // the client.
+    // This is to solve a problem in certain real-time streaming case, where
+    // encoder's rate control logic produces huge frames after a long period
+    // of suspension on input.
+    status_t setMaxTimestampGapUs(int64_t maxGapUs);
+
 protected:
     // BufferQueue::ConsumerListener interface, called when a new frame of
     // data is available.  If we're executing and a codec buffer is
@@ -165,6 +178,7 @@
 
     void setLatestSubmittedBuffer_l(const BufferQueue::BufferItem &item);
     bool repeatLatestSubmittedBuffer_l();
+    int64_t getTimestamp(const BufferQueue::BufferItem &item);
 
     // Lock, covers all member variables.
     mutable Mutex mMutex;
@@ -206,13 +220,22 @@
     enum {
         kWhatRepeatLastFrame,
     };
-
+    enum {
+        kRepeatLastFrameCount = 10,
+    };
     int64_t mRepeatAfterUs;
+    int64_t mMaxTimestampGapUs;
+
+    KeyedVector<int64_t, int64_t> mOriginalTimeUs;
+    int64_t mPrevOriginalTimeUs;
+    int64_t mPrevModifiedTimeUs;
 
     sp<ALooper> mLooper;
     sp<AHandlerReflector<GraphicBufferSource> > mReflector;
 
     int32_t mRepeatLastFrameGeneration;
+    int64_t mRepeatLastFrameTimestamp;
+    int32_t mRepeatLastFrameCount;
 
     int mLatestSubmittedBufferId;
     uint64_t mLatestSubmittedBufferFrameNum;
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 5f104fc..6c5c857 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -849,6 +849,7 @@
     switch (type) {
         case IOMX::INTERNAL_OPTION_SUSPEND:
         case IOMX::INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY:
+        case IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP:
         {
             const sp<GraphicBufferSource> &bufferSource =
                 getGraphicBufferSource();
@@ -864,7 +865,8 @@
 
                 bool suspend = *(bool *)data;
                 bufferSource->suspend(suspend);
-            } else {
+            } else if (type ==
+                    IOMX::INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY){
                 if (size != sizeof(int64_t)) {
                     return INVALID_OPERATION;
                 }
@@ -872,6 +874,14 @@
                 int64_t delayUs = *(int64_t *)data;
 
                 return bufferSource->setRepeatPreviousFrameDelayUs(delayUs);
+            } else {
+                if (size != sizeof(int64_t)) {
+                    return INVALID_OPERATION;
+                }
+
+                int64_t maxGapUs = *(int64_t *)data;
+
+                return bufferSource->setMaxTimestampGapUs(maxGapUs);
             }
 
             return OK;
@@ -883,6 +893,8 @@
 }
 
 void OMXNodeInstance::onMessage(const omx_message &msg) {
+    const sp<GraphicBufferSource>& bufferSource(getGraphicBufferSource());
+
     if (msg.type == omx_message::FILL_BUFFER_DONE) {
         OMX_BUFFERHEADERTYPE *buffer =
             static_cast<OMX_BUFFERHEADERTYPE *>(
@@ -892,10 +904,18 @@
             static_cast<BufferMeta *>(buffer->pAppPrivate);
 
         buffer_meta->CopyFromOMX(buffer);
-    } else if (msg.type == omx_message::EMPTY_BUFFER_DONE) {
-        const sp<GraphicBufferSource>& bufferSource(getGraphicBufferSource());
 
         if (bufferSource != NULL) {
+            // fix up the buffer info (especially timestamp) if needed
+            bufferSource->codecBufferFilled(buffer);
+
+            omx_message newMsg = msg;
+            newMsg.u.extended_buffer_data.timestamp = buffer->nTimeStamp;
+            mObserver->onMessage(newMsg);
+            return;
+        }
+    } else if (msg.type == omx_message::EMPTY_BUFFER_DONE) {
+        if (bufferSource != NULL) {
             // This is one of the buffers used exclusively by
             // GraphicBufferSource.
             // Don't dispatch a message back to ACodec, since it doesn't
diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp
index d5207d5..a347951 100644
--- a/media/mediaserver/main_mediaserver.cpp
+++ b/media/mediaserver/main_mediaserver.cpp
@@ -37,7 +37,7 @@
 
 using namespace android;
 
-int main(int argc, char** argv)
+int main(int argc __unused, char** argv)
 {
     signal(SIGPIPE, SIG_IGN);
     char value[PROPERTY_VALUE_MAX];
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index f9cc17b..7c73b19 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -264,7 +264,7 @@
     return NULL;
 }
 
-void AudioFlinger::dumpClients(int fd, const Vector<String16>& args)
+void AudioFlinger::dumpClients(int fd, const Vector<String16>& args __unused)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
@@ -296,7 +296,7 @@
 }
 
 
-void AudioFlinger::dumpInternals(int fd, const Vector<String16>& args)
+void AudioFlinger::dumpInternals(int fd, const Vector<String16>& args __unused)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
@@ -311,7 +311,7 @@
     write(fd, result.string(), result.size());
 }
 
-void AudioFlinger::dumpPermissionDenial(int fd, const Vector<String16>& args)
+void AudioFlinger::dumpPermissionDenial(int fd, const Vector<String16>& args __unused)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
@@ -559,7 +559,7 @@
 
         track = thread->createTrack_l(client, streamType, sampleRate, format,
                 channelMask, frameCount, sharedBuffer, lSessionId, flags, tid, clientUid, &lStatus);
-        LOG_ALWAYS_FATAL_IF((track != 0) != (lStatus == NO_ERROR));
+        LOG_ALWAYS_FATAL_IF((lStatus == NO_ERROR) && (track == 0));
         // we don't abort yet if lStatus != NO_ERROR; there is still work to be done regardless
 
         // move effect chain to this output thread if an effect on same session was waiting
@@ -1259,7 +1259,7 @@
 {
 }
 
-void AudioFlinger::NotificationClient::binderDied(const wp<IBinder>& who)
+void AudioFlinger::NotificationClient::binderDied(const wp<IBinder>& who __unused)
 {
     sp<NotificationClient> keep(this);
     mAudioFlinger->removeNotificationClient(mPid);
@@ -1340,7 +1340,7 @@
                                                   frameCount, lSessionId,
                                                   IPCThreadState::self()->getCallingUid(),
                                                   flags, tid, &lStatus);
-        LOG_ALWAYS_FATAL_IF((recordTrack != 0) != (lStatus == NO_ERROR));
+        LOG_ALWAYS_FATAL_IF((lStatus == NO_ERROR) && (recordTrack == 0));
     }
 
     if (lStatus != NO_ERROR) {
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index 59d1a59..f2af9b2 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -536,7 +536,7 @@
                 // Should have a way to distinguish tracks with static ratios vs. dynamic ratios.
                 if (!((value == 44100 && devSampleRate == 48000) ||
                       (value == 48000 && devSampleRate == 44100))) {
-                    quality = AudioResampler::LOW_QUALITY;
+                    quality = AudioResampler::DYN_LOW_QUALITY;
                 } else {
                     quality = AudioResampler::DEFAULT_QUALITY;
                 }
diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp
index 415f696..6a115ff 100644
--- a/services/audioflinger/AudioPolicyService.cpp
+++ b/services/audioflinger/AudioPolicyService.cpp
@@ -613,7 +613,7 @@
     return NO_ERROR;
 }
 
-status_t AudioPolicyService::dump(int fd, const Vector<String16>& args)
+status_t AudioPolicyService::dump(int fd, const Vector<String16>& args __unused)
 {
     if (!dumpAllowed()) {
         dumpPermissionDenial(fd);
@@ -1461,7 +1461,7 @@
 extern "C" {
 
 
-static audio_module_handle_t aps_load_hw_module(void *service,
+static audio_module_handle_t aps_load_hw_module(void *service __unused,
                                              const char *name)
 {
     sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
@@ -1474,7 +1474,7 @@
 }
 
 // deprecated: replaced by aps_open_output_on_module()
-static audio_io_handle_t aps_open_output(void *service,
+static audio_io_handle_t aps_open_output(void *service __unused,
                                          audio_devices_t *pDevices,
                                          uint32_t *pSamplingRate,
                                          audio_format_t *pFormat,
@@ -1492,7 +1492,7 @@
                           pLatencyMs, flags);
 }
 
-static audio_io_handle_t aps_open_output_on_module(void *service,
+static audio_io_handle_t aps_open_output_on_module(void *service __unused,
                                                    audio_module_handle_t module,
                                                    audio_devices_t *pDevices,
                                                    uint32_t *pSamplingRate,
@@ -1511,7 +1511,7 @@
                           pLatencyMs, flags, offloadInfo);
 }
 
-static audio_io_handle_t aps_open_dup_output(void *service,
+static audio_io_handle_t aps_open_dup_output(void *service __unused,
                                                  audio_io_handle_t output1,
                                                  audio_io_handle_t output2)
 {
@@ -1523,7 +1523,7 @@
     return af->openDuplicateOutput(output1, output2);
 }
 
-static int aps_close_output(void *service, audio_io_handle_t output)
+static int aps_close_output(void *service __unused, audio_io_handle_t output)
 {
     sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
     if (af == 0) {
@@ -1533,7 +1533,7 @@
     return af->closeOutput(output);
 }
 
-static int aps_suspend_output(void *service, audio_io_handle_t output)
+static int aps_suspend_output(void *service __unused, audio_io_handle_t output)
 {
     sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
     if (af == 0) {
@@ -1544,7 +1544,7 @@
     return af->suspendOutput(output);
 }
 
-static int aps_restore_output(void *service, audio_io_handle_t output)
+static int aps_restore_output(void *service __unused, audio_io_handle_t output)
 {
     sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
     if (af == 0) {
@@ -1556,12 +1556,12 @@
 }
 
 // deprecated: replaced by aps_open_input_on_module(), and acoustics parameter is ignored
-static audio_io_handle_t aps_open_input(void *service,
+static audio_io_handle_t aps_open_input(void *service __unused,
                                         audio_devices_t *pDevices,
                                         uint32_t *pSamplingRate,
                                         audio_format_t *pFormat,
                                         audio_channel_mask_t *pChannelMask,
-                                        audio_in_acoustics_t acoustics)
+                                        audio_in_acoustics_t acoustics __unused)
 {
     sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
     if (af == 0) {
@@ -1572,7 +1572,7 @@
     return af->openInput((audio_module_handle_t)0, pDevices, pSamplingRate, pFormat, pChannelMask);
 }
 
-static audio_io_handle_t aps_open_input_on_module(void *service,
+static audio_io_handle_t aps_open_input_on_module(void *service __unused,
                                                   audio_module_handle_t module,
                                                   audio_devices_t *pDevices,
                                                   uint32_t *pSamplingRate,
@@ -1588,7 +1588,7 @@
     return af->openInput(module, pDevices, pSamplingRate, pFormat, pChannelMask);
 }
 
-static int aps_close_input(void *service, audio_io_handle_t input)
+static int aps_close_input(void *service __unused, audio_io_handle_t input)
 {
     sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
     if (af == 0) {
@@ -1598,7 +1598,7 @@
     return af->closeInput(input);
 }
 
-static int aps_set_stream_output(void *service, audio_stream_type_t stream,
+static int aps_set_stream_output(void *service __unused, audio_stream_type_t stream,
                                      audio_io_handle_t output)
 {
     sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
@@ -1609,7 +1609,7 @@
     return af->setStreamOutput(stream, output);
 }
 
-static int aps_move_effects(void *service, int session,
+static int aps_move_effects(void *service __unused, int session,
                                 audio_io_handle_t src_output,
                                 audio_io_handle_t dst_output)
 {
@@ -1621,7 +1621,7 @@
     return af->moveEffects(session, src_output, dst_output);
 }
 
-static char * aps_get_parameters(void *service, audio_io_handle_t io_handle,
+static char * aps_get_parameters(void *service __unused, audio_io_handle_t io_handle,
                                      const char *keys)
 {
     String8 result = AudioSystem::getParameters(io_handle, String8(keys));
diff --git a/services/audioflinger/AudioResampler.cpp b/services/audioflinger/AudioResampler.cpp
index 24ff55d..07574ab 100644
--- a/services/audioflinger/AudioResampler.cpp
+++ b/services/audioflinger/AudioResampler.cpp
@@ -158,6 +158,16 @@
         atFinalQuality = true;
     }
 
+    /* if the caller requests DEFAULT_QUALITY and af.resampler.property
+     * has not been set, the target resampler quality is set to DYN_MED_QUALITY,
+     * and allowed to "throttle" down to DYN_LOW_QUALITY if necessary
+     * due to estimated CPU load of having too many active resamplers
+     * (the code below the if).
+     */
+    if (quality == DEFAULT_QUALITY) {
+        quality = DYN_MED_QUALITY;
+    }
+
     // naive implementation of CPU load throttling doesn't account for whether resampler is active
     pthread_mutex_lock(&mutex);
     for (;;) {
@@ -172,7 +182,6 @@
         // not enough CPU available for proposed quality level, so try next lowest level
         switch (quality) {
         default:
-        case DEFAULT_QUALITY:
         case LOW_QUALITY:
             atFinalQuality = true;
             break;
@@ -202,7 +211,6 @@
 
     switch (quality) {
     default:
-    case DEFAULT_QUALITY:
     case LOW_QUALITY:
         ALOGV("Create linear Resampler");
         resampler = new AudioResamplerOrder1(bitDepth, inChannelCount, sampleRate);
@@ -563,7 +571,7 @@
         "   ldr r8, [sp, #" MO_PARAM5 " + 4]\n"     // out
         "   ldr r0, [sp, #" MO_PARAM5 " + 0]\n"     // &outputIndex
         "   ldr r0, [r0]\n"                         // outputIndex
-        "   add r8, r0, asl #2\n"                   // curOut
+        "   add r8, r8, r0, asl #2\n"               // curOut
         "   ldr r9, [sp, #" MO_PARAM5 " + 24]\n"    // phaseIncrement
         "   ldr r10, [sp, #" MO_PARAM5 " + 12]\n"   // vl
         "   ldr r11, [sp, #" MO_PARAM5 " + 16]\n"   // vr
@@ -683,7 +691,7 @@
         "   ldr r8, [sp, #" ST_PARAM5 " + 4]\n"     // out
         "   ldr r0, [sp, #" ST_PARAM5 " + 0]\n"     // &outputIndex
         "   ldr r0, [r0]\n"                         // outputIndex
-        "   add r8, r0, asl #2\n"                   // curOut
+        "   add r8, r8, r0, asl #2\n"               // curOut
         "   ldr r9, [sp, #" ST_PARAM5 " + 24]\n"    // phaseIncrement
         "   ldr r10, [sp, #" ST_PARAM5 " + 12]\n"   // vl
         "   ldr r11, [sp, #" ST_PARAM5 " + 16]\n"   // vr
diff --git a/services/audioflinger/AudioResamplerDyn.cpp b/services/audioflinger/AudioResamplerDyn.cpp
index 984548d..cd67df5 100644
--- a/services/audioflinger/AudioResamplerDyn.cpp
+++ b/services/audioflinger/AudioResamplerDyn.cpp
@@ -372,11 +372,7 @@
     if (locked) {
         mPhaseFraction = mPhaseFraction >> c.mShift << c.mShift; // remove fractional phase
     }
-    if (!USE_NEON) {
-        stride = 2; // C version only
-    }
-    // TODO: Remove this for testing
-    //stride = 2;
+
     mResampleType = RESAMPLETYPE(mChannelCount, locked, stride, !!useS32);
 #ifdef DEBUG_RESAMPLER
     printf("channels:%d  %s  stride:%d  %s  coef:%d  shift:%d\n",
@@ -392,7 +388,7 @@
     // 24 cases - this perhaps can be reduced later, as testing might take too long
     switch (mResampleType) {
 
-    // stride 16 (stride 2 for machines that do not support NEON)
+    // stride 16 (falls back to stride 2 for machines that do not support NEON)
     case RESAMPLETYPE(1, true, 16, 0):
         return resample<1, true, 16>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
     case RESAMPLETYPE(2, true, 16, 0):
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 59b4770..537c076 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -805,7 +805,7 @@
     return mOffloaded;
 }
 
-void AudioFlinger::EffectModule::dump(int fd, const Vector<String16>& args)
+void AudioFlinger::EffectModule::dump(int fd, const Vector<String16>& args __unused)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 515368c..24df473 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -185,7 +185,11 @@
 {
 }
 
-void CpuStats::sample(const String8 &title) {
+void CpuStats::sample(const String8 &title
+#ifndef DEBUG_CPU_USAGE
+                __unused
+#endif
+        ) {
 #ifdef DEBUG_CPU_USAGE
     // get current thread's delta CPU time in wall clock ns
     double wcNs;
@@ -421,7 +425,7 @@
     }
 }
 
-void AudioFlinger::ThreadBase::dumpBase(int fd, const Vector<String16>& args)
+void AudioFlinger::ThreadBase::dumpBase(int fd, const Vector<String16>& args __unused)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
@@ -604,7 +608,7 @@
     mPowerManager.clear();
 }
 
-void AudioFlinger::ThreadBase::PMDeathRecipient::binderDied(const wp<IBinder>& who)
+void AudioFlinger::ThreadBase::PMDeathRecipient::binderDied(const wp<IBinder>& who __unused)
 {
     sp<ThreadBase> thread = mThread.promote();
     if (thread != 0) {
@@ -1088,7 +1092,7 @@
     dumpEffectChains(fd, args);
 }
 
-void AudioFlinger::PlaybackThread::dumpTracks(int fd, const Vector<String16>& args)
+void AudioFlinger::PlaybackThread::dumpTracks(int fd, const Vector<String16>& args __unused)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
@@ -1342,7 +1346,7 @@
         lStatus = track != 0 ? track->initCheck() : (status_t) NO_MEMORY;
         if (lStatus != NO_ERROR) {
             ALOGE("createTrack_l() initCheck failed %d; no control block?", lStatus);
-            track.clear();
+            // track must be cleared from the caller as the caller has the AF lock
             goto Exit;
         }
 
@@ -1614,7 +1618,7 @@
 
 // static
 int AudioFlinger::PlaybackThread::asyncCallback(stream_callback_event_t event,
-                                                void *param,
+                                                void *param __unused,
                                                 void *cookie)
 {
     AudioFlinger::PlaybackThread *me = (AudioFlinger::PlaybackThread *)cookie;
@@ -3739,14 +3743,14 @@
 }
 
 // getTrackName_l() must be called with ThreadBase::mLock held
-int AudioFlinger::DirectOutputThread::getTrackName_l(audio_channel_mask_t channelMask,
-        int sessionId)
+int AudioFlinger::DirectOutputThread::getTrackName_l(audio_channel_mask_t channelMask __unused,
+        int sessionId __unused)
 {
     return 0;
 }
 
 // deleteTrackName_l() must be called with ThreadBase::mLock held
-void AudioFlinger::DirectOutputThread::deleteTrackName_l(int name)
+void AudioFlinger::DirectOutputThread::deleteTrackName_l(int name __unused)
 {
 }
 
@@ -4859,7 +4863,7 @@
         lStatus = track->initCheck();
         if (lStatus != NO_ERROR) {
             ALOGE("createRecordTrack_l() initCheck failed %d; no control block?", lStatus);
-            track.clear();
+            // track must be cleared from the caller as the caller has the AF lock
             goto Exit;
         }
         mTracks.add(track);
@@ -5026,12 +5030,12 @@
     return false;
 }
 
-bool AudioFlinger::RecordThread::isValidSyncEvent(const sp<SyncEvent>& event) const
+bool AudioFlinger::RecordThread::isValidSyncEvent(const sp<SyncEvent>& event __unused) const
 {
     return false;
 }
 
-status_t AudioFlinger::RecordThread::setSyncEvent(const sp<SyncEvent>& event)
+status_t AudioFlinger::RecordThread::setSyncEvent(const sp<SyncEvent>& event __unused)
 {
 #if 0   // This branch is currently dead code, but is preserved in case it will be needed in future
     if (!isValidSyncEvent(event)) {
@@ -5109,7 +5113,7 @@
     dumpBase(fd, args);
 }
 
-void AudioFlinger::RecordThread::dumpTracks(int fd, const Vector<String16>& args)
+void AudioFlinger::RecordThread::dumpTracks(int fd, const Vector<String16>& args __unused)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
@@ -5142,7 +5146,7 @@
 }
 
 // AudioBufferProvider interface
-status_t AudioFlinger::RecordThread::getNextBuffer(AudioBufferProvider::Buffer* buffer, int64_t pts)
+status_t AudioFlinger::RecordThread::getNextBuffer(AudioBufferProvider::Buffer* buffer, int64_t pts __unused)
 {
     int32_t rear = mRsmpInRear;
     int32_t front = mRsmpInFront;
@@ -5321,7 +5325,7 @@
     return out_s8;
 }
 
-void AudioFlinger::RecordThread::audioConfigChanged_l(int event, int param) {
+void AudioFlinger::RecordThread::audioConfigChanged_l(int event, int param __unused) {
     AudioSystem::OutputDescriptor desc;
     const void *param2 = NULL;
 
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 8df6f94..1745ea1 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -201,13 +201,13 @@
                 // effect
                 void removeEffect_l(const sp< EffectModule>& effect);
                 // detach all tracks connected to an auxiliary effect
-    virtual     void detachAuxEffect_l(int effectId) {}
+    virtual     void detachAuxEffect_l(int effectId __unused) {}
                 // returns either EFFECT_SESSION if effects on this audio session exist in one
                 // chain, or TRACK_SESSION if tracks on this audio session exist, or both
                 virtual uint32_t hasAudioSession(int sessionId) const = 0;
                 // the value returned by default implementation is not important as the
                 // strategy is only meaningful for PlaybackThread which implements this method
-                virtual uint32_t getStrategyForSession_l(int sessionId) { return 0; }
+                virtual uint32_t getStrategyForSession_l(int sessionId __unused) { return 0; }
 
                 // suspend or restore effect according to the type of effect passed. a NULL
                 // type pointer means suspend all effects in the session
@@ -625,7 +625,7 @@
     sp<NBLog::Writer>       mFastMixerNBLogWriter;
 public:
     virtual     bool        hasFastMixer() const = 0;
-    virtual     FastTrackUnderruns getFastTrackUnderruns(size_t fastIndex) const
+    virtual     FastTrackUnderruns getFastTrackUnderruns(size_t fastIndex __unused) const
                                 { FastTrackUnderruns dummy; return dummy; }
 
 protected:
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index d8d7790..ecedca9 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -526,7 +526,7 @@
 
 // AudioBufferProvider interface
 status_t AudioFlinger::PlaybackThread::Track::getNextBuffer(
-        AudioBufferProvider::Buffer* buffer, int64_t pts)
+        AudioBufferProvider::Buffer* buffer, int64_t pts __unused)
 {
     ServerProxy::Buffer buf;
     size_t desiredFrames = buffer->frameCount;
@@ -576,8 +576,8 @@
     return false;
 }
 
-status_t AudioFlinger::PlaybackThread::Track::start(AudioSystem::sync_event_t event,
-                                                    int triggerSession)
+status_t AudioFlinger::PlaybackThread::Track::start(AudioSystem::sync_event_t event __unused,
+                                                    int triggerSession __unused)
 {
     status_t status = NO_ERROR;
     ALOGV("start(%d), calling pid %d session %d",
@@ -1163,7 +1163,7 @@
 
 void AudioFlinger::PlaybackThread::TimedTrack::updateFramesPendingAfterTrim_l(
         const TimedBuffer& buf,
-        const char* logTag) {
+        const char* logTag __unused) {
     uint32_t bufBytes        = buf.buffer()->size();
     uint32_t consumedAlready = buf.position();
 
@@ -1786,7 +1786,7 @@
 
 // AudioBufferProvider interface
 status_t AudioFlinger::RecordThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer,
-        int64_t pts)
+        int64_t pts __unused)
 {
     ServerProxy::Buffer buf;
     buf.mFrameCount = buffer->frameCount;
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index f84f019..2cf0d29 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -664,13 +664,13 @@
     focusState = ANDROID_CONTROL_AF_STATE_INACTIVE;
     shadowFocusMode = FOCUS_MODE_INVALID;
 
-    camera_metadata_ro_entry_t max3aRegions =
-        staticInfo(ANDROID_CONTROL_MAX_REGIONS, 1, 1);
-    if (!max3aRegions.count) return NO_INIT;
+    camera_metadata_ro_entry_t max3aRegions = staticInfo(ANDROID_CONTROL_MAX_REGIONS,
+            Parameters::NUM_REGION, Parameters::NUM_REGION);
+    if (max3aRegions.count != Parameters::NUM_REGION) return NO_INIT;
 
     int32_t maxNumFocusAreas = 0;
     if (focusMode != Parameters::FOCUS_MODE_FIXED) {
-        maxNumFocusAreas = max3aRegions.data.i32[0];
+        maxNumFocusAreas = max3aRegions.data.i32[Parameters::REGION_AF];
     }
     params.set(CameraParameters::KEY_MAX_NUM_FOCUS_AREAS, maxNumFocusAreas);
     params.set(CameraParameters::KEY_FOCUS_AREAS,
@@ -730,7 +730,7 @@
 
     meteringAreas.add(Parameters::Area(0, 0, 0, 0, 0));
     params.set(CameraParameters::KEY_MAX_NUM_METERING_AREAS,
-            max3aRegions.data.i32[0]);
+            max3aRegions.data.i32[Parameters::REGION_AE]);
     params.set(CameraParameters::KEY_METERING_AREAS,
             "(0,0,0,0,0)");
 
@@ -1591,10 +1591,11 @@
     // FOCUS_AREAS
     res = parseAreas(newParams.get(CameraParameters::KEY_FOCUS_AREAS),
             &validatedParams.focusingAreas);
-    size_t max3aRegions =
-        (size_t)staticInfo(ANDROID_CONTROL_MAX_REGIONS, 1, 1).data.i32[0];
+    size_t maxAfRegions = (size_t)staticInfo(ANDROID_CONTROL_MAX_REGIONS,
+              Parameters::NUM_REGION, Parameters::NUM_REGION).
+              data.i32[Parameters::REGION_AF];
     if (res == OK) res = validateAreas(validatedParams.focusingAreas,
-            max3aRegions, AREA_KIND_FOCUS);
+            maxAfRegions, AREA_KIND_FOCUS);
     if (res != OK) {
         ALOGE("%s: Requested focus areas are malformed: %s",
                 __FUNCTION__, newParams.get(CameraParameters::KEY_FOCUS_AREAS));
@@ -1624,10 +1625,13 @@
         newParams.get(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK));
 
     // METERING_AREAS
+    size_t maxAeRegions = (size_t)staticInfo(ANDROID_CONTROL_MAX_REGIONS,
+            Parameters::NUM_REGION, Parameters::NUM_REGION).
+            data.i32[Parameters::REGION_AE];
     res = parseAreas(newParams.get(CameraParameters::KEY_METERING_AREAS),
             &validatedParams.meteringAreas);
     if (res == OK) {
-        res = validateAreas(validatedParams.meteringAreas, max3aRegions,
+        res = validateAreas(validatedParams.meteringAreas, maxAeRegions,
                             AREA_KIND_METERING);
     }
     if (res != OK) {
@@ -1909,6 +1913,23 @@
             reqMeteringAreas, reqMeteringAreasSize);
     if (res != OK) return res;
 
+    // Set awb regions to be the same as the metering regions if allowed
+    size_t maxAwbRegions = (size_t)staticInfo(ANDROID_CONTROL_MAX_REGIONS,
+            Parameters::NUM_REGION, Parameters::NUM_REGION).
+            data.i32[Parameters::REGION_AWB];
+    if (maxAwbRegions > 0) {
+        if (maxAwbRegions >= meteringAreas.size()) {
+            res = request->update(ANDROID_CONTROL_AWB_REGIONS,
+                    reqMeteringAreas, reqMeteringAreasSize);
+        } else {
+            // Ensure the awb regions are zeroed if the region count is too high.
+            int32_t zeroedAwbAreas[5] = {0, 0, 0, 0, 0};
+            res = request->update(ANDROID_CONTROL_AWB_REGIONS,
+                    zeroedAwbAreas, sizeof(zeroedAwbAreas)/sizeof(int32_t));
+        }
+        if (res != OK) return res;
+    }
+
     delete[] reqMeteringAreas;
 
     /* don't include jpeg thumbnail size - it's valid for
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h
index 32dbd42..60c4687 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.h
+++ b/services/camera/libcameraservice/api1/client2/Parameters.h
@@ -113,6 +113,14 @@
     bool autoExposureLock;
     bool autoWhiteBalanceLock;
 
+    // 3A region types, for use with ANDROID_CONTROL_MAX_REGIONS
+    enum region_t {
+        REGION_AE = 0,
+        REGION_AWB,
+        REGION_AF,
+        NUM_REGION // Number of region types
+    } region;
+
     Vector<Area> meteringAreas;
 
     int zoom;
diff --git a/services/medialog/MediaLogService.cpp b/services/medialog/MediaLogService.cpp
index 683fdf3..0c7fbbd 100644
--- a/services/medialog/MediaLogService.cpp
+++ b/services/medialog/MediaLogService.cpp
@@ -54,7 +54,7 @@
     }
 }
 
-status_t MediaLogService::dump(int fd, const Vector<String16>& args)
+status_t MediaLogService::dump(int fd, const Vector<String16>& args __unused)
 {
     // FIXME merge with similar but not identical code at services/audioflinger/ServiceUtilities.cpp
     static const String16 sDump("android.permission.DUMP");