Merge "Fix typo in socket name"
diff --git a/camera/ProCamera.cpp b/camera/ProCamera.cpp
index fec5461..1040415 100644
--- a/camera/ProCamera.cpp
+++ b/camera/ProCamera.cpp
@@ -247,7 +247,8 @@
     sp <IProCameraUser> c = mCamera;
     if (c == 0) return NO_INIT;
 
-    sp<CpuConsumer> cc = new CpuConsumer(heapCount, synchronousMode);
+    sp<BufferQueue> bq = new BufferQueue();
+    sp<CpuConsumer> cc = new CpuConsumer(bq, heapCount/*, synchronousMode*/);
     cc->setName(String8("ProCamera::mCpuConsumer"));
 
     sp<Surface> stc = new Surface(
diff --git a/camera/photography/ICameraDeviceUser.cpp b/camera/photography/ICameraDeviceUser.cpp
index 0515bd7..325f94d 100644
--- a/camera/photography/ICameraDeviceUser.cpp
+++ b/camera/photography/ICameraDeviceUser.cpp
@@ -151,21 +151,22 @@
     }
 
 
-    virtual status_t getCameraInfo(int cameraId, camera_metadata** info)
+    virtual status_t getCameraInfo(CameraMetadata* info)
     {
         Parcel data, reply;
         data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor());
-        data.writeInt32(cameraId);
         remote()->transact(GET_CAMERA_INFO, data, &reply);
 
-
         reply.readExceptionCode();
         status_t result = reply.readInt32();
 
+        CameraMetadata out;
         if (reply.readInt32() != 0) {
-            CameraMetadata::readFromParcel(reply, /*out*/info);
-        } else if (info) {
-            *info = NULL;
+            out.readFromParcel(&reply);
+        }
+
+        if (info != NULL) {
+            info->swap(out);
         }
 
         return result;
@@ -273,6 +274,7 @@
             reply->writeNoException();
             reply->writeInt32(ret);
 
+            // out-variables are after exception and return value
             reply->writeInt32(1); // to mark presence of metadata object
             request.writeToParcel(const_cast<Parcel*>(reply));
 
@@ -281,19 +283,16 @@
         case GET_CAMERA_INFO: {
             CHECK_INTERFACE(ICameraDeviceUser, data, reply);
 
-            int cameraId = data.readInt32();
-
-            camera_metadata_t* info = NULL;
+            CameraMetadata info;
             status_t ret;
-            ret = getCameraInfo(cameraId, &info);
-
-            reply->writeInt32(1); // to mark presence of metadata object
-            CameraMetadata::writeToParcel(*reply, info);
+            ret = getCameraInfo(&info);
 
             reply->writeNoException();
             reply->writeInt32(ret);
 
-            free_camera_metadata(info);
+            // out-variables are after exception and return value
+            reply->writeInt32(1); // to mark presence of metadata object
+            info.writeToParcel(reply);
 
             return NO_ERROR;
         } break;
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index f8fc8ed..529b96c 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -937,7 +937,8 @@
         } else {
             CHECK(useSurfaceTexAlloc);
 
-            sp<GLConsumer> texture = new GLConsumer(0 /* tex */);
+            sp<BufferQueue> bq = new BufferQueue();
+            sp<GLConsumer> texture = new GLConsumer(bq, 0 /* tex */);
             gSurface = new Surface(texture->getBufferQueue());
         }
 
diff --git a/include/camera/photography/ICameraDeviceUser.h b/include/camera/photography/ICameraDeviceUser.h
index 1b8d666..3ea49f4 100644
--- a/include/camera/photography/ICameraDeviceUser.h
+++ b/include/camera/photography/ICameraDeviceUser.h
@@ -58,9 +58,8 @@
                                                  /*out*/
                                                  CameraMetadata* request) = 0;
     // Get static camera metadata
-    virtual status_t        getCameraInfo(int cameraId,
-                                          /*out*/
-                                          camera_metadata** info) = 0;
+    virtual status_t        getCameraInfo(/*out*/
+                                          CameraMetadata* info) = 0;
 
 };
 
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index fb1d631..e7b85c0 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -246,6 +246,8 @@
     static uint32_t getPrimaryOutputSamplingRate();
     static size_t getPrimaryOutputFrameCount();
 
+    static status_t setLowRamDevice(bool isLowRamDevice);
+
     // Check if hw offload is possible for given format, stream type, sample rate,
     // bit rate, duration, video and streaming or offload property is enabled
     static bool isOffloadSupported(const audio_offload_info_t& info);
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 6727601..58e0deb 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -75,8 +75,10 @@
         size_t      frameCount;   // number of sample frames corresponding to size;
                                   // on input it is the number of frames desired,
                                   // on output is the number of frames actually filled
+                                  // (currently ignored, but will make the primary field in future)
 
         size_t      size;         // input/output in bytes == frameCount * frameSize
+                                  // on output is the number of bytes actually filled
                                   // FIXME this is redundant with respect to frameCount,
                                   // and TRANSFER_OBTAIN mode is broken for 8-bit data
                                   // since we don't define the frame format
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index f8a9f2b..de45aa8 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -125,7 +125,9 @@
     virtual     String8     getParameters(audio_io_handle_t ioHandle, const String8& keys)
                                     const = 0;
 
-    // register a current process for audio output change notifications
+    // Register an object to receive audio input/output change and track notifications.
+    // For a given calling pid, AudioFlinger disregards any registrations after the first.
+    // Thus the IAudioFlingerClient must be a singleton per process.
     virtual void registerClient(const sp<IAudioFlingerClient>& client) = 0;
 
     // retrieve the audio recording buffer size
@@ -195,6 +197,10 @@
     virtual uint32_t getPrimaryOutputSamplingRate() = 0;
     virtual size_t getPrimaryOutputFrameCount() = 0;
 
+    // Intended for AudioService to inform AudioFlinger of device's low RAM attribute,
+    // and should be called at most once.  For a definition of what "low RAM" means, see
+    // android.app.ActivityManager.isLowRamDevice().
+    virtual status_t setLowRamDevice(bool isLowRamDevice) = 0;
 };
 
 
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index 0b1d1e4..38f9d11 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -130,6 +130,16 @@
             node_id node,
             const char *parameter_name,
             OMX_INDEXTYPE *index) = 0;
+
+    enum InternalOptionType {
+        INTERNAL_OPTION_SUSPEND,  // data is a bool
+    };
+    virtual status_t setInternalOption(
+            node_id node,
+            OMX_U32 port_index,
+            InternalOptionType type,
+            const void *data,
+            size_t size) = 0;
 };
 
 struct omx_message {
diff --git a/include/media/nbaio/NBLog.h b/include/media/nbaio/NBLog.h
index 107ba66..6d59ea7 100644
--- a/include/media/nbaio/NBLog.h
+++ b/include/media/nbaio/NBLog.h
@@ -90,6 +90,8 @@
     virtual ~Timeline();
 #endif
 
+    // Input parameter 'size' is the desired size of the timeline in byte units.
+    // Returns the size rounded up to a power-of-2, plus the constant size overhead for indices.
     static size_t sharedSize(size_t size);
 
 #if 0
@@ -110,8 +112,12 @@
 class Writer : public RefBase {
 public:
     Writer();                   // dummy nop implementation without shared memory
+
+    // Input parameter 'size' is the desired size of the timeline in byte units.
+    // The size of the shared memory must be at least Timeline::sharedSize(size).
     Writer(size_t size, void *shared);
     Writer(size_t size, const sp<IMemory>& iMemory);
+
     virtual ~Writer() { }
 
     virtual void    log(const char *string);
@@ -165,8 +171,12 @@
 
 class Reader : public RefBase {
 public:
+
+    // Input parameter 'size' is the desired size of the timeline in byte units.
+    // The size of the shared memory must be at least Timeline::sharedSize(size).
     Reader(size_t size, const void *shared);
     Reader(size_t size, const sp<IMemory>& iMemory);
+
     virtual ~Reader() { }
 
     void    dump(int fd, size_t indent = 0);
diff --git a/media/libstagefright/wifi-display/ANetworkSession.h b/include/media/stagefright/foundation/ANetworkSession.h
similarity index 97%
rename from media/libstagefright/wifi-display/ANetworkSession.h
rename to include/media/stagefright/foundation/ANetworkSession.h
index 7c62b29..fd3ebaa 100644
--- a/media/libstagefright/wifi-display/ANetworkSession.h
+++ b/include/media/stagefright/foundation/ANetworkSession.h
@@ -77,6 +77,8 @@
             int32_t sessionID, const void *data, ssize_t size = -1,
             bool timeValid = false, int64_t timeUs = -1ll);
 
+    status_t switchToWebSocketMode(int32_t sessionID);
+
     enum NotificationReason {
         kWhatError,
         kWhatConnected,
@@ -84,6 +86,7 @@
         kWhatData,
         kWhatDatagram,
         kWhatBinaryData,
+        kWhatWebSocketMessage,
         kWhatNetworkStall,
     };
 
diff --git a/media/libstagefright/wifi-display/ParsedMessage.h b/include/media/stagefright/foundation/ParsedMessage.h
similarity index 96%
rename from media/libstagefright/wifi-display/ParsedMessage.h
rename to include/media/stagefright/foundation/ParsedMessage.h
index e9a1859..9d43a93 100644
--- a/media/libstagefright/wifi-display/ParsedMessage.h
+++ b/include/media/stagefright/foundation/ParsedMessage.h
@@ -32,7 +32,7 @@
 
     const char *getContent() const;
 
-    void getRequestField(size_t index, AString *field) const;
+    bool getRequestField(size_t index, AString *field) const;
     bool getStatusCode(int32_t *statusCode) const;
 
     AString debugString() const;
diff --git a/libvideoeditor/lvpp/NativeWindowRenderer.cpp b/libvideoeditor/lvpp/NativeWindowRenderer.cpp
index 702900b..84a8e15 100755
--- a/libvideoeditor/lvpp/NativeWindowRenderer.cpp
+++ b/libvideoeditor/lvpp/NativeWindowRenderer.cpp
@@ -568,7 +568,8 @@
 RenderInput::RenderInput(NativeWindowRenderer* renderer, GLuint textureId)
     : mRenderer(renderer)
     , mTextureId(textureId) {
-    mST = new GLConsumer(mTextureId);
+    sp<BufferQueue> bq = new BufferQueue();
+    mST = new GLConsumer(bq, mTextureId);
     mSTC = new Surface(mST->getBufferQueue());
     native_window_connect(mSTC.get(), NATIVE_WINDOW_API_MEDIA);
 }
diff --git a/media/libeffects/testlibs/AudioFormatAdapter.h b/media/libeffects/testlibs/AudioFormatAdapter.h
index 41f1810..dea2734 100644
--- a/media/libeffects/testlibs/AudioFormatAdapter.h
+++ b/media/libeffects/testlibs/AudioFormatAdapter.h
@@ -75,6 +75,7 @@
         while (numSamples > 0) {
             uint32_t numSamplesIter = min(numSamples, mMaxSamplesPerCall);
             uint32_t nSamplesChannels = numSamplesIter * mNumChannels;
+            // This branch of "if" is untested
             if (mPcmFormat == AUDIO_FORMAT_PCM_8_24_BIT) {
                 if (mBehavior == EFFECT_BUFFER_ACCESS_WRITE) {
                     mpProcessor->process(
diff --git a/media/libeffects/testlibs/EffectEqualizer.cpp b/media/libeffects/testlibs/EffectEqualizer.cpp
index c35453b..8d00206 100644
--- a/media/libeffects/testlibs/EffectEqualizer.cpp
+++ b/media/libeffects/testlibs/EffectEqualizer.cpp
@@ -234,8 +234,7 @@
               (pConfig->inputCfg.channels == AUDIO_CHANNEL_OUT_STEREO));
     CHECK_ARG(pConfig->outputCfg.accessMode == EFFECT_BUFFER_ACCESS_WRITE
               || pConfig->outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE);
-    CHECK_ARG(pConfig->inputCfg.format == AUDIO_FORMAT_PCM_8_24_BIT
-              || pConfig->inputCfg.format == AUDIO_FORMAT_PCM_16_BIT);
+    CHECK_ARG(pConfig->inputCfg.format == AUDIO_FORMAT_PCM_16_BIT);
 
     int channelCount;
     if (pConfig->inputCfg.channels == AUDIO_CHANNEL_OUT_MONO) {
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 22d6763..0d59af0 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -454,7 +454,7 @@
         } break;
     case OUTPUT_CLOSED: {
         if (gOutputs.indexOfKey(ioHandle) < 0) {
-            ALOGW("ioConfigChanged() closing unknow output! %d", ioHandle);
+            ALOGW("ioConfigChanged() closing unknown output! %d", ioHandle);
             break;
         }
         ALOGV("ioConfigChanged() output %d closed", ioHandle);
@@ -465,7 +465,7 @@
     case OUTPUT_CONFIG_CHANGED: {
         int index = gOutputs.indexOfKey(ioHandle);
         if (index < 0) {
-            ALOGW("ioConfigChanged() modifying unknow output! %d", ioHandle);
+            ALOGW("ioConfigChanged() modifying unknown output! %d", ioHandle);
             break;
         }
         if (param2 == NULL) break;
@@ -537,6 +537,8 @@
     return gAudioPolicyService;
 }
 
+// ---------------------------------------------------------------------------
+
 status_t AudioSystem::setDeviceConnectionState(audio_devices_t device,
                                                audio_policy_dev_state_t state,
                                                const char *device_address)
@@ -770,6 +772,13 @@
     return af->getPrimaryOutputFrameCount();
 }
 
+status_t AudioSystem::setLowRamDevice(bool isLowRamDevice)
+{
+    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+    if (af == 0) return PERMISSION_DENIED;
+    return af->setLowRamDevice(isLowRamDevice);
+}
+
 void AudioSystem::clearAudioConfigCache()
 {
     Mutex::Autolock _l(gLock);
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 00f4640..7b6b38d 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -585,6 +585,7 @@
 
 status_t AudioTrack::setMarkerPosition(uint32_t marker)
 {
+    // The only purpose of setting marker position is to get a callback
     if (mCbf == NULL) {
         return INVALID_OPERATION;
     }
@@ -610,6 +611,7 @@
 
 status_t AudioTrack::setPositionUpdatePeriod(uint32_t updatePeriod)
 {
+    // The only purpose of setting position update period is to get a callback
     if (mCbf == NULL) {
         return INVALID_OPERATION;
     }
@@ -1220,6 +1222,11 @@
 
 nsecs_t AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
 {
+    // Currently the AudioTrack thread is not created if there are no callbacks.
+    // Would it ever make sense to run the thread, even without callbacks?
+    // If so, then replace this by checks at each use for mCbf != NULL.
+    LOG_ALWAYS_FATAL_IF(mCblk == NULL);
+
     mLock.lock();
     if (mAwaitBoost) {
         mAwaitBoost = false;
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index 6bb7df6..2e2c0cc 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -73,6 +73,7 @@
     LOAD_HW_MODULE,
     GET_PRIMARY_OUTPUT_SAMPLING_RATE,
     GET_PRIMARY_OUTPUT_FRAME_COUNT,
+    SET_LOW_RAM_DEVICE,
 };
 
 class BpAudioFlinger : public BpInterface<IAudioFlinger>
@@ -698,6 +699,15 @@
         return reply.readInt32();
     }
 
+    virtual status_t setLowRamDevice(bool isLowRamDevice)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32((int) isLowRamDevice);
+        remote()->transact(SET_LOW_RAM_DEVICE, data, &reply);
+        return reply.readInt32();
+    }
+
 };
 
 IMPLEMENT_META_INTERFACE(AudioFlinger, "android.media.IAudioFlinger");
@@ -1059,6 +1069,12 @@
             reply->writeInt32(getPrimaryOutputFrameCount());
             return NO_ERROR;
         } break;
+        case SET_LOW_RAM_DEVICE: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            bool isLowRamDevice = data.readInt32() != 0;
+            reply->writeInt32(setLowRamDevice(isLowRamDevice));
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index d6cd43a..5bbb2f0 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -51,6 +51,7 @@
     GET_EXTENSION_INDEX,
     OBSERVER_ON_MSG,
     GET_GRAPHIC_BUFFER_USAGE,
+    SET_INTERNAL_OPTION,
 };
 
 class BpOMX : public BpInterface<IOMX> {
@@ -439,6 +440,24 @@
 
         return err;
     }
+
+    virtual status_t setInternalOption(
+            node_id node,
+            OMX_U32 port_index,
+            InternalOptionType type,
+            const void *optionData,
+            size_t size) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+        data.writeIntPtr((intptr_t)node);
+        data.writeInt32(port_index);
+        data.writeInt32(size);
+        data.write(optionData, size);
+        data.writeInt32(type);
+        remote()->transact(SET_INTERNAL_OPTION, data, &reply);
+
+        return reply.readInt32();
+    }
 };
 
 IMPLEMENT_META_INTERFACE(OMX, "android.hardware.IOMX");
@@ -537,6 +556,7 @@
         case SET_PARAMETER:
         case GET_CONFIG:
         case SET_CONFIG:
+        case SET_INTERNAL_OPTION:
         {
             CHECK_OMX_INTERFACE(IOMX, data, reply);
 
@@ -562,6 +582,15 @@
                 case SET_CONFIG:
                     err = setConfig(node, index, params, size);
                     break;
+                case SET_INTERNAL_OPTION:
+                {
+                    InternalOptionType type =
+                        (InternalOptionType)data.readInt32();
+
+                    err = setInternalOption(node, index, type, params, size);
+                    break;
+                }
+
                 default:
                     TRESPASS();
             }
diff --git a/media/libmediaplayerservice/Crypto.cpp b/media/libmediaplayerservice/Crypto.cpp
index ae4d845..62593b2 100644
--- a/media/libmediaplayerservice/Crypto.cpp
+++ b/media/libmediaplayerservice/Crypto.cpp
@@ -134,7 +134,6 @@
         return;
     }
 
-    ALOGE("Failed to find crypto plugin");
     mInitCheck = ERROR_UNSUPPORTED;
 }
 
@@ -151,6 +150,7 @@
     if (!mLibrary.get()) {
         mLibrary = new SharedLibrary(path);
         if (!*mLibrary) {
+            ALOGE("loadLibraryForScheme failed:%s", mLibrary->lastError());
             return false;
         }
 
@@ -165,6 +165,7 @@
     if (createCryptoFactory == NULL ||
         (mFactory = createCryptoFactory()) == NULL ||
         !mFactory->isCryptoSchemeSupported(uuid)) {
+        ALOGE("createCryptoFactory failed:%s", mLibrary->lastError());
         closeFactory();
         return false;
     }
diff --git a/media/libmediaplayerservice/MidiFile.cpp b/media/libmediaplayerservice/MidiFile.cpp
index 8db5b9b..270b872 100644
--- a/media/libmediaplayerservice/MidiFile.cpp
+++ b/media/libmediaplayerservice/MidiFile.cpp
@@ -422,7 +422,7 @@
 
 status_t MidiFile::createOutputTrack() {
     if (mAudioSink->open(pLibConfig->sampleRate, pLibConfig->numChannels,
-            CHANNEL_MASK_USE_CHANNEL_ORDER, AUDIO_FORMAT_PCM_16_BIT, 2) != NO_ERROR) {
+            CHANNEL_MASK_USE_CHANNEL_ORDER, AUDIO_FORMAT_PCM_16_BIT, 2 /*bufferCount*/) != NO_ERROR) {
         ALOGE("mAudioSink open failed");
         return ERROR_OPEN_FAILED;
     }
diff --git a/media/libmediaplayerservice/RemoteDisplay.cpp b/media/libmediaplayerservice/RemoteDisplay.cpp
index 20e6513..eb959b4 100644
--- a/media/libmediaplayerservice/RemoteDisplay.cpp
+++ b/media/libmediaplayerservice/RemoteDisplay.cpp
@@ -16,19 +16,23 @@
 
 #include "RemoteDisplay.h"
 
-#include "ANetworkSession.h"
 #include "source/WifiDisplaySource.h"
 
 #include <media/IRemoteDisplayClient.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/ANetworkSession.h>
 
 namespace android {
 
 RemoteDisplay::RemoteDisplay(
-        const sp<IRemoteDisplayClient> &client, const char *iface)
+        const sp<IRemoteDisplayClient> &client,
+        const char *iface)
     : mLooper(new ALooper),
-      mNetSession(new ANetworkSession),
-      mSource(new WifiDisplaySource(mNetSession, client)) {
+      mNetSession(new ANetworkSession) {
     mLooper->setName("wfd_looper");
+
+    mSource = new WifiDisplaySource(mNetSession, client);
     mLooper->registerHandler(mSource);
 
     mNetSession->start();
@@ -50,6 +54,7 @@
 
 status_t RemoteDisplay::dispose() {
     mSource->stop();
+    mSource.clear();
 
     mLooper->stop();
     mNetSession->stop();
diff --git a/media/libmediaplayerservice/RemoteDisplay.h b/media/libmediaplayerservice/RemoteDisplay.h
index bd8b684..82a0116 100644
--- a/media/libmediaplayerservice/RemoteDisplay.h
+++ b/media/libmediaplayerservice/RemoteDisplay.h
@@ -18,6 +18,7 @@
 
 #define REMOTE_DISPLAY_H_
 
+#include <media/IMediaPlayerService.h>
 #include <media/IRemoteDisplay.h>
 #include <media/stagefright/foundation/ABase.h>
 #include <utils/Errors.h>
@@ -31,7 +32,9 @@
 struct WifiDisplaySource;
 
 struct RemoteDisplay : public BnRemoteDisplay {
-    RemoteDisplay(const sp<IRemoteDisplayClient> &client, const char *iface);
+    RemoteDisplay(
+            const sp<IRemoteDisplayClient> &client,
+            const char *iface);
 
     virtual status_t pause();
     virtual status_t resume();
diff --git a/media/libmediaplayerservice/SharedLibrary.cpp b/media/libmediaplayerservice/SharedLibrary.cpp
index 178e15d..34db761 100644
--- a/media/libmediaplayerservice/SharedLibrary.cpp
+++ b/media/libmediaplayerservice/SharedLibrary.cpp
@@ -46,4 +46,10 @@
         }
         return dlsym(mLibHandle, symbol);
     }
+
+    const char *SharedLibrary::lastError() const {
+        const char *error = dlerror();
+        return error ? error : "No errors or unknown error";
+    }
+
 };
diff --git a/media/libmediaplayerservice/SharedLibrary.h b/media/libmediaplayerservice/SharedLibrary.h
index 5353642..88451a0 100644
--- a/media/libmediaplayerservice/SharedLibrary.h
+++ b/media/libmediaplayerservice/SharedLibrary.h
@@ -29,6 +29,7 @@
 
         bool operator!() const;
         void *lookup(const char *symbol) const;
+        const char *lastError() const;
 
     private:
         void *mLibHandle;
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 6bc7718..00804c5 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -2630,6 +2630,14 @@
         goto error;
     }
 
+    err = native_window_set_scaling_mode(mNativeWindow.get(),
+                NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+    if (err != NO_ERROR) {
+        ALOGE("error pushing blank_frames: set_scaling_mode failed: %s (%d)",
+              strerror(-err), -err);
+        goto error;
+    }
+
     err = native_window_set_usage(mNativeWindow.get(),
             GRALLOC_USAGE_SW_WRITE_OFTEN);
     if (err != NO_ERROR) {
@@ -4106,6 +4114,19 @@
         }
     }
 
+    int32_t dropInputFrames;
+    if (params->findInt32("drop-input-frames", &dropInputFrames)) {
+        bool suspend = dropInputFrames != 0;
+
+        CHECK_EQ((status_t)OK,
+                 mOMX->setInternalOption(
+                     mNode,
+                     kPortIndexInput,
+                     IOMX::INTERNAL_OPTION_SUSPEND,
+                     &suspend,
+                     sizeof(suspend)));
+    }
+
     return OK;
 }
 
diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp
index 1822f07..810d88f 100644
--- a/media/libstagefright/OMXClient.cpp
+++ b/media/libstagefright/OMXClient.cpp
@@ -113,6 +113,13 @@
             const char *parameter_name,
             OMX_INDEXTYPE *index);
 
+    virtual status_t setInternalOption(
+            node_id node,
+            OMX_U32 port_index,
+            InternalOptionType type,
+            const void *data,
+            size_t size);
+
 private:
     mutable Mutex mLock;
 
@@ -331,6 +338,15 @@
     return getOMX(node)->getExtensionIndex(node, parameter_name, index);
 }
 
+status_t MuxOMX::setInternalOption(
+        node_id node,
+        OMX_U32 port_index,
+        InternalOptionType type,
+        const void *data,
+        size_t size) {
+    return getOMX(node)->setInternalOption(node, port_index, type, data, size);
+}
+
 OMXClient::OMXClient() {
 }
 
diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
index 305e7e0..befd4cc 100644
--- a/media/libstagefright/SurfaceMediaSource.cpp
+++ b/media/libstagefright/SurfaceMediaSource.cpp
@@ -21,7 +21,7 @@
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
 #include <OMX_IVCommon.h>
-#include <MetadataBufferType.h>
+#include <media/hardware/MetadataBufferType.h>
 
 #include <ui/GraphicBuffer.h>
 #include <gui/ISurfaceComposer.h>
@@ -54,9 +54,8 @@
         ALOGE("Invalid dimensions %dx%d", bufferWidth, bufferHeight);
     }
 
-    mBufferQueue = new BufferQueue(true);
+    mBufferQueue = new BufferQueue();
     mBufferQueue->setDefaultBufferSize(bufferWidth, bufferHeight);
-    mBufferQueue->setSynchronousMode(true);
     mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER |
             GRALLOC_USAGE_HW_TEXTURE);
 
@@ -71,7 +70,7 @@
     listener = static_cast<BufferQueue::ConsumerListener*>(this);
     proxy = new BufferQueue::ProxyConsumerListener(listener);
 
-    status_t err = mBufferQueue->consumerConnect(proxy);
+    status_t err = mBufferQueue->consumerConnect(proxy, false);
     if (err != NO_ERROR) {
         ALOGE("SurfaceMediaSource: error connecting to BufferQueue: %s (%d)",
                 strerror(-err), err);
diff --git a/media/libstagefright/codecs/on2/enc/Android.mk b/media/libstagefright/codecs/on2/enc/Android.mk
index a92d376..4060a0a 100644
--- a/media/libstagefright/codecs/on2/enc/Android.mk
+++ b/media/libstagefright/codecs/on2/enc/Android.mk
@@ -12,11 +12,16 @@
         frameworks/av/media/libstagefright/include \
         frameworks/native/include/media/openmax \
 
+ifeq ($(TARGET_DEVICE), manta)
+    LOCAL_CFLAGS += -DSURFACE_IS_BGR32
+endif
+
 LOCAL_STATIC_LIBRARIES := \
         libvpx
 
 LOCAL_SHARED_LIBRARIES := \
         libstagefright libstagefright_omx libstagefright_foundation libutils liblog \
+        libhardware \
 
 LOCAL_MODULE := libstagefright_soft_vpxenc
 LOCAL_MODULE_TAGS := optional
diff --git a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
index 74d6df5..5f2b5c8 100644
--- a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
+++ b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
@@ -20,6 +20,8 @@
 
 #include <utils/Log.h>
 
+#include <media/hardware/HardwareAPI.h>
+#include <media/hardware/MetadataBufferType.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaDefs.h>
 
@@ -81,6 +83,52 @@
     }
 }
 
+static void ConvertRGB32ToPlanar(
+        const uint8_t *src, uint8_t *dstY, int32_t width, int32_t height) {
+    CHECK((width & 1) == 0);
+    CHECK((height & 1) == 0);
+
+    uint8_t *dstU = dstY + width * height;
+    uint8_t *dstV = dstU + (width / 2) * (height / 2);
+
+    for (int32_t y = 0; y < height; ++y) {
+        for (int32_t x = 0; x < width; ++x) {
+#ifdef SURFACE_IS_BGR32
+            unsigned blue = src[4 * x];
+            unsigned green = src[4 * x + 1];
+            unsigned red= src[4 * x + 2];
+#else
+            unsigned red= src[4 * x];
+            unsigned green = src[4 * x + 1];
+            unsigned blue = src[4 * x + 2];
+#endif
+
+            unsigned luma =
+                ((red * 66 + green * 129 + blue * 25) >> 8) + 16;
+
+            dstY[x] = luma;
+
+            if ((x & 1) == 0 && (y & 1) == 0) {
+                unsigned U =
+                    ((-red * 38 - green * 74 + blue * 112) >> 8) + 128;
+
+                unsigned V =
+                    ((red * 112 - green * 94 - blue * 18) >> 8) + 128;
+
+                dstU[x / 2] = U;
+                dstV[x / 2] = V;
+            }
+        }
+
+        if ((y & 1) == 0) {
+            dstU += width / 2;
+            dstV += width / 2;
+        }
+
+        src += 4 * width;
+        dstY += width;
+    }
+}
 
 SoftVPXEncoder::SoftVPXEncoder(const char *name,
                                const OMX_CALLBACKTYPE *callbacks,
@@ -99,8 +147,10 @@
       mErrorResilience(OMX_FALSE),
       mColorFormat(OMX_COLOR_FormatYUV420Planar),
       mLevel(OMX_VIDEO_VP8Level_Version0),
-      mConversionBuffer(NULL) {
-
+      mConversionBuffer(NULL),
+      mInputDataIsMeta(false),
+      mGrallocModule(NULL),
+      mKeyFrameRequested(false) {
     initPorts();
 }
 
@@ -247,7 +297,7 @@
         return UNKNOWN_ERROR;
     }
 
-    if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) {
+    if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar || mInputDataIsMeta) {
         if (mConversionBuffer == NULL) {
             mConversionBuffer = (uint8_t *)malloc(mWidth * mHeight * 3 / 2);
             if (mConversionBuffer == NULL) {
@@ -427,9 +477,17 @@
                 (const OMX_VIDEO_PARAM_BITRATETYPE *)param);
 
         case OMX_IndexParamPortDefinition:
-            return internalSetPortParams(
+        {
+            OMX_ERRORTYPE err = internalSetPortParams(
                 (const OMX_PARAM_PORTDEFINITIONTYPE *)param);
 
+            if (err != OMX_ErrorNone) {
+                return err;
+            }
+
+            return SimpleSoftOMXComponent::internalSetParameter(index, param);
+        }
+
         case OMX_IndexParamVideoPortFormat:
             return internalSetFormatParams(
                 (const OMX_VIDEO_PARAM_PORTFORMATTYPE *)param);
@@ -442,11 +500,47 @@
             return internalSetProfileLevel(
                 (const OMX_VIDEO_PARAM_PROFILELEVELTYPE *)param);
 
+        case OMX_IndexVendorStartUnused:
+        {
+            // storeMetaDataInBuffers
+            const StoreMetaDataInBuffersParams *storeParam =
+                (const StoreMetaDataInBuffersParams *)param;
+
+            if (storeParam->nPortIndex != kInputPortIndex) {
+                return OMX_ErrorBadPortIndex;
+            }
+
+            mInputDataIsMeta = (storeParam->bStoreMetaData == OMX_TRUE);
+
+            return OMX_ErrorNone;
+        }
+
         default:
             return SimpleSoftOMXComponent::internalSetParameter(index, param);
     }
 }
 
+OMX_ERRORTYPE SoftVPXEncoder::setConfig(
+        OMX_INDEXTYPE index, const OMX_PTR _params) {
+    switch (index) {
+        case OMX_IndexConfigVideoIntraVOPRefresh:
+        {
+            OMX_CONFIG_INTRAREFRESHVOPTYPE *params =
+                (OMX_CONFIG_INTRAREFRESHVOPTYPE *)_params;
+
+            if (params->nPortIndex != kOutputPortIndex) {
+                return OMX_ErrorBadPortIndex;
+            }
+
+            mKeyFrameRequested = params->IntraRefreshVOP;
+            return OMX_ErrorNone;
+        }
+
+        default:
+            return SimpleSoftOMXComponent::setConfig(index, _params);
+    }
+}
+
 OMX_ERRORTYPE SoftVPXEncoder::internalSetProfileLevel(
         const OMX_VIDEO_PARAM_PROFILELEVELTYPE* profileAndLevel) {
     if (profileAndLevel->nPortIndex != kOutputPortIndex) {
@@ -507,6 +601,10 @@
             format->eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar ||
             format->eColorFormat == OMX_COLOR_FormatAndroidOpaque) {
             mColorFormat = format->eColorFormat;
+
+            OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kInputPortIndex)->mDef;
+            def->format.video.eColorFormat = mColorFormat;
+
             return OMX_ErrorNone;
         } else {
             ALOGE("Unsupported color format %i", format->eColorFormat);
@@ -552,11 +650,17 @@
         if (port->format.video.eColorFormat == OMX_COLOR_FormatYUV420Planar ||
             port->format.video.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar ||
             port->format.video.eColorFormat == OMX_COLOR_FormatAndroidOpaque) {
-                mColorFormat = port->format.video.eColorFormat;
+            mColorFormat = port->format.video.eColorFormat;
         } else {
             return OMX_ErrorUnsupportedSetting;
         }
 
+        OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kInputPortIndex)->mDef;
+        def->format.video.nFrameWidth = mWidth;
+        def->format.video.nFrameHeight = mHeight;
+        def->format.video.xFramerate = port->format.video.xFramerate;
+        def->format.video.eColorFormat = mColorFormat;
+
         return OMX_ErrorNone;
     } else if (port->nPortIndex == kOutputPortIndex) {
         mBitrate = port->format.video.nBitrate;
@@ -625,24 +729,63 @@
             return;
         }
 
-        uint8_t* source = inputBufferHeader->pBuffer + inputBufferHeader->nOffset;
+        uint8_t *source =
+            inputBufferHeader->pBuffer + inputBufferHeader->nOffset;
 
-        // NOTE: As much as nothing is known about color format
-        // when it is denoted as AndroidOpaque, it is at least
-        // assumed to be planar.
-        if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) {
-            ConvertSemiPlanarToPlanar(source, mConversionBuffer, mWidth, mHeight);
+        if (mInputDataIsMeta) {
+            CHECK_GE(inputBufferHeader->nFilledLen,
+                     4 + sizeof(buffer_handle_t));
+
+            uint32_t bufferType = *(uint32_t *)source;
+            CHECK_EQ(bufferType, kMetadataBufferTypeGrallocSource);
+
+            if (mGrallocModule == NULL) {
+                CHECK_EQ(0, hw_get_module(
+                            GRALLOC_HARDWARE_MODULE_ID, &mGrallocModule));
+            }
+
+            const gralloc_module_t *grmodule =
+                (const gralloc_module_t *)mGrallocModule;
+
+            buffer_handle_t handle = *(buffer_handle_t *)(source + 4);
+
+            void *bits;
+            CHECK_EQ(0,
+                     grmodule->lock(
+                         grmodule, handle,
+                         GRALLOC_USAGE_SW_READ_OFTEN
+                            | GRALLOC_USAGE_SW_WRITE_NEVER,
+                         0, 0, mWidth, mHeight, &bits));
+
+            ConvertRGB32ToPlanar(
+                    (const uint8_t *)bits, mConversionBuffer, mWidth, mHeight);
+
+            source = mConversionBuffer;
+
+            CHECK_EQ(0, grmodule->unlock(grmodule, handle));
+        } else if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) {
+            ConvertSemiPlanarToPlanar(
+                    source, mConversionBuffer, mWidth, mHeight);
+
             source = mConversionBuffer;
         }
         vpx_image_t raw_frame;
         vpx_img_wrap(&raw_frame, VPX_IMG_FMT_I420, mWidth, mHeight,
                      kInputBufferAlignment, source);
-        codec_return = vpx_codec_encode(mCodecContext,
-                                        &raw_frame,
-                                        inputBufferHeader->nTimeStamp,  // in timebase units
-                                        mFrameDurationUs,  // frame duration in timebase units
-                                        0,  // frame flags
-                                        VPX_DL_REALTIME);  // encoding deadline
+
+        vpx_enc_frame_flags_t flags = 0;
+        if (mKeyFrameRequested) {
+            flags |= VPX_EFLAG_FORCE_KF;
+            mKeyFrameRequested = false;
+        }
+
+        codec_return = vpx_codec_encode(
+                mCodecContext,
+                &raw_frame,
+                inputBufferHeader->nTimeStamp,  // in timebase units
+                mFrameDurationUs,  // frame duration in timebase units
+                flags,  // frame flags
+                VPX_DL_REALTIME);  // encoding deadline
         if (codec_return != VPX_CODEC_OK) {
             ALOGE("vpx encoder failed to encode frame");
             notify(OMX_EventError,
@@ -676,6 +819,17 @@
         notifyEmptyBufferDone(inputBufferHeader);
     }
 }
+
+OMX_ERRORTYPE SoftVPXEncoder::getExtensionIndex(
+        const char *name, OMX_INDEXTYPE *index) {
+    if (!strcmp(name, "OMX.google.android.index.storeMetaDataInBuffers")) {
+        *index = OMX_IndexVendorStartUnused;
+        return OMX_ErrorNone;
+    }
+
+    return SimpleSoftOMXComponent::getExtensionIndex(name, index);
+}
+
 }  // namespace android
 
 
diff --git a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h
index a0a8ee6..4ee5e51 100644
--- a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h
+++ b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h
@@ -23,6 +23,8 @@
 #include <OMX_VideoExt.h>
 #include <OMX_IndexExt.h>
 
+#include <hardware/gralloc.h>
+
 #include "vpx/vpx_encoder.h"
 #include "vpx/vpx_codec.h"
 #include "vpx/vp8cx.h"
@@ -57,14 +59,13 @@
 //    - OMX timestamps are in microseconds, therefore
 // encoder timebase is fixed to 1/1000000
 
-class SoftVPXEncoder : public SimpleSoftOMXComponent {
- public:
+struct SoftVPXEncoder : public SimpleSoftOMXComponent {
     SoftVPXEncoder(const char *name,
                    const OMX_CALLBACKTYPE *callbacks,
                    OMX_PTR appData,
                    OMX_COMPONENTTYPE **component);
 
- protected:
+protected:
     virtual ~SoftVPXEncoder();
 
     // Returns current values for requested OMX
@@ -77,13 +78,19 @@
     virtual OMX_ERRORTYPE internalSetParameter(
             OMX_INDEXTYPE index, const OMX_PTR param);
 
+    virtual OMX_ERRORTYPE setConfig(
+            OMX_INDEXTYPE index, const OMX_PTR params);
+
     // OMX callback when buffers available
     // Note that both an input and output buffer
     // is expected to be available to carry out
     // encoding of the frame
     virtual void onQueueFilled(OMX_U32 portIndex);
 
- private:
+    virtual OMX_ERRORTYPE getExtensionIndex(
+            const char *name, OMX_INDEXTYPE *index);
+
+private:
     // number of buffers allocated per port
     static const uint32_t kNumBuffers = 4;
 
@@ -156,6 +163,11 @@
     // indeed YUV420SemiPlanar.
     uint8_t* mConversionBuffer;
 
+    bool mInputDataIsMeta;
+    const hw_module_t *mGrallocModule;
+
+    bool mKeyFrameRequested;
+
     // Initializes input and output OMX ports with sensible
     // default values.
     void initPorts();
diff --git a/media/libstagefright/wifi-display/ANetworkSession.cpp b/media/libstagefright/foundation/ANetworkSession.cpp
similarity index 85%
rename from media/libstagefright/wifi-display/ANetworkSession.cpp
rename to media/libstagefright/foundation/ANetworkSession.cpp
index 938d601..e629588 100644
--- a/media/libstagefright/wifi-display/ANetworkSession.cpp
+++ b/media/libstagefright/foundation/ANetworkSession.cpp
@@ -34,10 +34,21 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/Utils.h>
 
 namespace android {
 
+static uint16_t U16_AT(const uint8_t *ptr) {
+    return ptr[0] << 8 | ptr[1];
+}
+
+static uint32_t U32_AT(const uint8_t *ptr) {
+    return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3];
+}
+
+static uint64_t U64_AT(const uint8_t *ptr) {
+    return ((uint64_t)U32_AT(ptr)) << 32 | U32_AT(ptr + 4);
+}
+
 static const size_t kMaxUDPSize = 1500;
 static const int32_t kMaxUDPRetries = 200;
 
@@ -56,6 +67,12 @@
 };
 
 struct ANetworkSession::Session : public RefBase {
+    enum Mode {
+        MODE_RTSP,
+        MODE_DATAGRAM,
+        MODE_WEBSOCKET,
+    };
+
     enum State {
         CONNECTING,
         CONNECTED,
@@ -85,7 +102,9 @@
     status_t sendRequest(
             const void *data, ssize_t size, bool timeValid, int64_t timeUs);
 
-    void setIsRTSPConnection(bool yesno);
+    void setMode(Mode mode);
+
+    status_t switchToWebSocketMode();
 
 protected:
     virtual ~Session();
@@ -102,7 +121,7 @@
 
     int32_t mSessionID;
     State mState;
-    bool mIsRTSPConnection;
+    Mode mMode;
     int mSocket;
     sp<AMessage> mNotify;
     bool mSawReceiveFailure, mSawSendFailure;
@@ -145,7 +164,7 @@
         const sp<AMessage> &notify)
     : mSessionID(sessionID),
       mState(state),
-      mIsRTSPConnection(false),
+      mMode(MODE_DATAGRAM),
       mSocket(s),
       mNotify(notify),
       mSawReceiveFailure(false),
@@ -209,8 +228,18 @@
     return mSocket;
 }
 
-void ANetworkSession::Session::setIsRTSPConnection(bool yesno) {
-    mIsRTSPConnection = yesno;
+void ANetworkSession::Session::setMode(Mode mode) {
+    mMode = mode;
+}
+
+status_t ANetworkSession::Session::switchToWebSocketMode() {
+    if (mState != CONNECTED || mMode != MODE_RTSP) {
+        return INVALID_OPERATION;
+    }
+
+    mMode = MODE_WEBSOCKET;
+
+    return OK;
 }
 
 sp<AMessage> ANetworkSession::Session::getNotificationMessage() const {
@@ -238,6 +267,8 @@
 
 status_t ANetworkSession::Session::readMore() {
     if (mState == DATAGRAM) {
+        CHECK_EQ(mMode, MODE_DATAGRAM);
+
         status_t err;
         do {
             sp<ABuffer> buf = new ABuffer(kMaxUDPSize);
@@ -326,7 +357,7 @@
         err = -ECONNRESET;
     }
 
-    if (!mIsRTSPConnection) {
+    if (mMode == MODE_DATAGRAM) {
         // TCP stream carrying 16-bit length-prefixed datagrams.
 
         while (mInBuffer.size() >= 2) {
@@ -350,7 +381,7 @@
 
             mInBuffer.erase(0, packetSize + 2);
         }
-    } else {
+    } else if (mMode == MODE_RTSP) {
         for (;;) {
             size_t length;
 
@@ -417,6 +448,69 @@
                 break;
             }
         }
+    } else {
+        CHECK_EQ(mMode, MODE_WEBSOCKET);
+
+        const uint8_t *data = (const uint8_t *)mInBuffer.c_str();
+        // hexdump(data, mInBuffer.size());
+
+        while (mInBuffer.size() >= 2) {
+            size_t offset = 2;
+
+            unsigned payloadLen = data[1] & 0x7f;
+            if (payloadLen == 126) {
+                if (offset + 2 > mInBuffer.size()) {
+                    break;
+                }
+
+                payloadLen = U16_AT(&data[offset]);
+                offset += 2;
+            } else if (payloadLen == 127) {
+                if (offset + 8 > mInBuffer.size()) {
+                    break;
+                }
+
+                payloadLen = U64_AT(&data[offset]);
+                offset += 8;
+            }
+
+            uint32_t mask = 0;
+            if (data[1] & 0x80) {
+                // MASK==1
+                if (offset + 4 > mInBuffer.size()) {
+                    break;
+                }
+
+                mask = U32_AT(&data[offset]);
+                offset += 4;
+            }
+
+            if (offset + payloadLen > mInBuffer.size()) {
+                break;
+            }
+
+            // We have the full message.
+
+            sp<ABuffer> packet = new ABuffer(payloadLen);
+            memcpy(packet->data(), &data[offset], payloadLen);
+
+            if (mask != 0) {
+                for (size_t i = 0; i < payloadLen; ++i) {
+                    packet->data()[i] =
+                        data[offset + i]
+                            ^ ((mask >> (8 * (3 - (i % 4)))) & 0xff);
+                }
+            }
+
+            sp<AMessage> notify = mNotify->dup();
+            notify->setInt32("sessionID", mSessionID);
+            notify->setInt32("reason", kWhatWebSocketMessage);
+            notify->setBuffer("data", packet);
+            notify->setInt32("headerByte", data[0]);
+            notify->post();
+
+            mInBuffer.erase(0, offset + payloadLen);
+        }
     }
 
     if (err != OK) {
@@ -608,13 +702,61 @@
 
     sp<ABuffer> buffer;
 
-    if (mState == CONNECTED && !mIsRTSPConnection) {
+    if (mState == CONNECTED && mMode == MODE_DATAGRAM) {
         CHECK_LE(size, 65535);
 
         buffer = new ABuffer(size + 2);
         buffer->data()[0] = size >> 8;
         buffer->data()[1] = size & 0xff;
         memcpy(buffer->data() + 2, data, size);
+    } else if (mState == CONNECTED && mMode == MODE_WEBSOCKET) {
+        static const bool kUseMask = false;  // Chromium doesn't like it.
+
+        size_t numHeaderBytes = 2 + (kUseMask ? 4 : 0);
+        if (size > 65535) {
+            numHeaderBytes += 8;
+        } else if (size > 125) {
+            numHeaderBytes += 2;
+        }
+
+        buffer = new ABuffer(numHeaderBytes + size);
+        buffer->data()[0] = 0x81;  // FIN==1 | opcode=1 (text)
+        buffer->data()[1] = kUseMask ? 0x80 : 0x00;
+
+        if (size > 65535) {
+            buffer->data()[1] |= 127;
+            buffer->data()[2] = 0x00;
+            buffer->data()[3] = 0x00;
+            buffer->data()[4] = 0x00;
+            buffer->data()[5] = 0x00;
+            buffer->data()[6] = (size >> 24) & 0xff;
+            buffer->data()[7] = (size >> 16) & 0xff;
+            buffer->data()[8] = (size >> 8) & 0xff;
+            buffer->data()[9] = size & 0xff;
+        } else if (size > 125) {
+            buffer->data()[1] |= 126;
+            buffer->data()[2] = (size >> 8) & 0xff;
+            buffer->data()[3] = size & 0xff;
+        } else {
+            buffer->data()[1] |= size;
+        }
+
+        if (kUseMask) {
+            uint32_t mask = rand();
+
+            buffer->data()[numHeaderBytes - 4] = (mask >> 24) & 0xff;
+            buffer->data()[numHeaderBytes - 3] = (mask >> 16) & 0xff;
+            buffer->data()[numHeaderBytes - 2] = (mask >> 8) & 0xff;
+            buffer->data()[numHeaderBytes - 1] = mask & 0xff;
+
+            for (size_t i = 0; i < (size_t)size; ++i) {
+                buffer->data()[numHeaderBytes + i] =
+                    ((const uint8_t *)data)[i]
+                        ^ ((mask >> (8 * (3 - (i % 4)))) & 0xff);
+            }
+        } else {
+            memcpy(buffer->data() + numHeaderBytes, data, size);
+        }
     } else {
         buffer = new ABuffer(size);
         memcpy(buffer->data(), data, size);
@@ -1001,9 +1143,9 @@
             notify);
 
     if (mode == kModeCreateTCPDatagramSessionActive) {
-        session->setIsRTSPConnection(false);
+        session->setMode(Session::MODE_DATAGRAM);
     } else if (mode == kModeCreateRTSPClient) {
-        session->setIsRTSPConnection(true);
+        session->setMode(Session::MODE_RTSP);
     }
 
     mSessions.add(session->sessionID(), session);
@@ -1080,6 +1222,19 @@
     return err;
 }
 
+status_t ANetworkSession::switchToWebSocketMode(int32_t sessionID) {
+    Mutex::Autolock autoLock(mLock);
+
+    ssize_t index = mSessions.indexOfKey(sessionID);
+
+    if (index < 0) {
+        return -ENOENT;
+    }
+
+    const sp<Session> session = mSessions.valueAt(index);
+    return session->switchToWebSocketMode();
+}
+
 void ANetworkSession::interrupt() {
     static const char dummy = 0;
 
@@ -1213,8 +1368,10 @@
                                         clientSocket,
                                         session->getNotificationMessage());
 
-                            clientSession->setIsRTSPConnection(
-                                    session->isRTSPServer());
+                            clientSession->setMode(
+                                    session->isRTSPServer()
+                                        ? Session::MODE_RTSP
+                                        : Session::MODE_DATAGRAM);
 
                             sessionsToAdd.push_back(clientSession);
                         }
diff --git a/media/libstagefright/foundation/Android.mk b/media/libstagefright/foundation/Android.mk
index d65e213..ad2dab5 100644
--- a/media/libstagefright/foundation/Android.mk
+++ b/media/libstagefright/foundation/Android.mk
@@ -10,7 +10,9 @@
     ALooper.cpp                   \
     ALooperRoster.cpp             \
     AMessage.cpp                  \
+    ANetworkSession.cpp           \
     AString.cpp                   \
+    ParsedMessage.cpp             \
     base64.cpp                    \
     hexdump.cpp
 
diff --git a/media/libstagefright/wifi-display/ParsedMessage.cpp b/media/libstagefright/foundation/ParsedMessage.cpp
similarity index 89%
rename from media/libstagefright/wifi-display/ParsedMessage.cpp
rename to media/libstagefright/foundation/ParsedMessage.cpp
index c0e60c3..049c9ad 100644
--- a/media/libstagefright/wifi-display/ParsedMessage.cpp
+++ b/media/libstagefright/foundation/ParsedMessage.cpp
@@ -19,6 +19,7 @@
 #include <ctype.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/hexdump.h>
 
 namespace android {
 
@@ -89,6 +90,7 @@
     ssize_t lastDictIndex = -1;
 
     size_t offset = 0;
+    bool headersComplete = false;
     while (offset < size) {
         size_t lineEndOffset = offset;
         while (lineEndOffset + 1 < size
@@ -113,6 +115,8 @@
         }
 
         if (lineEndOffset == offset) {
+            // An empty line separates headers from body.
+            headersComplete = true;
             offset += 2;
             break;
         }
@@ -146,12 +150,17 @@
         offset = lineEndOffset + 2;
     }
 
+    if (!headersComplete && (!noMoreData || offset == 0)) {
+        // We either saw the empty line separating headers from body
+        // or we saw at least the status line and know that no more data
+        // is going to follow.
+        return -1;
+    }
+
     for (size_t i = 0; i < mDict.size(); ++i) {
         mDict.editValueAt(i).trim();
     }
 
-    // Found the end of headers.
-
     int32_t contentLength;
     if (!findInt32("content-length", &contentLength) || contentLength < 0) {
         contentLength = 0;
@@ -168,13 +177,17 @@
     return totalLength;
 }
 
-void ParsedMessage::getRequestField(size_t index, AString *field) const {
+bool ParsedMessage::getRequestField(size_t index, AString *field) const {
     AString line;
     CHECK(findString("_", &line));
 
     size_t prevOffset = 0;
     size_t offset = 0;
     for (size_t i = 0; i <= index; ++i) {
+        if (offset >= line.size()) {
+            return false;
+        }
+
         ssize_t spacePos = line.find(" ", offset);
 
         if (spacePos < 0) {
@@ -186,11 +199,16 @@
     }
 
     field->setTo(line, prevOffset, offset - prevOffset - 1);
+
+    return true;
 }
 
 bool ParsedMessage::getStatusCode(int32_t *statusCode) const {
     AString statusCodeString;
-    getRequestField(1, &statusCodeString);
+    if (!getRequestField(1, &statusCodeString)) {
+        *statusCode = 0;
+        return false;
+    }
 
     char *end;
     *statusCode = strtol(statusCodeString.c_str(), &end, 10);
diff --git a/media/libstagefright/include/OMX.h b/media/libstagefright/include/OMX.h
index 24b8d98..7fed7d4 100644
--- a/media/libstagefright/include/OMX.h
+++ b/media/libstagefright/include/OMX.h
@@ -109,6 +109,13 @@
             const char *parameter_name,
             OMX_INDEXTYPE *index);
 
+    virtual status_t setInternalOption(
+            node_id node,
+            OMX_U32 port_index,
+            InternalOptionType type,
+            const void *data,
+            size_t size);
+
     virtual void binderDied(const wp<IBinder> &the_late_who);
 
     OMX_ERRORTYPE OnEvent(
diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h
index 67aba6b..f6ae376 100644
--- a/media/libstagefright/include/OMXNodeInstance.h
+++ b/media/libstagefright/include/OMXNodeInstance.h
@@ -96,6 +96,12 @@
     status_t getExtensionIndex(
             const char *parameterName, OMX_INDEXTYPE *index);
 
+    status_t setInternalOption(
+            OMX_U32 portIndex,
+            IOMX::InternalOptionType type,
+            const void *data,
+            size_t size);
+
     void onMessage(const omx_message &msg);
     void onObserverDied(OMXMaster *master);
     void onGetHandleFailed();
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index b3167b5..bbd71be 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -18,12 +18,12 @@
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
-#include <GraphicBufferSource.h>
+#include "GraphicBufferSource.h"
 
 #include <OMX_Core.h>
 #include <media/stagefright/foundation/ADebug.h>
 
-#include <MetadataBufferType.h>
+#include <media/hardware/MetadataBufferType.h>
 #include <ui/GraphicBuffer.h>
 
 namespace android {
@@ -36,6 +36,7 @@
     mInitCheck(UNKNOWN_ERROR),
     mNodeInstance(nodeInstance),
     mExecuting(false),
+    mSuspended(false),
     mNumFramesAvailable(0),
     mEndOfStream(false),
     mEndOfStreamSent(false) {
@@ -51,10 +52,9 @@
 
     String8 name("GraphicBufferSource");
 
-    mBufferQueue = new BufferQueue(true);
+    mBufferQueue = new BufferQueue();
     mBufferQueue->setConsumerName(name);
     mBufferQueue->setDefaultBufferSize(bufferWidth, bufferHeight);
-    mBufferQueue->setSynchronousMode(true);
     mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER |
             GRALLOC_USAGE_HW_TEXTURE);
 
@@ -75,7 +75,7 @@
     sp<BufferQueue::ConsumerListener> proxy;
     proxy = new BufferQueue::ProxyConsumerListener(listener);
 
-    mInitCheck = mBufferQueue->consumerConnect(proxy);
+    mInitCheck = mBufferQueue->consumerConnect(proxy, false);
     if (mInitCheck != NO_ERROR) {
         ALOGE("Error connecting to BufferQueue: %s (%d)",
                 strerror(-mInitCheck), mInitCheck);
@@ -237,9 +237,43 @@
     return;
 }
 
+void GraphicBufferSource::suspend(bool suspend) {
+    Mutex::Autolock autoLock(mMutex);
+
+    if (suspend) {
+        mSuspended = true;
+
+        while (mNumFramesAvailable > 0) {
+            BufferQueue::BufferItem item;
+            status_t err = mBufferQueue->acquireBuffer(&item, 0);
+
+            if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
+                // shouldn't happen.
+                ALOGW("suspend: frame was not available");
+                break;
+            } else if (err != OK) {
+                ALOGW("suspend: acquireBuffer returned err=%d", err);
+                break;
+            }
+
+            --mNumFramesAvailable;
+
+            mBufferQueue->releaseBuffer(item.mBuf, item.mFrameNumber,
+                    EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, item.mFence);
+        }
+        return;
+    }
+
+    mSuspended = false;
+}
+
 bool GraphicBufferSource::fillCodecBuffer_l() {
     CHECK(mExecuting && mNumFramesAvailable > 0);
 
+    if (mSuspended) {
+        return false;
+    }
+
     int cbi = findAvailableCodecBuffer_l();
     if (cbi < 0) {
         // No buffers available, bail.
@@ -416,10 +450,15 @@
     ALOGV("onFrameAvailable exec=%d avail=%d",
             mExecuting, mNumFramesAvailable);
 
-    if (mEndOfStream) {
-        // This should only be possible if a new buffer was queued after
-        // EOS was signaled, i.e. the app is misbehaving.
-        ALOGW("onFrameAvailable: EOS is set, ignoring frame");
+    if (mEndOfStream || mSuspended) {
+        if (mEndOfStream) {
+            // This should only be possible if a new buffer was queued after
+            // EOS was signaled, i.e. the app is misbehaving.
+
+            ALOGW("onFrameAvailable: EOS is set, ignoring frame");
+        } else {
+            ALOGV("onFrameAvailable: suspended, ignoring frame");
+        }
 
         BufferQueue::BufferItem item;
         status_t err = mBufferQueue->acquireBuffer(&item, 0);
diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h
index 8c6b470..ac73770 100644
--- a/media/libstagefright/omx/GraphicBufferSource.h
+++ b/media/libstagefright/omx/GraphicBufferSource.h
@@ -85,6 +85,10 @@
     // have a codec buffer ready, we just set the mEndOfStream flag.
     status_t signalEndOfInputStream();
 
+    // If suspend is true, all incoming buffers (including those currently
+    // in the BufferQueue) will be discarded until the suspension is lifted.
+    void suspend(bool suspend);
+
 protected:
     // BufferQueue::ConsumerListener interface, called when a new frame of
     // data is available.  If we're executing and a codec buffer is
@@ -155,6 +159,8 @@
     // Set by omxExecuting() / omxIdling().
     bool mExecuting;
 
+    bool mSuspended;
+
     // We consume graphic buffers from this.
     sp<BufferQueue> mBufferQueue;
 
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index 3987ead..4b1dbe6 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -396,6 +396,15 @@
             parameter_name, index);
 }
 
+status_t OMX::setInternalOption(
+        node_id node,
+        OMX_U32 port_index,
+        InternalOptionType type,
+        const void *data,
+        size_t size) {
+    return findInstance(node)->setInternalOption(port_index, type, data, size);
+}
+
 OMX_ERRORTYPE OMX::OnEvent(
         node_id node,
         OMX_IN OMX_EVENTTYPE eEvent,
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index a9eb94f..61a866f 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -238,6 +238,18 @@
 
 status_t OMXNodeInstance::sendCommand(
         OMX_COMMANDTYPE cmd, OMX_S32 param) {
+    const sp<GraphicBufferSource>& bufferSource(getGraphicBufferSource());
+    if (bufferSource != NULL
+            && cmd == OMX_CommandStateSet
+            && param == OMX_StateLoaded) {
+        // Initiating transition from Executing -> Loaded
+        // Buffers are about to be freed.
+        bufferSource->omxLoaded();
+        setGraphicBufferSource(NULL);
+
+        // fall through
+    }
+
     Mutex::Autolock autoLock(mLock);
 
     OMX_ERRORTYPE err = OMX_SendCommand(mHandle, cmd, param, NULL);
@@ -769,6 +781,36 @@
     return StatusFromOMXError(err);
 }
 
+status_t OMXNodeInstance::setInternalOption(
+        OMX_U32 portIndex,
+        IOMX::InternalOptionType type,
+        const void *data,
+        size_t size) {
+    switch (type) {
+        case IOMX::INTERNAL_OPTION_SUSPEND:
+        {
+            const sp<GraphicBufferSource> &bufferSource =
+                getGraphicBufferSource();
+
+            if (bufferSource == NULL || portIndex != kPortIndexInput) {
+                return ERROR_UNSUPPORTED;
+            }
+
+            if (size != sizeof(bool)) {
+                return INVALID_OPERATION;
+            }
+
+            bool suspend = *(bool *)data;
+            bufferSource->suspend(suspend);
+
+            return OK;
+        }
+
+        default:
+            return ERROR_UNSUPPORTED;
+    }
+}
+
 void OMXNodeInstance::onMessage(const omx_message &msg) {
     if (msg.type == omx_message::FILL_BUFFER_DONE) {
         OMX_BUFFERHEADERTYPE *buffer =
@@ -818,16 +860,11 @@
         OMX_EVENTTYPE event, OMX_U32 arg1, OMX_U32 arg2) {
     const sp<GraphicBufferSource>& bufferSource(getGraphicBufferSource());
 
-    if (bufferSource != NULL && event == OMX_EventCmdComplete &&
-            arg1 == OMX_CommandStateSet) {
-        if (arg2 == OMX_StateExecuting) {
-            bufferSource->omxExecuting();
-        } else if (arg2 == OMX_StateLoaded) {
-            // Must be shutting down -- won't have a GraphicBufferSource
-            // on the way up.
-            bufferSource->omxLoaded();
-            setGraphicBufferSource(NULL);
-        }
+    if (bufferSource != NULL
+            && event == OMX_EventCmdComplete
+            && arg1 == OMX_CommandStateSet
+            && arg2 == OMX_StateExecuting) {
+        bufferSource->omxExecuting();
     }
 }
 
diff --git a/media/libstagefright/wifi-display/Android.mk b/media/libstagefright/wifi-display/Android.mk
index 404b41e..c7d107e 100644
--- a/media/libstagefright/wifi-display/Android.mk
+++ b/media/libstagefright/wifi-display/Android.mk
@@ -3,11 +3,9 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-        ANetworkSession.cpp             \
         MediaReceiver.cpp               \
         MediaSender.cpp                 \
         Parameters.cpp                  \
-        ParsedMessage.cpp               \
         rtp/RTPAssembler.cpp            \
         rtp/RTPReceiver.cpp             \
         rtp/RTPSender.cpp               \
diff --git a/media/libstagefright/wifi-display/MediaReceiver.cpp b/media/libstagefright/wifi-display/MediaReceiver.cpp
index 364acb9..5524235 100644
--- a/media/libstagefright/wifi-display/MediaReceiver.cpp
+++ b/media/libstagefright/wifi-display/MediaReceiver.cpp
@@ -20,13 +20,13 @@
 
 #include "MediaReceiver.h"
 
-#include "ANetworkSession.h"
 #include "AnotherPacketSource.h"
 #include "rtp/RTPReceiver.h"
 
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/ANetworkSession.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
 
diff --git a/media/libstagefright/wifi-display/MediaSender.cpp b/media/libstagefright/wifi-display/MediaSender.cpp
index a230cd8..b1cdec0 100644
--- a/media/libstagefright/wifi-display/MediaSender.cpp
+++ b/media/libstagefright/wifi-display/MediaSender.cpp
@@ -20,7 +20,6 @@
 
 #include "MediaSender.h"
 
-#include "ANetworkSession.h"
 #include "rtp/RTPSender.h"
 #include "source/TSPacketizer.h"
 
@@ -31,6 +30,7 @@
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/ANetworkSession.h>
 #include <ui/GraphicBuffer.h>
 
 namespace android {
diff --git a/media/libstagefright/wifi-display/TimeSyncer.cpp b/media/libstagefright/wifi-display/TimeSyncer.cpp
index cb429bc..0f4d93a 100644
--- a/media/libstagefright/wifi-display/TimeSyncer.cpp
+++ b/media/libstagefright/wifi-display/TimeSyncer.cpp
@@ -20,13 +20,12 @@
 
 #include "TimeSyncer.h"
 
-#include "ANetworkSession.h"
-
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AHandler.h>
 #include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/ANetworkSession.h>
 #include <media/stagefright/Utils.h>
 
 namespace android {
diff --git a/media/libstagefright/wifi-display/nettest.cpp b/media/libstagefright/wifi-display/nettest.cpp
index 0779bf5..73c0d80 100644
--- a/media/libstagefright/wifi-display/nettest.cpp
+++ b/media/libstagefright/wifi-display/nettest.cpp
@@ -18,7 +18,6 @@
 #define LOG_TAG "nettest"
 #include <utils/Log.h>
 
-#include "ANetworkSession.h"
 #include "TimeSyncer.h"
 
 #include <binder/ProcessState.h>
@@ -27,6 +26,7 @@
 #include <media/stagefright/foundation/AHandler.h>
 #include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/ANetworkSession.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaDefs.h>
diff --git a/media/libstagefright/wifi-display/rtp/RTPReceiver.cpp b/media/libstagefright/wifi-display/rtp/RTPReceiver.cpp
index 2d22e79..3b3bd63 100644
--- a/media/libstagefright/wifi-display/rtp/RTPReceiver.cpp
+++ b/media/libstagefright/wifi-display/rtp/RTPReceiver.cpp
@@ -21,11 +21,10 @@
 #include "RTPAssembler.h"
 #include "RTPReceiver.h"
 
-#include "ANetworkSession.h"
-
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/ANetworkSession.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/Utils.h>
diff --git a/media/libstagefright/wifi-display/rtp/RTPSender.cpp b/media/libstagefright/wifi-display/rtp/RTPSender.cpp
index 6bbe650..1887b8b 100644
--- a/media/libstagefright/wifi-display/rtp/RTPSender.cpp
+++ b/media/libstagefright/wifi-display/rtp/RTPSender.cpp
@@ -20,11 +20,10 @@
 
 #include "RTPSender.h"
 
-#include "ANetworkSession.h"
-
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/ANetworkSession.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/Utils.h>
diff --git a/media/libstagefright/wifi-display/rtptest.cpp b/media/libstagefright/wifi-display/rtptest.cpp
index 764a38b..b902f29 100644
--- a/media/libstagefright/wifi-display/rtptest.cpp
+++ b/media/libstagefright/wifi-display/rtptest.cpp
@@ -18,7 +18,6 @@
 #define LOG_TAG "rtptest"
 #include <utils/Log.h>
 
-#include "ANetworkSession.h"
 #include "rtp/RTPSender.h"
 #include "rtp/RTPReceiver.h"
 #include "TimeSyncer.h"
@@ -29,6 +28,7 @@
 #include <media/stagefright/foundation/AHandler.h>
 #include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/ANetworkSession.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaDefs.h>
diff --git a/media/libstagefright/wifi-display/sink/DirectRenderer.cpp b/media/libstagefright/wifi-display/sink/DirectRenderer.cpp
index 15f9c88..cdb2267 100644
--- a/media/libstagefright/wifi-display/sink/DirectRenderer.cpp
+++ b/media/libstagefright/wifi-display/sink/DirectRenderer.cpp
@@ -29,9 +29,8 @@
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/Utils.h>
 
 namespace android {
 
@@ -488,12 +487,38 @@
             break;
         }
 
+        case kWhatQueueAccessUnit:
+            onQueueAccessUnit(msg);
+            break;
+
+        case kWhatSetFormat:
+            onSetFormat(msg);
+            break;
+
         default:
             TRESPASS();
     }
 }
 
 void DirectRenderer::setFormat(size_t trackIndex, const sp<AMessage> &format) {
+    sp<AMessage> msg = new AMessage(kWhatSetFormat, id());
+    msg->setSize("trackIndex", trackIndex);
+    msg->setMessage("format", format);
+    msg->post();
+}
+
+void DirectRenderer::onSetFormat(const sp<AMessage> &msg) {
+    size_t trackIndex;
+    CHECK(msg->findSize("trackIndex", &trackIndex));
+
+    sp<AMessage> format;
+    CHECK(msg->findMessage("format", &format));
+
+    internalSetFormat(trackIndex, format);
+}
+
+void DirectRenderer::internalSetFormat(
+        size_t trackIndex, const sp<AMessage> &format) {
     CHECK_LT(trackIndex, 2u);
 
     CHECK(mDecoderContext[trackIndex] == NULL);
@@ -517,18 +542,21 @@
 
 void DirectRenderer::queueAccessUnit(
         size_t trackIndex, const sp<ABuffer> &accessUnit) {
+    sp<AMessage> msg = new AMessage(kWhatQueueAccessUnit, id());
+    msg->setSize("trackIndex", trackIndex);
+    msg->setBuffer("accessUnit", accessUnit);
+    msg->post();
+}
+
+void DirectRenderer::onQueueAccessUnit(const sp<AMessage> &msg) {
+    size_t trackIndex;
+    CHECK(msg->findSize("trackIndex", &trackIndex));
+
+    sp<ABuffer> accessUnit;
+    CHECK(msg->findBuffer("accessUnit", &accessUnit));
+
     CHECK_LT(trackIndex, 2u);
-
-    if (mDecoderContext[trackIndex] == NULL) {
-        CHECK_EQ(trackIndex, 0u);
-
-        sp<AMessage> format = new AMessage;
-        format->setString("mime", "video/avc");
-        format->setInt32("width", 640);
-        format->setInt32("height", 360);
-
-        setFormat(trackIndex, format);
-    }
+    CHECK(mDecoderContext[trackIndex] != NULL);
 
     mDecoderContext[trackIndex]->queueInputBuffer(accessUnit);
 }
diff --git a/media/libstagefright/wifi-display/sink/DirectRenderer.h b/media/libstagefright/wifi-display/sink/DirectRenderer.h
index 1e7dc34..07c2170 100644
--- a/media/libstagefright/wifi-display/sink/DirectRenderer.h
+++ b/media/libstagefright/wifi-display/sink/DirectRenderer.h
@@ -43,6 +43,8 @@
     enum {
         kWhatDecoderNotify,
         kWhatRenderVideo,
+        kWhatQueueAccessUnit,
+        kWhatSetFormat,
     };
 
     struct OutputInfo {
@@ -72,6 +74,11 @@
     void scheduleVideoRenderIfNecessary();
     void onRenderVideo();
 
+    void onSetFormat(const sp<AMessage> &msg);
+    void onQueueAccessUnit(const sp<AMessage> &msg);
+
+    void internalSetFormat(size_t trackIndex, const sp<AMessage> &format);
+
     DISALLOW_EVIL_CONSTRUCTORS(DirectRenderer);
 };
 
diff --git a/media/libstagefright/wifi-display/sink/WifiDisplaySink.cpp b/media/libstagefright/wifi-display/sink/WifiDisplaySink.cpp
index 5db2099..bc88f1e 100644
--- a/media/libstagefright/wifi-display/sink/WifiDisplaySink.cpp
+++ b/media/libstagefright/wifi-display/sink/WifiDisplaySink.cpp
@@ -22,13 +22,13 @@
 
 #include "DirectRenderer.h"
 #include "MediaReceiver.h"
-#include "ParsedMessage.h"
 #include "TimeSyncer.h"
 
 #include <cutils/properties.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/ParsedMessage.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/Utils.h>
 
diff --git a/media/libstagefright/wifi-display/sink/WifiDisplaySink.h b/media/libstagefright/wifi-display/sink/WifiDisplaySink.h
index adb9d89..dc1fc32 100644
--- a/media/libstagefright/wifi-display/sink/WifiDisplaySink.h
+++ b/media/libstagefright/wifi-display/sink/WifiDisplaySink.h
@@ -18,12 +18,11 @@
 
 #define WIFI_DISPLAY_SINK_H_
 
-#include "ANetworkSession.h"
-
 #include "VideoFormats.h"
 
 #include <gui/Surface.h>
 #include <media/stagefright/foundation/AHandler.h>
+#include <media/stagefright/foundation/ANetworkSession.h>
 
 namespace android {
 
diff --git a/media/libstagefright/wifi-display/source/Converter.cpp b/media/libstagefright/wifi-display/source/Converter.cpp
index 0214520..6f23854 100644
--- a/media/libstagefright/wifi-display/source/Converter.cpp
+++ b/media/libstagefright/wifi-display/source/Converter.cpp
@@ -21,6 +21,7 @@
 #include "Converter.h"
 
 #include "MediaPuller.h"
+#include "include/avc_utils.h"
 
 #include <cutils/properties.h>
 #include <gui/Surface.h>
@@ -33,6 +34,8 @@
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 
+#include <arpa/inet.h>
+
 #include <OMX_Video.h>
 
 namespace android {
@@ -40,12 +43,14 @@
 Converter::Converter(
         const sp<AMessage> &notify,
         const sp<ALooper> &codecLooper,
-        const sp<AMessage> &outputFormat)
-    : mInitCheck(NO_INIT),
-      mNotify(notify),
+        const sp<AMessage> &outputFormat,
+        uint32_t flags)
+    : mNotify(notify),
       mCodecLooper(codecLooper),
       mOutputFormat(outputFormat),
+      mFlags(flags),
       mIsVideo(false),
+      mIsH264(false),
       mIsPCMAudio(false),
       mNeedToManuallyPrependSPSPPS(false),
       mDoMoreWorkPending(false)
@@ -55,21 +60,18 @@
 #endif
       ,mPrevVideoBitrate(-1)
       ,mNumFramesToDrop(0)
+      ,mEncodingSuspended(false)
     {
     AString mime;
     CHECK(mOutputFormat->findString("mime", &mime));
 
     if (!strncasecmp("video/", mime.c_str(), 6)) {
         mIsVideo = true;
+
+        mIsH264 = !strcasecmp(mime.c_str(), MEDIA_MIMETYPE_VIDEO_AVC);
     } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_RAW, mime.c_str())) {
         mIsPCMAudio = true;
     }
-
-    mInitCheck = initEncoder();
-
-    if (mInitCheck != OK) {
-        releaseEncoder();
-    }
 }
 
 static void ReleaseMediaBufferReference(const sp<ABuffer> &accessUnit) {
@@ -118,8 +120,19 @@
     (new AMessage(kWhatShutdown, id()))->post();
 }
 
-status_t Converter::initCheck() const {
-    return mInitCheck;
+status_t Converter::init() {
+    status_t err = initEncoder();
+
+    if (err != OK) {
+        releaseEncoder();
+    }
+
+    return err;
+}
+
+sp<IGraphicBufferProducer> Converter::getGraphicBufferProducer() {
+    CHECK(mFlags & FLAG_USE_SURFACE_INPUT);
+    return mGraphicBufferProducer;
 }
 
 size_t Converter::getInputBufferCount() const {
@@ -244,6 +257,16 @@
         return err;
     }
 
+    if (mFlags & FLAG_USE_SURFACE_INPUT) {
+        CHECK(mIsVideo);
+
+        err = mEncoder->createInputSurface(&mGraphicBufferProducer);
+
+        if (err != OK) {
+            return err;
+        }
+    }
+
     err = mEncoder->start();
 
     if (err != OK) {
@@ -256,7 +279,17 @@
         return err;
     }
 
-    return mEncoder->getOutputBuffers(&mEncoderOutputBuffers);
+    err = mEncoder->getOutputBuffers(&mEncoderOutputBuffers);
+
+    if (err != OK) {
+        return err;
+    }
+
+    if (mFlags & FLAG_USE_SURFACE_INPUT) {
+        scheduleDoMoreWork();
+    }
+
+    return OK;
 }
 
 void Converter::notifyError(status_t err) {
@@ -312,9 +345,12 @@
                 sp<ABuffer> accessUnit;
                 CHECK(msg->findBuffer("accessUnit", &accessUnit));
 
-                if (mIsVideo && mNumFramesToDrop) {
-                    --mNumFramesToDrop;
-                    ALOGI("dropping frame.");
+                if (mNumFramesToDrop > 0 || mEncodingSuspended) {
+                    if (mNumFramesToDrop > 0) {
+                        --mNumFramesToDrop;
+                        ALOGI("dropping frame.");
+                    }
+
                     ReleaseMediaBufferReference(accessUnit);
                     break;
                 }
@@ -396,7 +432,7 @@
             }
 
             if (mIsVideo) {
-                ALOGI("requesting IDR frame");
+                ALOGV("requesting IDR frame");
                 mEncoder->requestIDRFrame();
             }
             break;
@@ -411,6 +447,10 @@
             AString mime;
             CHECK(mOutputFormat->findString("mime", &mime));
             ALOGI("encoder (%s) shut down.", mime.c_str());
+
+            sp<AMessage> notify = mNotify->dup();
+            notify->setInt32("what", kWhatShutdownCompleted);
+            notify->post();
             break;
         }
 
@@ -431,6 +471,21 @@
             break;
         }
 
+        case kWhatSuspendEncoding:
+        {
+            int32_t suspend;
+            CHECK(msg->findInt32("suspend", &suspend));
+
+            mEncodingSuspended = suspend;
+
+            if (mFlags & FLAG_USE_SURFACE_INPUT) {
+                sp<AMessage> params = new AMessage;
+                params->setInt32("drop-input-frames",suspend);
+                mEncoder->setParameters(params);
+            }
+            break;
+        }
+
         default:
             TRESPASS();
     }
@@ -616,22 +671,39 @@
     return OK;
 }
 
+sp<ABuffer> Converter::prependCSD(const sp<ABuffer> &accessUnit) const {
+    CHECK(mCSD0 != NULL);
+
+    sp<ABuffer> dup = new ABuffer(accessUnit->size() + mCSD0->size());
+    memcpy(dup->data(), mCSD0->data(), mCSD0->size());
+    memcpy(dup->data() + mCSD0->size(), accessUnit->data(), accessUnit->size());
+
+    int64_t timeUs;
+    CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
+
+    dup->meta()->setInt64("timeUs", timeUs);
+
+    return dup;
+}
+
 status_t Converter::doMoreWork() {
     status_t err;
 
-    for (;;) {
-        size_t bufferIndex;
-        err = mEncoder->dequeueInputBuffer(&bufferIndex);
+    if (!(mFlags & FLAG_USE_SURFACE_INPUT)) {
+        for (;;) {
+            size_t bufferIndex;
+            err = mEncoder->dequeueInputBuffer(&bufferIndex);
 
-        if (err != OK) {
-            break;
+            if (err != OK) {
+                break;
+            }
+
+            mAvailEncoderInputIndices.push_back(bufferIndex);
         }
 
-        mAvailEncoderInputIndices.push_back(bufferIndex);
+        feedEncoderInputBuffers();
     }
 
-    feedEncoderInputBuffers();
-
     for (;;) {
         size_t bufferIndex;
         size_t offset;
@@ -705,9 +777,19 @@
 
             if (flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) {
                 if (!handle) {
+                    if (mIsH264) {
+                        mCSD0 = buffer;
+                    }
                     mOutputFormat->setBuffer("csd-0", buffer);
                 }
             } else {
+                if (mNeedToManuallyPrependSPSPPS
+                        && mIsH264
+                        && (mFlags & FLAG_PREPEND_CSD_IF_NECESSARY)
+                        && IsIDR(buffer)) {
+                    buffer = prependCSD(buffer);
+                }
+
                 sp<AMessage> notify = mNotify->dup();
                 notify->setInt32("what", kWhatAccessUnit);
                 notify->setBuffer("accessUnit", buffer);
@@ -732,9 +814,18 @@
 }
 
 void Converter::dropAFrame() {
+    // Unsupported in surface input mode.
+    CHECK(!(mFlags & FLAG_USE_SURFACE_INPUT));
+
     (new AMessage(kWhatDropAFrame, id()))->post();
 }
 
+void Converter::suspendEncoding(bool suspend) {
+    sp<AMessage> msg = new AMessage(kWhatSuspendEncoding, id());
+    msg->setInt32("suspend", suspend);
+    msg->post();
+}
+
 int32_t Converter::getVideoBitrate() const {
     return mPrevVideoBitrate;
 }
diff --git a/media/libstagefright/wifi-display/source/Converter.h b/media/libstagefright/wifi-display/source/Converter.h
index 76c8b19..5876e07 100644
--- a/media/libstagefright/wifi-display/source/Converter.h
+++ b/media/libstagefright/wifi-display/source/Converter.h
@@ -18,13 +18,12 @@
 
 #define CONVERTER_H_
 
-#include "WifiDisplaySource.h"
-
 #include <media/stagefright/foundation/AHandler.h>
 
 namespace android {
 
 struct ABuffer;
+struct IGraphicBufferProducer;
 struct MediaCodec;
 
 #define ENABLE_SILENCE_DETECTION        0
@@ -33,11 +32,25 @@
 // media access unit of a different format.
 // Right now this'll convert raw video into H.264 and raw audio into AAC.
 struct Converter : public AHandler {
+    enum {
+        kWhatAccessUnit,
+        kWhatEOS,
+        kWhatError,
+        kWhatShutdownCompleted,
+    };
+
+    enum FlagBits {
+        FLAG_USE_SURFACE_INPUT          = 1,
+        FLAG_PREPEND_CSD_IF_NECESSARY   = 2,
+    };
     Converter(const sp<AMessage> &notify,
               const sp<ALooper> &codecLooper,
-              const sp<AMessage> &outputFormat);
+              const sp<AMessage> &outputFormat,
+              uint32_t flags = 0);
 
-    status_t initCheck() const;
+    status_t init();
+
+    sp<IGraphicBufferProducer> getGraphicBufferProducer();
 
     size_t getInputBufferCount() const;
 
@@ -50,22 +63,7 @@
     void requestIDRFrame();
 
     void dropAFrame();
-
-    enum {
-        kWhatAccessUnit,
-        kWhatEOS,
-        kWhatError,
-    };
-
-    enum {
-        kWhatDoMoreWork,
-        kWhatRequestIDRFrame,
-        kWhatShutdown,
-        kWhatMediaPullerNotify,
-        kWhatEncoderActivity,
-        kWhatDropAFrame,
-        kWhatReleaseOutputBuffer,
-    };
+    void suspendEncoding(bool suspend);
 
     void shutdownAsync();
 
@@ -74,22 +72,40 @@
 
     static int32_t GetInt32Property(const char *propName, int32_t defaultValue);
 
+    enum {
+        // MUST not conflict with private enums below.
+        kWhatMediaPullerNotify = 'pulN',
+    };
+
 protected:
     virtual ~Converter();
     virtual void onMessageReceived(const sp<AMessage> &msg);
 
 private:
-    status_t mInitCheck;
+    enum {
+        kWhatDoMoreWork,
+        kWhatRequestIDRFrame,
+        kWhatSuspendEncoding,
+        kWhatShutdown,
+        kWhatEncoderActivity,
+        kWhatDropAFrame,
+        kWhatReleaseOutputBuffer,
+    };
+
     sp<AMessage> mNotify;
     sp<ALooper> mCodecLooper;
     sp<AMessage> mOutputFormat;
+    uint32_t mFlags;
     bool mIsVideo;
+    bool mIsH264;
     bool mIsPCMAudio;
     bool mNeedToManuallyPrependSPSPPS;
 
     sp<MediaCodec> mEncoder;
     sp<AMessage> mEncoderActivityNotify;
 
+    sp<IGraphicBufferProducer> mGraphicBufferProducer;
+
     Vector<sp<ABuffer> > mEncoderInputBuffers;
     Vector<sp<ABuffer> > mEncoderOutputBuffers;
 
@@ -97,6 +113,8 @@
 
     List<sp<ABuffer> > mInputBufferQueue;
 
+    sp<ABuffer> mCSD0;
+
     bool mDoMoreWorkPending;
 
 #if ENABLE_SILENCE_DETECTION
@@ -109,6 +127,7 @@
     int32_t mPrevVideoBitrate;
 
     int32_t mNumFramesToDrop;
+    bool mEncodingSuspended;
 
     status_t initEncoder();
     void releaseEncoder();
@@ -127,6 +146,8 @@
 
     static bool IsSilence(const sp<ABuffer> &accessUnit);
 
+    sp<ABuffer> prependCSD(const sp<ABuffer> &accessUnit) const;
+
     DISALLOW_EVIL_CONSTRUCTORS(Converter);
 };
 
diff --git a/media/libstagefright/wifi-display/source/MediaPuller.cpp b/media/libstagefright/wifi-display/source/MediaPuller.cpp
index 189bea3..7e8891d 100644
--- a/media/libstagefright/wifi-display/source/MediaPuller.cpp
+++ b/media/libstagefright/wifi-display/source/MediaPuller.cpp
@@ -93,6 +93,9 @@
                 err = mSource->start(params.get());
             } else {
                 err = mSource->start();
+                if (err != OK) {
+                    ALOGE("source failed to start w/ err %d", err);
+                }
             }
 
             if (err == OK) {
diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.cpp b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
index a15fbac..0aa4ee5 100644
--- a/media/libstagefright/wifi-display/source/PlaybackSession.cpp
+++ b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
@@ -521,7 +521,7 @@
                 if (mTracks.isEmpty()) {
                     ALOGI("Reached EOS");
                 }
-            } else {
+            } else if (what != Converter::kWhatShutdownCompleted) {
                 CHECK_EQ(what, Converter::kWhatError);
 
                 status_t err;
@@ -957,14 +957,16 @@
 
     sp<Converter> converter = new Converter(notify, codecLooper, format);
 
-    err = converter->initCheck();
+    looper()->registerHandler(converter);
+
+    err = converter->init();
     if (err != OK) {
         ALOGE("%s converter returned err %d", isVideo ? "video" : "audio", err);
+
+        looper()->unregisterHandler(converter->id());
         return err;
     }
 
-    looper()->registerHandler(converter);
-
     notify = new AMessage(Converter::kWhatMediaPullerNotify, converter->id());
     notify->setSize("trackIndex", trackIndex);
 
diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
index b421b35..4b59e62 100644
--- a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
+++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
@@ -21,7 +21,6 @@
 #include "WifiDisplaySource.h"
 #include "PlaybackSession.h"
 #include "Parameters.h"
-#include "ParsedMessage.h"
 #include "rtp/RTPSender.h"
 #include "TimeSyncer.h"
 
@@ -33,6 +32,7 @@
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/ParsedMessage.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/Utils.h>
 
diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.h b/media/libstagefright/wifi-display/source/WifiDisplaySource.h
index 64186fc..4f11712 100644
--- a/media/libstagefright/wifi-display/source/WifiDisplaySource.h
+++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.h
@@ -18,10 +18,10 @@
 
 #define WIFI_DISPLAY_SOURCE_H_
 
-#include "ANetworkSession.h"
 #include "VideoFormats.h"
 
 #include <media/stagefright/foundation/AHandler.h>
+#include <media/stagefright/foundation/ANetworkSession.h>
 
 #include <netinet/in.h>
 
diff --git a/media/libstagefright/wifi-display/udptest.cpp b/media/libstagefright/wifi-display/udptest.cpp
index 111846d..61eb9f9 100644
--- a/media/libstagefright/wifi-display/udptest.cpp
+++ b/media/libstagefright/wifi-display/udptest.cpp
@@ -18,11 +18,11 @@
 #define LOG_TAG "udptest"
 #include <utils/Log.h>
 
-#include "ANetworkSession.h"
 #include "TimeSyncer.h"
 
 #include <binder/ProcessState.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/ANetworkSession.h>
 
 namespace android {
 
diff --git a/media/libstagefright/wifi-display/wfd.cpp b/media/libstagefright/wifi-display/wfd.cpp
index 9fee4d0..4607606 100644
--- a/media/libstagefright/wifi-display/wfd.cpp
+++ b/media/libstagefright/wifi-display/wfd.cpp
@@ -175,7 +175,8 @@
     iface.append(StringPrintf(":%d", port).c_str());
 
     sp<RemoteDisplayClient> client = new RemoteDisplayClient;
-    sp<IRemoteDisplay> display = service->listenForRemoteDisplay(client, iface);
+    sp<IRemoteDisplay> display =
+        service->listenForRemoteDisplay(client, iface);
 
     client->waitUntilDone();
 
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 714854e..54377f1 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -27,9 +27,6 @@
 
 LOCAL_SRC_FILES += StateQueue.cpp
 
-# uncomment for debugging timing problems related to StateQueue::push()
-LOCAL_CFLAGS += -DSTATE_QUEUE_DUMP
-
 LOCAL_C_INCLUDES := \
     $(call include-path-for, audio-effects) \
     $(call include-path-for, audio-utils)
@@ -56,24 +53,10 @@
 
 LOCAL_MODULE:= libaudioflinger
 
-LOCAL_SRC_FILES += FastMixer.cpp FastMixerState.cpp
-
-LOCAL_CFLAGS += -DFAST_MIXER_STATISTICS
-
-# uncomment to display CPU load adjusted for CPU frequency
-# LOCAL_CFLAGS += -DCPU_FREQUENCY_STATISTICS
+LOCAL_SRC_FILES += FastMixer.cpp FastMixerState.cpp AudioWatchdog.cpp
 
 LOCAL_CFLAGS += -DSTATE_QUEUE_INSTANTIATIONS='"StateQueueInstantiations.cpp"'
 
-LOCAL_CFLAGS += -UFAST_TRACKS_AT_NON_NATIVE_SAMPLE_RATE
-
-# uncomment to allow tee sink debugging to be enabled by property
-# LOCAL_CFLAGS += -DTEE_SINK
-
-# uncomment to enable the audio watchdog
-# LOCAL_SRC_FILES += AudioWatchdog.cpp
-# LOCAL_CFLAGS += -DAUDIO_WATCHDOG
-
 # Define ANDROID_SMP appropriately. Used to get inline tracing fast-path.
 ifeq ($(TARGET_CPU_SMP),true)
     LOCAL_CFLAGS += -DANDROID_SMP=1
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 17a69fa..99e077c 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -19,6 +19,7 @@
 #define LOG_TAG "AudioFlinger"
 //#define LOG_NDEBUG 0
 
+#include "Configuration.h"
 #include <dirent.h>
 #include <math.h>
 #include <signal.h>
@@ -61,6 +62,7 @@
 #include <media/nbaio/Pipe.h>
 #include <media/nbaio/PipeReader.h>
 #include <media/AudioParameter.h>
+#include <private/android_filesystem_config.h>
 
 // ----------------------------------------------------------------------------
 
@@ -138,7 +140,9 @@
       mMasterMute(false),
       mNextUniqueId(1),
       mMode(AUDIO_MODE_INVALID),
-      mBtNrecIsOff(false)
+      mBtNrecIsOff(false),
+      mIsLowRamDevice(true),
+      mIsDeviceTypeKnown(false)
 {
     getpid_cached = getpid();
     char value[PROPERTY_VALUE_MAX];
@@ -1380,6 +1384,23 @@
 
 // ----------------------------------------------------------------------------
 
+status_t AudioFlinger::setLowRamDevice(bool isLowRamDevice)
+{
+    uid_t uid = IPCThreadState::self()->getCallingUid();
+    if (uid != AID_SYSTEM) {
+        return PERMISSION_DENIED;
+    }
+    Mutex::Autolock _l(mLock);
+    if (mIsDeviceTypeKnown) {
+        return INVALID_OPERATION;
+    }
+    mIsLowRamDevice = isLowRamDevice;
+    mIsDeviceTypeKnown = true;
+    return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
 audio_io_handle_t AudioFlinger::openOutput(audio_module_handle_t module,
                                            audio_devices_t *pDevices,
                                            uint32_t *pSamplingRate,
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index b640b31..f31619b 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -220,6 +220,8 @@
     virtual uint32_t getPrimaryOutputSamplingRate();
     virtual size_t getPrimaryOutputFrameCount();
 
+    virtual status_t setLowRamDevice(bool isLowRamDevice);
+
     virtual     status_t    onTransact(
                                 uint32_t code,
                                 const Parcel& data,
@@ -594,12 +596,11 @@
     status_t    closeOutput_nonvirtual(audio_io_handle_t output);
     status_t    closeInput_nonvirtual(audio_io_handle_t input);
 
-// do not use #ifdef here, since AudioFlinger.h is included by more than one module
-//#ifdef TEE_SINK
+#ifdef TEE_SINK
     // all record threads serially share a common tee sink, which is re-created on format change
     sp<NBAIO_Sink>   mRecordTeeSink;
     sp<NBAIO_Source> mRecordTeeSource;
-//#endif
+#endif
 
 public:
 
@@ -624,6 +625,15 @@
     static const size_t kTeeSinkTrackFramesDefault = 0x1000;
 #endif
 
+    // This method reads from a variable without mLock, but the variable is updated under mLock.  So
+    // we might read a stale value, or a value that's inconsistent with respect to other variables.
+    // In this case, it's safe because the return value isn't used for making an important decision.
+    // The reason we don't want to take mLock is because it could block the caller for a long time.
+    bool    isLowRamDevice() const { return mIsLowRamDevice; }
+
+private:
+    bool    mIsLowRamDevice;
+    bool    mIsDeviceTypeKnown;
 };
 
 #undef INCLUDING_FROM_AUDIOFLINGER_H
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index 7d38f80..df4e029 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -18,6 +18,7 @@
 #define LOG_TAG "AudioMixer"
 //#define LOG_NDEBUG 0
 
+#include "Configuration.h"
 #include <stdint.h>
 #include <string.h>
 #include <stdlib.h>
diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp
index eacecf0..fa1e405 100644
--- a/services/audioflinger/AudioPolicyService.cpp
+++ b/services/audioflinger/AudioPolicyService.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "AudioPolicyService"
 //#define LOG_NDEBUG 0
 
+#include "Configuration.h"
 #undef __STRICT_ANSI__
 #define __STDINT_LIMITS
 #define __STDC_LIMIT_MACROS
@@ -50,7 +51,7 @@
 static const int kDumpLockRetries = 50;
 static const int kDumpLockSleepUs = 20000;
 
-static const nsecs_t kAudioCommandTimeout = 3000000000; // 3 seconds
+static const nsecs_t kAudioCommandTimeout = 3000000000LL; // 3 seconds
 
 namespace {
     extern struct audio_policy_service_ops aps_ops;
diff --git a/services/audioflinger/AudioWatchdog.cpp b/services/audioflinger/AudioWatchdog.cpp
index 8f328ee..93d185e 100644
--- a/services/audioflinger/AudioWatchdog.cpp
+++ b/services/audioflinger/AudioWatchdog.cpp
@@ -17,9 +17,12 @@
 #define LOG_TAG "AudioWatchdog"
 //#define LOG_NDEBUG 0
 
+#include "Configuration.h"
 #include <utils/Log.h>
 #include "AudioWatchdog.h"
 
+#ifdef AUDIO_WATCHDOG
+
 namespace android {
 
 void AudioWatchdogDump::dump(int fd)
@@ -132,3 +135,5 @@
 }
 
 }   // namespace android
+
+#endif // AUDIO_WATCHDOG
diff --git a/services/audioflinger/Configuration.h b/services/audioflinger/Configuration.h
new file mode 100644
index 0000000..bc2038a
--- /dev/null
+++ b/services/audioflinger/Configuration.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+// Put build-time configuration options here rather than Android.mk,
+// so that the instantiate for AudioFlinger service will pick up the same options.
+
+#ifndef ANDROID_AUDIOFLINGER_CONFIGURATION_H
+#define ANDROID_AUDIOFLINGER_CONFIGURATION_H
+
+// uncomment to enable detailed battery usage reporting (not debugged)
+//#define ADD_BATTERY_DATA
+
+// uncomment to enable the audio watchdog
+//#define AUDIO_WATCHDOG
+
+// uncomment to display CPU load adjusted for CPU frequency
+//#define CPU_FREQUENCY_STATISTICS
+
+// uncomment to enable fast mixer to take performance samples for later statistical analysis
+#define FAST_MIXER_STATISTICS
+
+// uncomment to allow fast tracks at non-native sample rate
+//#define FAST_TRACKS_AT_NON_NATIVE_SAMPLE_RATE
+
+// uncomment for debugging timing problems related to StateQueue::push()
+//#define STATE_QUEUE_DUMP
+
+// uncomment to allow tee sink debugging to be enabled by property
+//#define TEE_SINK
+
+// uncomment to log CPU statistics every n wall clock seconds
+//#define DEBUG_CPU_USAGE 10
+
+#endif // ANDROID_AUDIOFLINGER_CONFIGURATION_H
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 942ea35..1c7a64b 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -19,6 +19,7 @@
 #define LOG_TAG "AudioFlinger"
 //#define LOG_NDEBUG 0
 
+#include "Configuration.h"
 #include <utils/Log.h>
 #include <audio_effects/effect_visualizer.h>
 #include <audio_utils/primitives.h>
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index 21df1d7..5350e2c 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -25,6 +25,7 @@
 
 #define ATRACE_TAG ATRACE_TAG_AUDIO
 
+#include "Configuration.h"
 #include <sys/atomics.h>
 #include <time.h>
 #include <utils/Log.h>
@@ -82,7 +83,7 @@
     struct timespec oldLoad = {0, 0};    // previous value of clock_gettime(CLOCK_THREAD_CPUTIME_ID)
     bool oldLoadValid = false;  // whether oldLoad is valid
     uint32_t bounds = 0;
-    bool full = false;      // whether we have collected at least kSamplingN samples
+    bool full = false;      // whether we have collected at least mSamplingN samples
 #ifdef CPU_FREQUENCY_STATISTICS
     ThreadCpuUsage tcu;     // for reading the current CPU clock frequency in kHz
 #endif
@@ -142,7 +143,9 @@
                     preIdle = *current;
                     current = &preIdle;
                     oldTsValid = false;
+#ifdef FAST_MIXER_STATISTICS
                     oldLoadValid = false;
+#endif
                     ignoreNextOverrun = true;
                 }
                 previous = current;
@@ -182,8 +185,10 @@
                 warmupCycles = 0;
                 sleepNs = -1;
                 coldGen = current->mColdGen;
+#ifdef FAST_MIXER_STATISTICS
                 bounds = 0;
                 full = false;
+#endif
                 oldTsValid = !clock_gettime(CLOCK_MONOTONIC, &oldTs);
             } else {
                 sleepNs = FAST_HOT_IDLE_NS;
@@ -498,91 +503,91 @@
                     }
                 }
                 sleepNs = -1;
-              if (isWarm) {
-                if (sec > 0 || nsec > underrunNs) {
-                    ATRACE_NAME("underrun");
-                    // FIXME only log occasionally
-                    ALOGV("underrun: time since last cycle %d.%03ld sec",
-                            (int) sec, nsec / 1000000L);
-                    dumpState->mUnderruns++;
-                    ignoreNextOverrun = true;
-                } else if (nsec < overrunNs) {
-                    if (ignoreNextOverrun) {
-                        ignoreNextOverrun = false;
-                    } else {
+                if (isWarm) {
+                    if (sec > 0 || nsec > underrunNs) {
+                        ATRACE_NAME("underrun");
                         // FIXME only log occasionally
-                        ALOGV("overrun: time since last cycle %d.%03ld sec",
+                        ALOGV("underrun: time since last cycle %d.%03ld sec",
                                 (int) sec, nsec / 1000000L);
-                        dumpState->mOverruns++;
-                    }
-                    // This forces a minimum cycle time. It:
-                    //   - compensates for an audio HAL with jitter due to sample rate conversion
-                    //   - works with a variable buffer depth audio HAL that never pulls at a rate
-                    //     < than overrunNs per buffer.
-                    //   - recovers from overrun immediately after underrun
-                    // It doesn't work with a non-blocking audio HAL.
-                    sleepNs = forceNs - nsec;
-                } else {
-                    ignoreNextOverrun = false;
-                }
-              }
-#ifdef FAST_MIXER_STATISTICS
-              if (isWarm) {
-                // advance the FIFO queue bounds
-                size_t i = bounds & (FastMixerDumpState::kSamplingN - 1);
-                bounds = (bounds & 0xFFFF0000) | ((bounds + 1) & 0xFFFF);
-                if (full) {
-                    bounds += 0x10000;
-                } else if (!(bounds & (FastMixerDumpState::kSamplingN - 1))) {
-                    full = true;
-                }
-                // compute the delta value of clock_gettime(CLOCK_MONOTONIC)
-                uint32_t monotonicNs = nsec;
-                if (sec > 0 && sec < 4) {
-                    monotonicNs += sec * 1000000000;
-                }
-                // compute the raw CPU load = delta value of clock_gettime(CLOCK_THREAD_CPUTIME_ID)
-                uint32_t loadNs = 0;
-                struct timespec newLoad;
-                rc = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &newLoad);
-                if (rc == 0) {
-                    if (oldLoadValid) {
-                        sec = newLoad.tv_sec - oldLoad.tv_sec;
-                        nsec = newLoad.tv_nsec - oldLoad.tv_nsec;
-                        if (nsec < 0) {
-                            --sec;
-                            nsec += 1000000000;
+                        dumpState->mUnderruns++;
+                        ignoreNextOverrun = true;
+                    } else if (nsec < overrunNs) {
+                        if (ignoreNextOverrun) {
+                            ignoreNextOverrun = false;
+                        } else {
+                            // FIXME only log occasionally
+                            ALOGV("overrun: time since last cycle %d.%03ld sec",
+                                    (int) sec, nsec / 1000000L);
+                            dumpState->mOverruns++;
                         }
-                        loadNs = nsec;
-                        if (sec > 0 && sec < 4) {
-                            loadNs += sec * 1000000000;
-                        }
+                        // This forces a minimum cycle time. It:
+                        //  - compensates for an audio HAL with jitter due to sample rate conversion
+                        //  - works with a variable buffer depth audio HAL that never pulls at a
+                        //    rate < than overrunNs per buffer.
+                        //  - recovers from overrun immediately after underrun
+                        // It doesn't work with a non-blocking audio HAL.
+                        sleepNs = forceNs - nsec;
                     } else {
-                        // first time through the loop
-                        oldLoadValid = true;
+                        ignoreNextOverrun = false;
                     }
-                    oldLoad = newLoad;
                 }
+#ifdef FAST_MIXER_STATISTICS
+                if (isWarm) {
+                    // advance the FIFO queue bounds
+                    size_t i = bounds & (dumpState->mSamplingN - 1);
+                    bounds = (bounds & 0xFFFF0000) | ((bounds + 1) & 0xFFFF);
+                    if (full) {
+                        bounds += 0x10000;
+                    } else if (!(bounds & (dumpState->mSamplingN - 1))) {
+                        full = true;
+                    }
+                    // compute the delta value of clock_gettime(CLOCK_MONOTONIC)
+                    uint32_t monotonicNs = nsec;
+                    if (sec > 0 && sec < 4) {
+                        monotonicNs += sec * 1000000000;
+                    }
+                    // compute raw CPU load = delta value of clock_gettime(CLOCK_THREAD_CPUTIME_ID)
+                    uint32_t loadNs = 0;
+                    struct timespec newLoad;
+                    rc = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &newLoad);
+                    if (rc == 0) {
+                        if (oldLoadValid) {
+                            sec = newLoad.tv_sec - oldLoad.tv_sec;
+                            nsec = newLoad.tv_nsec - oldLoad.tv_nsec;
+                            if (nsec < 0) {
+                                --sec;
+                                nsec += 1000000000;
+                            }
+                            loadNs = nsec;
+                            if (sec > 0 && sec < 4) {
+                                loadNs += sec * 1000000000;
+                            }
+                        } else {
+                            // first time through the loop
+                            oldLoadValid = true;
+                        }
+                        oldLoad = newLoad;
+                    }
 #ifdef CPU_FREQUENCY_STATISTICS
-                // get the absolute value of CPU clock frequency in kHz
-                int cpuNum = sched_getcpu();
-                uint32_t kHz = tcu.getCpukHz(cpuNum);
-                kHz = (kHz << 4) | (cpuNum & 0xF);
+                    // get the absolute value of CPU clock frequency in kHz
+                    int cpuNum = sched_getcpu();
+                    uint32_t kHz = tcu.getCpukHz(cpuNum);
+                    kHz = (kHz << 4) | (cpuNum & 0xF);
 #endif
-                // save values in FIFO queues for dumpsys
-                // these stores #1, #2, #3 are not atomic with respect to each other,
-                // or with respect to store #4 below
-                dumpState->mMonotonicNs[i] = monotonicNs;
-                dumpState->mLoadNs[i] = loadNs;
+                    // save values in FIFO queues for dumpsys
+                    // these stores #1, #2, #3 are not atomic with respect to each other,
+                    // or with respect to store #4 below
+                    dumpState->mMonotonicNs[i] = monotonicNs;
+                    dumpState->mLoadNs[i] = loadNs;
 #ifdef CPU_FREQUENCY_STATISTICS
-                dumpState->mCpukHz[i] = kHz;
+                    dumpState->mCpukHz[i] = kHz;
 #endif
-                // this store #4 is not atomic with respect to stores #1, #2, #3 above, but
-                // the newest open and oldest closed halves are atomic with respect to each other
-                dumpState->mBounds = bounds;
-                ATRACE_INT("cycle_ms", monotonicNs / 1000000);
-                ATRACE_INT("load_us", loadNs / 1000);
-              }
+                    // this store #4 is not atomic with respect to stores #1, #2, #3 above, but
+                    // the newest open & oldest closed halves are atomic with respect to each other
+                    dumpState->mBounds = bounds;
+                    ATRACE_INT("cycle_ms", monotonicNs / 1000000);
+                    ATRACE_INT("load_us", loadNs / 1000);
+                }
 #endif
             } else {
                 // first time through the loop
@@ -603,26 +608,44 @@
     // never return 'true'; Thread::_threadLoop() locks mutex which can result in priority inversion
 }
 
-FastMixerDumpState::FastMixerDumpState() :
+FastMixerDumpState::FastMixerDumpState(
+#ifdef FAST_MIXER_STATISTICS
+        uint32_t samplingN
+#endif
+        ) :
     mCommand(FastMixerState::INITIAL), mWriteSequence(0), mFramesWritten(0),
     mNumTracks(0), mWriteErrors(0), mUnderruns(0), mOverruns(0),
     mSampleRate(0), mFrameCount(0), /* mMeasuredWarmupTs({0, 0}), */ mWarmupCycles(0),
     mTrackMask(0)
 #ifdef FAST_MIXER_STATISTICS
-    , mBounds(0)
+    , mSamplingN(0), mBounds(0)
 #endif
 {
     mMeasuredWarmupTs.tv_sec = 0;
     mMeasuredWarmupTs.tv_nsec = 0;
-    // sample arrays aren't accessed atomically with respect to the bounds,
-    // so clearing reduces chance for dumpsys to read random uninitialized samples
-    memset(&mMonotonicNs, 0, sizeof(mMonotonicNs));
-    memset(&mLoadNs, 0, sizeof(mLoadNs));
-#ifdef CPU_FREQUENCY_STATISTICS
-    memset(&mCpukHz, 0, sizeof(mCpukHz));
+#ifdef FAST_MIXER_STATISTICS
+    increaseSamplingN(samplingN);
 #endif
 }
 
+#ifdef FAST_MIXER_STATISTICS
+void FastMixerDumpState::increaseSamplingN(uint32_t samplingN)
+{
+    if (samplingN <= mSamplingN || samplingN > kSamplingN || roundup(samplingN) != samplingN) {
+        return;
+    }
+    uint32_t additional = samplingN - mSamplingN;
+    // sample arrays aren't accessed atomically with respect to the bounds,
+    // so clearing reduces chance for dumpsys to read random uninitialized samples
+    memset(&mMonotonicNs[mSamplingN], 0, sizeof(mMonotonicNs[0]) * additional);
+    memset(&mLoadNs[mSamplingN], 0, sizeof(mLoadNs[0]) * additional);
+#ifdef CPU_FREQUENCY_STATISTICS
+    memset(&mCpukHz[mSamplingN], 0, sizeof(mCpukHz[0]) * additional);
+#endif
+    mSamplingN = samplingN;
+}
+#endif
+
 FastMixerDumpState::~FastMixerDumpState()
 {
 }
@@ -641,7 +664,7 @@
     }
 }
 
-void FastMixerDumpState::dump(int fd)
+void FastMixerDumpState::dump(int fd) const
 {
     if (mCommand == FastMixerState::INITIAL) {
         fdprintf(fd, "FastMixer not initialized\n");
@@ -692,9 +715,9 @@
     uint32_t newestOpen = bounds & 0xFFFF;
     uint32_t oldestClosed = bounds >> 16;
     uint32_t n = (newestOpen - oldestClosed) & 0xFFFF;
-    if (n > kSamplingN) {
+    if (n > mSamplingN) {
         ALOGE("too many samples %u", n);
-        n = kSamplingN;
+        n = mSamplingN;
     }
     // statistics for monotonic (wall clock) time, thread raw CPU load in time, CPU clock frequency,
     // and adjusted CPU load in MHz normalized for CPU clock frequency
@@ -710,7 +733,7 @@
     uint32_t *tail = n >= kTailDenominator ? new uint32_t[n] : NULL;
     // loop over all the samples
     for (uint32_t j = 0; j < n; ++j) {
-        size_t i = oldestClosed++ & (kSamplingN - 1);
+        size_t i = oldestClosed++ & (mSamplingN - 1);
         uint32_t wallNs = mMonotonicNs[i];
         if (tail != NULL) {
             tail[j] = wallNs;
diff --git a/services/audioflinger/FastMixer.h b/services/audioflinger/FastMixer.h
index 2ab1d04..6158925 100644
--- a/services/audioflinger/FastMixer.h
+++ b/services/audioflinger/FastMixer.h
@@ -85,10 +85,14 @@
 // Only POD types are permitted, and the contents shouldn't be trusted (i.e. do range checks).
 // It has a different lifetime than the FastMixer, and so it can't be a member of FastMixer.
 struct FastMixerDumpState {
-    FastMixerDumpState();
+    FastMixerDumpState(
+#ifdef FAST_MIXER_STATISTICS
+            uint32_t samplingN = kSamplingNforLowRamDevice
+#endif
+            );
     /*virtual*/ ~FastMixerDumpState();
 
-    void dump(int fd);          // should only be called on a stable copy, not the original
+    void dump(int fd) const;    // should only be called on a stable copy, not the original
 
     FastMixerState::Command mCommand;   // current command
     uint32_t mWriteSequence;    // incremented before and after each write()
@@ -106,8 +110,15 @@
 
 #ifdef FAST_MIXER_STATISTICS
     // Recently collected samples of per-cycle monotonic time, thread CPU time, and CPU frequency.
-    // kSamplingN is the size of the sampling frame, and must be a power of 2 <= 0x8000.
+    // kSamplingN is max size of sampling frame (statistics), and must be a power of 2 <= 0x8000.
+    // The sample arrays are virtually allocated based on this compile-time constant,
+    // but are only initialized and used based on the runtime parameter mSamplingN.
     static const uint32_t kSamplingN = 0x8000;
+    // Compile-time constant for a "low RAM device", must be a power of 2 <= kSamplingN.
+    // This value was chosen such that each array uses 1 small page (4 Kbytes).
+    static const uint32_t kSamplingNforLowRamDevice = 0x400;
+    // Corresponding runtime maximum size of sample arrays, must be a power of 2 <= kSamplingN.
+    uint32_t mSamplingN;
     // The bounds define the interval of valid samples, and are represented as follows:
     //      newest open (excluded) endpoint   = lower 16 bits of bounds, modulo N
     //      oldest closed (included) endpoint = upper 16 bits of bounds, modulo N
@@ -119,6 +130,8 @@
 #ifdef CPU_FREQUENCY_STATISTICS
     uint32_t mCpukHz[kSamplingN];       // absolute CPU clock frequency in kHz, bits 0-3 are CPU#
 #endif
+    // Increase sampling window after construction, must be a power of 2 <= kSamplingN
+    void    increaseSamplingN(uint32_t samplingN);
 #endif
 };
 
diff --git a/services/audioflinger/FastMixerState.cpp b/services/audioflinger/FastMixerState.cpp
index c45c81b..737de97 100644
--- a/services/audioflinger/FastMixerState.cpp
+++ b/services/audioflinger/FastMixerState.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include "Configuration.h"
 #include "FastMixerState.h"
 
 namespace android {
diff --git a/services/audioflinger/StateQueue.cpp b/services/audioflinger/StateQueue.cpp
index 3e891a5..c2d3bbd 100644
--- a/services/audioflinger/StateQueue.cpp
+++ b/services/audioflinger/StateQueue.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "StateQueue"
 //#define LOG_NDEBUG 0
 
+#include "Configuration.h"
 #include <time.h>
 #include <cutils/atomic.h>
 #include <utils/Log.h>
diff --git a/services/audioflinger/StateQueue.h b/services/audioflinger/StateQueue.h
index e33b3c6..9cde642 100644
--- a/services/audioflinger/StateQueue.h
+++ b/services/audioflinger/StateQueue.h
@@ -31,8 +31,14 @@
 //        and this may result in an audible artifact
 //      needs read-only access to a recent stable state,
 //        but not necessarily the most current one
+//      only allocate and free memory when configuration changes
+//      avoid conventional logging, as this is a form of I/O and could block
+//      defer computation to other threads when feasible; for example
+//        cycle times are collected by fast mixer thread but the floating-point
+//        statistical calculations on these cycle times are computed by normal mixer
+//      these requirements also apply to callouts such as AudioBufferProvider and VolumeProvider
 //  Normal mixer thread:
-//      periodic with typical period ~40 ms
+//      periodic with typical period ~20 ms
 //      SCHED_OTHER scheduling policy and nice priority == urgent audio
 //      ok to block, but prefer to avoid as much as possible
 //      needs read/write access to state
diff --git a/services/audioflinger/StateQueueInstantiations.cpp b/services/audioflinger/StateQueueInstantiations.cpp
index 077582f..0d5cd0c 100644
--- a/services/audioflinger/StateQueueInstantiations.cpp
+++ b/services/audioflinger/StateQueueInstantiations.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include "Configuration.h"
 #include "FastMixerState.h"
 #include "StateQueue.h"
 
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index ef109af..f27d908 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -20,6 +20,7 @@
 //#define LOG_NDEBUG 0
 #define ATRACE_TAG ATRACE_TAG_AUDIO
 
+#include "Configuration.h"
 #include <math.h>
 #include <fcntl.h>
 #include <sys/stat.h>
@@ -54,14 +55,11 @@
 #include "ServiceUtilities.h"
 #include "SchedulingPolicyService.h"
 
-#undef ADD_BATTERY_DATA
-
 #ifdef ADD_BATTERY_DATA
 #include <media/IMediaPlayerService.h>
 #include <media/IMediaDeathNotifier.h>
 #endif
 
-// #define DEBUG_CPU_USAGE 10  // log statistics every n wall clock seconds
 #ifdef DEBUG_CPU_USAGE
 #include <cpustats/CentralTendencyStatistics.h>
 #include <cpustats/ThreadCpuUsage.h>
@@ -282,6 +280,12 @@
 
 AudioFlinger::ThreadBase::~ThreadBase()
 {
+    // mConfigEvents should be empty, but just in case it isn't, free the memory it owns
+    for (size_t i = 0; i < mConfigEvents.size(); i++) {
+        delete mConfigEvents[i];
+    }
+    mConfigEvents.clear();
+
     mParamCond.broadcast();
     // do not lock the mutex in destructor
     releaseWakeLock_l();
@@ -2281,6 +2285,8 @@
 #endif
             }
             state->mCommand = FastMixerState::MIX_WRITE;
+            mFastMixerDumpState.increaseSamplingN(mAudioFlinger->isLowRamDevice() ?
+                    FastMixerDumpState::kSamplingNforLowRamDevice : FastMixerDumpState::kSamplingN);
             sq->end();
             sq->push(FastMixerStateQueue::BLOCK_UNTIL_PUSHED);
             if (kUseFastMixer == FastMixer_Dynamic) {
@@ -3081,7 +3087,7 @@
     write(fd, result.string(), result.size());
 
     // Make a non-atomic copy of fast mixer dump state so it won't change underneath us
-    FastMixerDumpState copy = mFastMixerDumpState;
+    const FastMixerDumpState copy(mFastMixerDumpState);
     copy.dump(fd);
 
 #ifdef STATE_QUEUE_DUMP
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 7de6872..365c790 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -290,6 +290,7 @@
                 Vector<String8>         mNewParameters;
                 status_t                mParamStatus;
 
+                // vector owns each ConfigEvent *, so must delete after removing
                 Vector<ConfigEvent *>     mConfigEvents;
 
                 // These fields are written and read by thread itself without lock or barrier,
@@ -429,6 +430,8 @@
 
                 virtual status_t setSyncEvent(const sp<SyncEvent>& event);
                 virtual bool     isValidSyncEvent(const sp<SyncEvent>& event) const;
+
+                // called with AudioFlinger lock held
                         void     invalidateTracks(audio_stream_type_t streamType);
 
 
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index f0dbee3..c45daae 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -19,6 +19,7 @@
 #define LOG_TAG "AudioFlinger"
 //#define LOG_NDEBUG 0
 
+#include "Configuration.h"
 #include <math.h>
 #include <cutils/compiler.h>
 #include <utils/Log.h>
diff --git a/services/camera/libcameraservice/Camera2Device.cpp b/services/camera/libcameraservice/Camera2Device.cpp
index 77df152..710d0e9 100644
--- a/services/camera/libcameraservice/Camera2Device.cpp
+++ b/services/camera/libcameraservice/Camera2Device.cpp
@@ -445,6 +445,10 @@
     return res;
 }
 
+bool Camera2Device::willNotify3A() {
+    return true;
+}
+
 void Camera2Device::notificationCallback(int32_t msg_type,
         int32_t ext1,
         int32_t ext2,
diff --git a/services/camera/libcameraservice/Camera2Device.h b/services/camera/libcameraservice/Camera2Device.h
index 3034a1d..372ce9f 100644
--- a/services/camera/libcameraservice/Camera2Device.h
+++ b/services/camera/libcameraservice/Camera2Device.h
@@ -59,6 +59,7 @@
     virtual status_t createDefaultRequest(int templateId, CameraMetadata *request);
     virtual status_t waitUntilDrained();
     virtual status_t setNotifyCallback(NotificationListener *listener);
+    virtual bool     willNotify3A();
     virtual status_t waitForNextFrame(nsecs_t timeout);
     virtual status_t getNextFrame(CameraMetadata *frame);
     virtual status_t triggerAutofocus(uint32_t id);
diff --git a/services/camera/libcameraservice/Camera3Device.cpp b/services/camera/libcameraservice/Camera3Device.cpp
index 73bf30c..9d0f392 100644
--- a/services/camera/libcameraservice/Camera3Device.cpp
+++ b/services/camera/libcameraservice/Camera3Device.cpp
@@ -844,6 +844,10 @@
     return OK;
 }
 
+bool Camera3Device::willNotify3A() {
+    return false;
+}
+
 status_t Camera3Device::waitForNextFrame(nsecs_t timeout) {
     ATRACE_CALL();
     status_t res;
@@ -1244,13 +1248,6 @@
 
     }
 
-    AlgState cur3aState;
-    AlgState new3aState;
-    int32_t aeTriggerId = 0;
-    int32_t afTriggerId = 0;
-
-    NotificationListener *listener = NULL;
-
     // Process the result metadata, if provided
     if (result->result != NULL) {
         Mutex::Autolock l(mOutputLock);
@@ -1288,59 +1285,6 @@
                     " metadata for frame %d (%lld vs %lld respectively)",
                     frameNumber, timestamp, entry.data.i64[0]);
         }
-
-        // Get 3A states from result metadata
-
-        entry = captureResult.find(ANDROID_CONTROL_AE_STATE);
-        if (entry.count == 0) {
-            CLOGE("No AE state provided by HAL for frame %d!",
-                    frameNumber);
-        } else {
-            new3aState.aeState =
-                    static_cast<camera_metadata_enum_android_control_ae_state>(
-                        entry.data.u8[0]);
-        }
-
-        entry = captureResult.find(ANDROID_CONTROL_AF_STATE);
-        if (entry.count == 0) {
-            CLOGE("No AF state provided by HAL for frame %d!",
-                    frameNumber);
-        } else {
-            new3aState.afState =
-                    static_cast<camera_metadata_enum_android_control_af_state>(
-                        entry.data.u8[0]);
-        }
-
-        entry = captureResult.find(ANDROID_CONTROL_AWB_STATE);
-        if (entry.count == 0) {
-            CLOGE("No AWB state provided by HAL for frame %d!",
-                    frameNumber);
-        } else {
-            new3aState.awbState =
-                    static_cast<camera_metadata_enum_android_control_awb_state>(
-                        entry.data.u8[0]);
-        }
-
-        entry = captureResult.find(ANDROID_CONTROL_AF_TRIGGER_ID);
-        if (entry.count == 0) {
-            CLOGE("No AF trigger ID provided by HAL for frame %d!",
-                    frameNumber);
-        } else {
-            afTriggerId = entry.data.i32[0];
-        }
-
-        entry = captureResult.find(ANDROID_CONTROL_AE_PRECAPTURE_ID);
-        if (entry.count == 0) {
-            CLOGE("No AE precapture trigger ID provided by HAL"
-                    " for frame %d!", frameNumber);
-        } else {
-            aeTriggerId = entry.data.i32[0];
-        }
-
-        listener = mListener;
-        cur3aState = m3AState;
-
-        m3AState = new3aState;
     } // scope for mOutputLock
 
     // Return completed buffers to their streams with the timestamp
@@ -1357,30 +1301,16 @@
         }
     }
 
-    // Finally, dispatch any 3A change events to listeners if we got metadata
+    // Finally, signal any waiters for new frames
 
     if (result->result != NULL) {
         mResultSignal.signal();
     }
 
-    if (result->result != NULL && listener != NULL) {
-        if (new3aState.aeState != cur3aState.aeState) {
-            ALOGVV("%s: AE state changed from 0x%x to 0x%x",
-                    __FUNCTION__, cur3aState.aeState, new3aState.aeState);
-            listener->notifyAutoExposure(new3aState.aeState, aeTriggerId);
-        }
-        if (new3aState.afState != cur3aState.afState) {
-            ALOGVV("%s: AF state changed from 0x%x to 0x%x",
-                    __FUNCTION__, cur3aState.afState, new3aState.afState);
-            listener->notifyAutoFocus(new3aState.afState, afTriggerId);
-        }
-        if (new3aState.awbState != cur3aState.awbState) {
-            listener->notifyAutoWhitebalance(new3aState.awbState, aeTriggerId);
-        }
-    }
-
 }
 
+
+
 void Camera3Device::notify(const camera3_notify_msg *msg) {
     ATRACE_CALL();
     NotificationListener *listener;
diff --git a/services/camera/libcameraservice/Camera3Device.h b/services/camera/libcameraservice/Camera3Device.h
index faa42b9..2328f89 100644
--- a/services/camera/libcameraservice/Camera3Device.h
+++ b/services/camera/libcameraservice/Camera3Device.h
@@ -107,6 +107,7 @@
     virtual status_t waitUntilDrained();
 
     virtual status_t setNotifyCallback(NotificationListener *listener);
+    virtual bool     willNotify3A();
     virtual status_t waitForNextFrame(nsecs_t timeout);
     virtual status_t getNextFrame(CameraMetadata *frame);
 
@@ -389,18 +390,6 @@
     Condition              mResultSignal;
     NotificationListener  *mListener;
 
-    struct AlgState {
-        camera_metadata_enum_android_control_ae_state  aeState;
-        camera_metadata_enum_android_control_af_state  afState;
-        camera_metadata_enum_android_control_awb_state awbState;
-
-        AlgState() :
-                aeState(ANDROID_CONTROL_AE_STATE_INACTIVE),
-                afState(ANDROID_CONTROL_AF_STATE_INACTIVE),
-                awbState(ANDROID_CONTROL_AWB_STATE_INACTIVE) {
-        }
-    } m3AState;
-
     /**** End scope for mOutputLock ****/
 
     /**
diff --git a/services/camera/libcameraservice/CameraDeviceBase.h b/services/camera/libcameraservice/CameraDeviceBase.h
index 8c457d9..aa92bec 100644
--- a/services/camera/libcameraservice/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/CameraDeviceBase.h
@@ -156,6 +156,13 @@
     virtual status_t setNotifyCallback(NotificationListener *listener) = 0;
 
     /**
+     * Whether the device supports calling notifyAutofocus, notifyAutoExposure,
+     * and notifyAutoWhitebalance; if this returns false, the client must
+     * synthesize these notifications from received frame metadata.
+     */
+    virtual bool     willNotify3A() = 0;
+
+    /**
      * Wait for a new frame to be produced, with timeout in nanoseconds.
      * Returns TIMED_OUT when no frame produced within the specified duration
      */
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index c284a0d..0eb3e32 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -489,6 +489,7 @@
             break;
           case CAMERA_DEVICE_API_VERSION_2_0:
           case CAMERA_DEVICE_API_VERSION_2_1:
+          case CAMERA_DEVICE_API_VERSION_3_0:
             client = new ProCamera2Client(this, cameraCb, String16(),
                     cameraId, facing, callingPid, USE_CALLING_UID, getpid());
             break;
diff --git a/services/camera/libcameraservice/camera2/CallbackProcessor.cpp b/services/camera/libcameraservice/camera2/CallbackProcessor.cpp
index aae2504..d7bafda 100644
--- a/services/camera/libcameraservice/camera2/CallbackProcessor.cpp
+++ b/services/camera/libcameraservice/camera2/CallbackProcessor.cpp
@@ -110,8 +110,8 @@
     if (!mCallbackToApp && mCallbackConsumer == 0) {
         // Create CPU buffer queue endpoint, since app hasn't given us one
         // Make it async to avoid disconnect deadlocks
-        mCallbackConsumer = new CpuConsumer(kCallbackHeapCount,
-                /*synchronized*/ false);
+        sp<BufferQueue> bq = new BufferQueue();
+        mCallbackConsumer = new CpuConsumer(bq, kCallbackHeapCount);
         mCallbackConsumer->setFrameAvailableListener(this);
         mCallbackConsumer->setName(String8("Camera2Client::CallbackConsumer"));
         mCallbackWindow = new Surface(
diff --git a/services/camera/libcameraservice/camera2/FrameProcessor.cpp b/services/camera/libcameraservice/camera2/FrameProcessor.cpp
index d13d398..114a7a8 100644
--- a/services/camera/libcameraservice/camera2/FrameProcessor.cpp
+++ b/services/camera/libcameraservice/camera2/FrameProcessor.cpp
@@ -33,6 +33,9 @@
     ProFrameProcessor(device),
     mClient(client),
     mLastFrameNumberOfFaces(0) {
+
+    sp<CameraDeviceBase> d = device.promote();
+    mSynthesize3ANotify = !(d->willNotify3A());
 }
 
 FrameProcessor::~FrameProcessor() {
@@ -50,6 +53,11 @@
         return false;
     }
 
+    if (mSynthesize3ANotify) {
+        // Ignoring missing fields for now
+        process3aState(frame, client);
+    }
+
     if (!ProFrameProcessor::processSingleFrame(frame, device)) {
         return false;
     }
@@ -185,6 +193,99 @@
     return OK;
 }
 
+status_t FrameProcessor::process3aState(const CameraMetadata &frame,
+        const sp<Camera2Client> &client) {
+
+    ATRACE_CALL();
+    camera_metadata_ro_entry_t entry;
+    int mId = client->getCameraId();
+
+    entry = frame.find(ANDROID_REQUEST_FRAME_COUNT);
+    int32_t frameNumber = entry.data.i32[0];
+
+    // Get 3A states from result metadata
+    bool gotAllStates = true;
+
+    AlgState new3aState;
+
+    entry = frame.find(ANDROID_CONTROL_AE_STATE);
+    if (entry.count == 0) {
+        ALOGE("%s: Camera %d: No AE state provided by HAL for frame %d!",
+                __FUNCTION__, mId, frameNumber);
+        gotAllStates = false;
+    } else {
+        new3aState.aeState =
+                static_cast<camera_metadata_enum_android_control_ae_state>(
+                    entry.data.u8[0]);
+    }
+
+    entry = frame.find(ANDROID_CONTROL_AF_STATE);
+    if (entry.count == 0) {
+        ALOGE("%s: Camera %d: No AF state provided by HAL for frame %d!",
+                __FUNCTION__, mId, frameNumber);
+        gotAllStates = false;
+    } else {
+        new3aState.afState =
+                static_cast<camera_metadata_enum_android_control_af_state>(
+                    entry.data.u8[0]);
+    }
+
+    entry = frame.find(ANDROID_CONTROL_AWB_STATE);
+    if (entry.count == 0) {
+        ALOGE("%s: Camera %d: No AWB state provided by HAL for frame %d!",
+                __FUNCTION__, mId, frameNumber);
+        gotAllStates = false;
+    } else {
+        new3aState.awbState =
+                static_cast<camera_metadata_enum_android_control_awb_state>(
+                    entry.data.u8[0]);
+    }
+
+    int32_t afTriggerId = 0;
+    entry = frame.find(ANDROID_CONTROL_AF_TRIGGER_ID);
+    if (entry.count == 0) {
+        ALOGE("%s: Camera %d: No AF trigger ID provided by HAL for frame %d!",
+                __FUNCTION__, mId, frameNumber);
+        gotAllStates = false;
+    } else {
+        afTriggerId = entry.data.i32[0];
+    }
+
+    int32_t aeTriggerId = 0;
+    entry = frame.find(ANDROID_CONTROL_AE_PRECAPTURE_ID);
+    if (entry.count == 0) {
+        ALOGE("%s: Camera %d: No AE precapture trigger ID provided by HAL"
+                " for frame %d!",
+                __FUNCTION__, mId, frameNumber);
+        gotAllStates = false;
+    } else {
+        aeTriggerId = entry.data.i32[0];
+    }
+
+    if (!gotAllStates) return BAD_VALUE;
+
+    if (new3aState.aeState != m3aState.aeState) {
+        ALOGV("%s: AE state changed from 0x%x to 0x%x",
+                __FUNCTION__, m3aState.aeState, new3aState.aeState);
+        client->notifyAutoExposure(new3aState.aeState, aeTriggerId);
+    }
+    if (new3aState.afState != m3aState.afState) {
+        ALOGV("%s: AF state changed from 0x%x to 0x%x",
+                __FUNCTION__, m3aState.afState, new3aState.afState);
+        client->notifyAutoFocus(new3aState.afState, afTriggerId);
+    }
+    if (new3aState.awbState != m3aState.awbState) {
+        ALOGV("%s: AWB state changed from 0x%x to 0x%x",
+                __FUNCTION__, m3aState.awbState, new3aState.awbState);
+        client->notifyAutoWhitebalance(new3aState.awbState, aeTriggerId);
+    }
+
+    m3aState = new3aState;
+
+    return OK;
+}
+
+
 void FrameProcessor::callbackFaceDetection(sp<Camera2Client> client,
                                      const camera_frame_metadata &metadata) {
 
diff --git a/services/camera/libcameraservice/camera2/FrameProcessor.h b/services/camera/libcameraservice/camera2/FrameProcessor.h
index 27ed8f6..f480c55 100644
--- a/services/camera/libcameraservice/camera2/FrameProcessor.h
+++ b/services/camera/libcameraservice/camera2/FrameProcessor.h
@@ -44,6 +44,9 @@
 
   private:
     wp<Camera2Client> mClient;
+
+    bool mSynthesize3ANotify;
+
     int mLastFrameNumberOfFaces;
 
     void processNewFrames(const sp<Camera2Client> &client);
@@ -54,6 +57,22 @@
     status_t processFaceDetect(const CameraMetadata &frame,
             const sp<Camera2Client> &client);
 
+    // Send 3A state change notifications to client based on frame metadata
+    status_t process3aState(const CameraMetadata &frame,
+            const sp<Camera2Client> &client);
+
+    struct AlgState {
+        camera_metadata_enum_android_control_ae_state  aeState;
+        camera_metadata_enum_android_control_af_state  afState;
+        camera_metadata_enum_android_control_awb_state awbState;
+
+        AlgState() :
+                aeState(ANDROID_CONTROL_AE_STATE_INACTIVE),
+                afState(ANDROID_CONTROL_AF_STATE_INACTIVE),
+                awbState(ANDROID_CONTROL_AWB_STATE_INACTIVE) {
+        }
+    } m3aState;
+
     // Emit FaceDetection event to java if faces changed
     void callbackFaceDetection(sp<Camera2Client> client,
                                const camera_frame_metadata &metadata);
diff --git a/services/camera/libcameraservice/camera2/JpegProcessor.cpp b/services/camera/libcameraservice/camera2/JpegProcessor.cpp
index f0a13ca..1d739cd 100644
--- a/services/camera/libcameraservice/camera2/JpegProcessor.cpp
+++ b/services/camera/libcameraservice/camera2/JpegProcessor.cpp
@@ -82,7 +82,8 @@
 
     if (mCaptureConsumer == 0) {
         // Create CPU buffer queue endpoint
-        mCaptureConsumer = new CpuConsumer(1);
+        sp<BufferQueue> bq = new BufferQueue();
+        mCaptureConsumer = new CpuConsumer(bq, 1);
         mCaptureConsumer->setFrameAvailableListener(this);
         mCaptureConsumer->setName(String8("Camera2Client::CaptureConsumer"));
         mCaptureWindow = new Surface(
diff --git a/services/camera/libcameraservice/camera2/StreamingProcessor.cpp b/services/camera/libcameraservice/camera2/StreamingProcessor.cpp
index 35eb433..5981be7 100644
--- a/services/camera/libcameraservice/camera2/StreamingProcessor.cpp
+++ b/services/camera/libcameraservice/camera2/StreamingProcessor.cpp
@@ -319,10 +319,10 @@
         // Create CPU buffer queue endpoint. We need one more buffer here so that we can
         // always acquire and free a buffer when the heap is full; otherwise the consumer
         // will have buffers in flight we'll never clear out.
-        mRecordingConsumer = new BufferItemConsumer(
+        sp<BufferQueue> bq = new BufferQueue();
+        mRecordingConsumer = new BufferItemConsumer(bq,
                 GRALLOC_USAGE_HW_VIDEO_ENCODER,
-                mRecordingHeapCount + 1,
-                true);
+                mRecordingHeapCount + 1);
         mRecordingConsumer->setFrameAvailableListener(this);
         mRecordingConsumer->setName(String8("Camera2-RecordingConsumer"));
         mRecordingWindow = new Surface(
diff --git a/services/camera/libcameraservice/camera2/ZslProcessor.cpp b/services/camera/libcameraservice/camera2/ZslProcessor.cpp
index 8af8276..0094992 100644
--- a/services/camera/libcameraservice/camera2/ZslProcessor.cpp
+++ b/services/camera/libcameraservice/camera2/ZslProcessor.cpp
@@ -128,10 +128,10 @@
 
     if (mZslConsumer == 0) {
         // Create CPU buffer queue endpoint
-        mZslConsumer = new BufferItemConsumer(
+        sp<BufferQueue> bq = new BufferQueue();
+        mZslConsumer = new BufferItemConsumer(bq,
             GRALLOC_USAGE_HW_CAMERA_ZSL,
-            kZslBufferDepth,
-            true);
+            kZslBufferDepth);
         mZslConsumer->setFrameAvailableListener(this);
         mZslConsumer->setName(String8("Camera2Client::ZslConsumer"));
         mZslWindow = new Surface(
diff --git a/services/camera/libcameraservice/camera3/Camera3InputStream.cpp b/services/camera/libcameraservice/camera3/Camera3InputStream.cpp
index 13e9c83..e9a9c2b 100644
--- a/services/camera/libcameraservice/camera3/Camera3InputStream.cpp
+++ b/services/camera/libcameraservice/camera3/Camera3InputStream.cpp
@@ -211,9 +211,9 @@
     mFrameCount = 0;
 
     if (mConsumer.get() == 0) {
-        mConsumer = new BufferItemConsumer(camera3_stream::usage,
-                                           mTotalBufferCount,
-                                           /*synchronousMode*/true);
+        sp<BufferQueue> bq = new BufferQueue();
+        mConsumer = new BufferItemConsumer(bq, camera3_stream::usage,
+                                           mTotalBufferCount);
         mConsumer->setName(String8::format("Camera3-InputStream-%d", mId));
     }
 
diff --git a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
index 7625735..8141f4e 100644
--- a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
+++ b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
@@ -36,11 +36,10 @@
 
 RingBufferConsumer::RingBufferConsumer(uint32_t consumerUsage,
         int bufferCount) :
-    ConsumerBase(new BufferQueue(true)),
+    ConsumerBase(new BufferQueue()),
     mBufferCount(bufferCount)
 {
     mBufferQueue->setConsumerUsageBits(consumerUsage);
-    mBufferQueue->setSynchronousMode(true);
     mBufferQueue->setMaxAcquiredBufferCount(bufferCount);
 
     assert(bufferCount > 0);
diff --git a/services/camera/libcameraservice/photography/CameraDeviceClient.cpp b/services/camera/libcameraservice/photography/CameraDeviceClient.cpp
index bd6b60a..e1c7e79 100644
--- a/services/camera/libcameraservice/photography/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/photography/CameraDeviceClient.cpp
@@ -176,7 +176,7 @@
             ALOGE("%s: Camera %d:  Got error %d after trying to set streaming "
                   "request", __FUNCTION__, mCameraId, res);
         } else {
-            mStreamingRequestList.push_back(mRequestIdCounter);
+            mStreamingRequestList.push_back(requestId);
         }
     } else {
         res = mDevice->capture(metadata);
@@ -391,28 +391,23 @@
     return res;
 }
 
-status_t CameraDeviceClient::getCameraInfo(int cameraId,
-                                         /*out*/
-                                         camera_metadata** info)
+status_t CameraDeviceClient::getCameraInfo(/*out*/CameraMetadata* info)
 {
     ATRACE_CALL();
     ALOGV("%s", __FUNCTION__);
 
     status_t res = OK;
 
-    // TODO: remove cameraId. this should be device-specific info, not static.
-    if (cameraId != mCameraId) {
-        return INVALID_OPERATION;
-    }
-
     if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
 
     Mutex::Autolock icl(mBinderSerializationLock);
 
     if (!mDevice.get()) return DEAD_OBJECT;
 
-    CameraMetadata deviceInfo = mDevice->info();
-    *info = deviceInfo.release();
+    if (info != NULL) {
+        *info = mDevice->info(); // static camera metadata
+        // TODO: merge with device-specific camera metadata
+    }
 
     return res;
 }
diff --git a/services/camera/libcameraservice/photography/CameraDeviceClient.h b/services/camera/libcameraservice/photography/CameraDeviceClient.h
index 806aa15..c6c241a 100644
--- a/services/camera/libcameraservice/photography/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/photography/CameraDeviceClient.h
@@ -85,9 +85,7 @@
 
     // Get the static metadata for the camera
     // -- Caller owns the newly allocated metadata
-    virtual status_t      getCameraInfo(int cameraId,
-                                        /*out*/
-                                        camera_metadata** info);
+    virtual status_t      getCameraInfo(/*out*/CameraMetadata* info);
 
     /**
      * Interface used by CameraService