am a9ab66c5: (-s ours) am ffd99cb7: Merge "Shutter sound is heard at the end of the recorded video"

* commit 'a9ab66c5fac826a765186146128158672bfac67c':
  Shutter sound is heard at the end of the recorded video
diff --git a/camera/CameraParameters.cpp b/camera/CameraParameters.cpp
index 059a8a5..872512a 100644
--- a/camera/CameraParameters.cpp
+++ b/camera/CameraParameters.cpp
@@ -155,6 +155,7 @@
 const char CameraParameters::PIXEL_FORMAT_RGBA8888[] = "rgba8888";
 const char CameraParameters::PIXEL_FORMAT_JPEG[] = "jpeg";
 const char CameraParameters::PIXEL_FORMAT_BAYER_RGGB[] = "bayer-rggb";
+const char CameraParameters::PIXEL_FORMAT_ANDROID_OPAQUE[] = "android-opaque";
 
 // Values for focus mode settings.
 const char CameraParameters::FOCUS_MODE_AUTO[] = "auto";
diff --git a/cmds/stagefright/codec.cpp b/cmds/stagefright/codec.cpp
index f3370a5..bfe20cc 100644
--- a/cmds/stagefright/codec.cpp
+++ b/cmds/stagefright/codec.cpp
@@ -35,6 +35,7 @@
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/NuMediaExtractor.h>
 #include <gui/SurfaceComposerClient.h>
+#include <ui/DisplayInfo.h>
 
 static void usage(const char *me) {
     fprintf(stderr, "usage: %s [-a] use audio\n"
@@ -378,8 +379,10 @@
         composerClient = new SurfaceComposerClient;
         CHECK_EQ(composerClient->initCheck(), (status_t)OK);
 
-        ssize_t displayWidth = composerClient->getDisplayWidth(0);
-        ssize_t displayHeight = composerClient->getDisplayHeight(0);
+        DisplayInfo info;
+        SurfaceComposerClient::getDisplayInfo(0, &info);
+        ssize_t displayWidth = info.w;
+        ssize_t displayHeight = info.h;
 
         ALOGV("display is %ld x %ld\n", displayWidth, displayHeight);
 
diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp
index efa1445..a9f0ab2 100644
--- a/cmds/stagefright/stream.cpp
+++ b/cmds/stagefright/stream.cpp
@@ -35,6 +35,7 @@
 #include <gui/SurfaceComposerClient.h>
 
 #include <fcntl.h>
+#include <ui/DisplayInfo.h>
 
 using namespace android;
 
@@ -304,8 +305,10 @@
     sp<SurfaceComposerClient> composerClient = new SurfaceComposerClient;
     CHECK_EQ(composerClient->initCheck(), (status_t)OK);
 
-    ssize_t displayWidth = composerClient->getDisplayWidth(0);
-    ssize_t displayHeight = composerClient->getDisplayHeight(0);
+    DisplayInfo info;
+    SurfaceComposerClient::getDisplayInfo(0, &info);
+    ssize_t displayWidth = info.w;
+    ssize_t displayHeight = info.h;
 
     ALOGV("display is %d x %d\n", displayWidth, displayHeight);
 
diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h
index 36248a0..4d5aa36 100644
--- a/include/camera/CameraParameters.h
+++ b/include/camera/CameraParameters.h
@@ -606,6 +606,8 @@
     // Raw bayer format used for images, which is 10 bit precision samples
     // stored in 16 bit words. The filter pattern is RGGB.
     static const char PIXEL_FORMAT_BAYER_RGGB[];
+    // Pixel format is not known to the framework
+    static const char PIXEL_FORMAT_ANDROID_OPAQUE[];
 
     // Values for focus mode settings.
     // Auto-focus mode. Applications should call
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index ef77692..156c592 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -17,21 +17,14 @@
 #ifndef AUDIORECORD_H_
 #define AUDIORECORD_H_
 
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <media/IAudioFlinger.h>
-#include <media/IAudioRecord.h>
-
-#include <utils/RefBase.h>
-#include <utils/Errors.h>
-#include <binder/IInterface.h>
 #include <binder/IMemory.h>
 #include <cutils/sched_policy.h>
-#include <utils/threads.h>
-
-#include <system/audio.h>
 #include <media/AudioSystem.h>
+#include <media/IAudioRecord.h>
+#include <system/audio.h>
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <utils/threads.h>
 
 namespace android {
 
@@ -46,11 +39,10 @@
     static const int DEFAULT_SAMPLE_RATE = 8000;
 
     /* Events used by AudioRecord callback function (callback_t).
-     *
-     * to keep in sync with frameworks/base/media/java/android/media/AudioRecord.java
+     * Keep in sync with frameworks/base/media/java/android/media/AudioRecord.java NATIVE_EVENT_*.
      */
     enum event_type {
-        EVENT_MORE_DATA = 0,        // Request to reqd more data from PCM buffer.
+        EVENT_MORE_DATA = 0,        // Request to read more data from PCM buffer.
         EVENT_OVERRUN = 1,          // PCM buffer overrun occured.
         EVENT_MARKER = 2,           // Record head is at the specified marker position
                                     // (See setMarkerPosition()).
@@ -72,7 +64,7 @@
         int         channelCount;
         audio_format_t format;
         size_t      frameCount;
-        size_t      size;
+        size_t      size;           // total size in bytes == frameCount * frameSize
         union {
             void*       raw;
             short*      i16;
@@ -80,12 +72,6 @@
         };
     };
 
-    /* These are static methods to control the system-wide AudioFlinger
-     * only privileged processes can have access to them
-     */
-
-//    static status_t setMasterMute(bool mute);
-
     /* As a convenience, if a callback is supplied, a handler thread
      * is automatically created with the appropriate priority. This thread
      * invokes the callback when a new buffer becomes ready or an overrun condition occurs.
@@ -98,8 +84,8 @@
      *          more bytes than indicated by 'size' field and update 'size' if less bytes are
      *          read.
      *          - EVENT_OVERRUN: unused.
-     *          - EVENT_MARKER: pointer to an uin32_t containing the marker position in frames.
-     *          - EVENT_NEW_POS: pointer to an uin32_t containing the new position in frames.
+     *          - EVENT_MARKER: pointer to const uint32_t containing the marker position in frames.
+     *          - EVENT_NEW_POS: pointer to const uint32_t containing the new position in frames.
      */
 
     typedef void (*callback_t)(int event, void* user, void *info);
@@ -115,7 +101,7 @@
      static status_t getMinFrameCount(int* frameCount,
                                       uint32_t sampleRate,
                                       audio_format_t format,
-                                      int channelCount);
+                                      audio_channel_mask_t channelMask);
 
     /* Constructs an uninitialized AudioRecord. No connection with
      * AudioFlinger takes place.
@@ -133,32 +119,22 @@
      * sampleRate:         Track sampling rate in Hz.
      * format:             Audio format (e.g AUDIO_FORMAT_PCM_16_BIT for signed
      *                     16 bits per sample).
-     * channelMask:        Channel mask: see audio_channels_t.
+     * channelMask:        Channel mask.
      * frameCount:         Total size of track PCM buffer in frames. This defines the
      *                     latency of the track.
-     * flags:              A bitmask of acoustic values from enum record_flags.  It enables
-     *                     AGC, NS, and IIR.
      * cbf:                Callback function. If not null, this function is called periodically
      *                     to provide new PCM data.
+     * user:               Context for use by the callback receiver.
      * notificationFrames: The callback function is called each time notificationFrames PCM
      *                     frames are ready in record track output buffer.
-     * user                Context for use by the callback receiver.
+     * sessionId:          Not yet supported.
      */
 
-     // FIXME consider removing this alias and replacing it by audio_in_acoustics_t
-     //       or removing the parameter entirely if it is unused
-     enum record_flags {
-         RECORD_AGC_ENABLE = AUDIO_IN_ACOUSTICS_AGC_ENABLE,
-         RECORD_NS_ENABLE  = AUDIO_IN_ACOUSTICS_NS_ENABLE,
-         RECORD_IIR_ENABLE = AUDIO_IN_ACOUSTICS_TX_IIR_ENABLE,
-     };
-
                         AudioRecord(audio_source_t inputSource,
                                     uint32_t sampleRate = 0,
                                     audio_format_t format = AUDIO_FORMAT_DEFAULT,
-                                    uint32_t channelMask = AUDIO_CHANNEL_IN_MONO,
+                                    audio_channel_mask_t channelMask = AUDIO_CHANNEL_IN_MONO,
                                     int frameCount      = 0,
-                                    record_flags flags  = (record_flags) 0,
                                     callback_t cbf = NULL,
                                     void* user = NULL,
                                     int notificationFrames = 0,
@@ -166,7 +142,7 @@
 
 
     /* Terminates the AudioRecord and unregisters it from AudioFlinger.
-     * Also destroys all resources assotiated with the AudioRecord.
+     * Also destroys all resources associated with the AudioRecord.
      */
                         ~AudioRecord();
 
@@ -182,9 +158,8 @@
             status_t    set(audio_source_t inputSource = AUDIO_SOURCE_DEFAULT,
                             uint32_t sampleRate = 0,
                             audio_format_t format = AUDIO_FORMAT_DEFAULT,
-                            uint32_t channelMask = AUDIO_CHANNEL_IN_MONO,
+                            audio_channel_mask_t channelMask = AUDIO_CHANNEL_IN_MONO,
                             int frameCount      = 0,
-                            record_flags flags  = (record_flags) 0,
                             callback_t cbf = NULL,
                             void* user = NULL,
                             int notificationFrames = 0,
@@ -205,11 +180,10 @@
      */
             uint32_t     latency() const;
 
-   /* getters, see constructor */
+   /* getters, see constructor and set() */
 
             audio_format_t format() const;
             int         channelCount() const;
-            int         channels() const;
             uint32_t    frameCount() const;
             size_t      frameSize() const;
             audio_source_t inputSource() const;
@@ -227,7 +201,7 @@
      * obtainBuffer returns STOPPED. Note that obtainBuffer() still works
      * and will fill up buffers until the pool is exhausted.
      */
-            status_t    stop();
+            void        stop();
             bool        stopped() const;
 
     /* get sample rate for this record track
@@ -271,7 +245,7 @@
             status_t    getPositionUpdatePeriod(uint32_t *updatePeriod) const;
 
 
-    /* Gets record head position. The position is the  total number of frames
+    /* Gets record head position. The position is the total number of frames
      * recorded since record start.
      *
      * Parameters:
@@ -294,7 +268,7 @@
      */
             audio_io_handle_t    getInput() const;
 
-    /* returns the audio session ID associated to this AudioRecord.
+    /* returns the audio session ID associated with this AudioRecord.
      *
      * Parameters:
      *  none.
@@ -342,57 +316,72 @@
             AudioRecord& operator = (const AudioRecord& other);
 
     /* a small internal class to handle the callback */
-    class ClientRecordThread : public Thread
+    class AudioRecordThread : public Thread
     {
     public:
-        ClientRecordThread(AudioRecord& receiver, bool bCanCallJava = false);
+        AudioRecordThread(AudioRecord& receiver, bool bCanCallJava = false);
+
+        // Do not call Thread::requestExitAndWait() without first calling requestExit().
+        // Thread::requestExitAndWait() is not virtual, and the implementation doesn't do enough.
+        virtual void        requestExit();
+
+                void        pause();    // suspend thread from execution at next loop boundary
+                void        resume();   // allow thread to execute, if not requested to exit
+
     private:
         friend class AudioRecord;
         virtual bool        threadLoop();
-        virtual status_t    readyToRun();
-        virtual void        onFirstRef() {}
         AudioRecord& mReceiver;
+        virtual ~AudioRecordThread();
+        Mutex               mMyLock;    // Thread::mLock is private
+        Condition           mMyCond;    // Thread::mThreadExitedCondition is private
+        bool                mPaused;    // whether thread is currently paused
     };
 
-            bool processAudioBuffer(const sp<ClientRecordThread>& thread);
+            // body of AudioRecordThread::threadLoop()
+            bool processAudioBuffer(const sp<AudioRecordThread>& thread);
+
             status_t openRecord_l(uint32_t sampleRate,
                                 audio_format_t format,
-                                uint32_t channelMask,
+                                audio_channel_mask_t channelMask,
                                 int frameCount,
                                 audio_io_handle_t input);
             audio_io_handle_t getInput_l();
             status_t restoreRecord_l(audio_track_cblk_t*& cblk);
 
-    sp<IAudioRecord>        mAudioRecord;
-    sp<IMemory>             mCblkMemory;
-    sp<ClientRecordThread>  mClientRecordThread;
-    status_t                mReadyToRun;
+    sp<AudioRecordThread>   mAudioRecordThread;
     mutable Mutex           mLock;
-    Condition               mCondition;
 
+    bool                    mActive;            // protected by mLock
+
+    // for client callback handler
+    callback_t              mCbf;
+    void*                   mUserData;
+
+    // for notification APIs
+    uint32_t                mNotificationFrames;
+    uint32_t                mRemainingFrames;
+    uint32_t                mMarkerPosition;    // in frames
+    bool                    mMarkerReached;
+    uint32_t                mNewPosition;       // in frames
+    uint32_t                mUpdatePeriod;      // in ms
+
+    // constant after constructor or set()
     uint32_t                mFrameCount;
-
-    audio_track_cblk_t*     mCblk;
     audio_format_t          mFormat;
     uint8_t                 mChannelCount;
     audio_source_t          mInputSource;
     status_t                mStatus;
     uint32_t                mLatency;
-
-    volatile int32_t        mActive;
-
-    callback_t              mCbf;
-    void*                   mUserData;
-    uint32_t                mNotificationFrames;
-    uint32_t                mRemainingFrames;
-    uint32_t                mMarkerPosition;
-    bool                    mMarkerReached;
-    uint32_t                mNewPosition;
-    uint32_t                mUpdatePeriod;
-    record_flags            mFlags;
-    uint32_t                mChannelMask;
-    audio_io_handle_t       mInput;
+    audio_channel_mask_t    mChannelMask;
+    audio_io_handle_t       mInput;                     // returned by AudioSystem::getInput()
     int                     mSessionId;
+
+    // may be changed if IAudioRecord object is re-created
+    sp<IAudioRecord>        mAudioRecord;
+    sp<IMemory>             mCblkMemory;
+    audio_track_cblk_t*     mCblk;
+
     int                     mPreviousPriority;          // before start()
     SchedPolicy             mPreviousSchedulingGroup;
 };
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index e2662f2..932482b 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -110,8 +110,8 @@
 
     static bool routedToA2dpOutput(audio_stream_type_t streamType);
 
-    static status_t getInputBufferSize(uint32_t sampleRate, audio_format_t format, int channelCount,
-        size_t* buffSize);
+    static status_t getInputBufferSize(uint32_t sampleRate, audio_format_t format,
+        audio_channel_mask_t channelMask, size_t* buffSize);
 
     static status_t setVoiceVolume(float volume);
 
@@ -126,6 +126,7 @@
     // necessary to check returned status before using the returned values.
     static status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, audio_stream_type_t stream = AUDIO_STREAM_DEFAULT);
 
+    // return the number of input frames lost by HAL implementation, or 0 if the handle is invalid
     static unsigned int  getInputFramesLost(audio_io_handle_t ioHandle);
 
     static int newAudioSessionId();
@@ -188,7 +189,7 @@
     static audio_io_handle_t getOutput(audio_stream_type_t stream,
                                         uint32_t samplingRate = 0,
                                         audio_format_t format = AUDIO_FORMAT_DEFAULT,
-                                        uint32_t channels = AUDIO_CHANNEL_OUT_STEREO,
+                                        audio_channel_mask_t channelMask = AUDIO_CHANNEL_OUT_STEREO,
                                         audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE);
     static status_t startOutput(audio_io_handle_t output,
                                 audio_stream_type_t stream,
@@ -200,8 +201,7 @@
     static audio_io_handle_t getInput(audio_source_t inputSource,
                                     uint32_t samplingRate = 0,
                                     audio_format_t format = AUDIO_FORMAT_DEFAULT,
-                                    uint32_t channels = AUDIO_CHANNEL_IN_MONO,
-                                    audio_in_acoustics_t acoustics = (audio_in_acoustics_t)0,
+                                    audio_channel_mask_t channelMask = AUDIO_CHANNEL_IN_MONO,
                                     int sessionId = 0);
     static status_t startInput(audio_io_handle_t input);
     static status_t stopInput(audio_io_handle_t input);
@@ -219,8 +219,8 @@
     static uint32_t getStrategyForStream(audio_stream_type_t stream);
     static audio_devices_t getDevicesForStream(audio_stream_type_t stream);
 
-    static audio_io_handle_t getOutputForEffect(effect_descriptor_t *desc);
-    static status_t registerEffect(effect_descriptor_t *desc,
+    static audio_io_handle_t getOutputForEffect(const effect_descriptor_t *desc);
+    static status_t registerEffect(const effect_descriptor_t *desc,
                                     audio_io_handle_t io,
                                     uint32_t strategy,
                                     int session,
@@ -277,7 +277,7 @@
     // previous parameters for recording buffer size queries
     static uint32_t gPrevInSamplingRate;
     static audio_format_t gPrevInFormat;
-    static int gPrevInChannelCount;
+    static audio_channel_mask_t gPrevInChannelMask;
 
     static sp<IAudioPolicyService> gAudioPolicyService;
 
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 639d6d2..4488ce4 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -135,7 +135,7 @@
      * sampleRate:         Track sampling rate in Hz.
      * format:             Audio format (e.g AUDIO_FORMAT_PCM_16_BIT for signed
      *                     16 bits per sample).
-     * channelMask:        Channel mask: see audio_channels_t.
+     * channelMask:        Channel mask.
      * frameCount:         Minimum size of track PCM buffer in frames. This defines the
      *                     latency of the track. The actual size selected by the AudioTrack could be
      *                     larger if the requested size is not compatible with current audio HAL
@@ -154,7 +154,7 @@
                         AudioTrack( audio_stream_type_t streamType,
                                     uint32_t sampleRate  = 0,
                                     audio_format_t format = AUDIO_FORMAT_DEFAULT,
-                                    int channelMask      = 0,
+                                    audio_channel_mask_t channelMask = 0,
                                     int frameCount       = 0,
                                     audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
                                     callback_t cbf       = NULL,
@@ -186,7 +186,7 @@
                         AudioTrack( audio_stream_type_t streamType,
                                     uint32_t sampleRate = 0,
                                     audio_format_t format = AUDIO_FORMAT_DEFAULT,
-                                    int channelMask     = 0,
+                                    audio_channel_mask_t channelMask = 0,
                                     const sp<IMemory>& sharedBuffer = 0,
                                     audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
                                     callback_t cbf      = NULL,
@@ -204,13 +204,13 @@
      * Returned status (from utils/Errors.h) can be:
      *  - NO_ERROR: successful initialization
      *  - INVALID_OPERATION: AudioTrack is already initialized
-     *  - BAD_VALUE: invalid parameter (channels, format, sampleRate...)
+     *  - BAD_VALUE: invalid parameter (channelMask, format, sampleRate...)
      *  - NO_INIT: audio server or audio hardware not initialized
      * */
             status_t    set(audio_stream_type_t streamType = AUDIO_STREAM_DEFAULT,
                             uint32_t sampleRate = 0,
                             audio_format_t format = AUDIO_FORMAT_DEFAULT,
-                            int channelMask     = 0,
+                            audio_channel_mask_t channelMask = 0,
                             int frameCount      = 0,
                             audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
                             callback_t cbf      = NULL,
@@ -472,10 +472,8 @@
     private:
         friend class AudioTrack;
         virtual bool        threadLoop();
-        virtual status_t    readyToRun();
-        virtual void        onFirstRef();
         AudioTrack& mReceiver;
-        ~AudioTrackThread();
+        virtual ~AudioTrackThread();
         Mutex               mMyLock;    // Thread::mLock is private
         Condition           mMyCond;    // Thread::mThreadExitedCondition is private
         bool                mPaused;    // whether thread is currently paused
@@ -487,7 +485,7 @@
             status_t createTrack_l(audio_stream_type_t streamType,
                                  uint32_t sampleRate,
                                  audio_format_t format,
-                                 uint32_t channelMask,
+                                 audio_channel_mask_t channelMask,
                                  int frameCount,
                                  audio_output_flags_t flags,
                                  const sp<IMemory>& sharedBuffer,
@@ -512,7 +510,7 @@
     uint8_t                 mChannelCount;
     uint8_t                 mMuted;
     uint8_t                 mReserved;
-    uint32_t                mChannelMask;
+    audio_channel_mask_t    mChannelMask;
     status_t                mStatus;
     uint32_t                mLatency;
 
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index 86e228b..bdd0142 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -48,7 +48,7 @@
     enum {
         TRACK_DEFAULT = 0,  // client requests a default AudioTrack
         TRACK_TIMED   = 1,  // client requests a TimedAudioTrack
-        TRACK_FAST    = 2,  // client requests a fast AudioTrack
+        TRACK_FAST    = 2,  // client requests a fast AudioTrack or AudioRecord
     };
     typedef uint32_t track_flags_t;
 
@@ -60,7 +60,7 @@
                                 audio_stream_type_t streamType,
                                 uint32_t sampleRate,
                                 audio_format_t format,
-                                uint32_t channelMask,
+                                audio_channel_mask_t channelMask,
                                 int frameCount,
                                 track_flags_t flags,
                                 const sp<IMemory>& sharedBuffer,
@@ -74,9 +74,10 @@
                                 audio_io_handle_t input,
                                 uint32_t sampleRate,
                                 audio_format_t format,
-                                uint32_t channelMask,
+                                audio_channel_mask_t channelMask,
                                 int frameCount,
                                 track_flags_t flags,
+                                pid_t tid,  // -1 means unused, otherwise must be valid non-0
                                 int *sessionId,
                                 status_t *status) = 0;
 
@@ -84,7 +85,9 @@
      * and therefore can be cached.
      */
     virtual     uint32_t    sampleRate(audio_io_handle_t output) const = 0;
+#if 0
     virtual     int         channelCount(audio_io_handle_t output) const = 0;
+#endif
     virtual     audio_format_t format(audio_io_handle_t output) const = 0;
     virtual     size_t      frameCount(audio_io_handle_t output) const = 0;
 
@@ -126,7 +129,8 @@
     virtual void registerClient(const sp<IAudioFlingerClient>& client) = 0;
 
     // retrieve the audio recording buffer size
-    virtual size_t getInputBufferSize(uint32_t sampleRate, audio_format_t format, int channelCount) const = 0;
+    virtual size_t getInputBufferSize(uint32_t sampleRate, audio_format_t format,
+            audio_channel_mask_t channelMask) const = 0;
 
     virtual audio_io_handle_t openOutput(audio_module_handle_t module,
                                          audio_devices_t *pDevices,
diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h
index e160d70..fb556af 100644
--- a/include/media/IAudioPolicyService.h
+++ b/include/media/IAudioPolicyService.h
@@ -51,7 +51,7 @@
     virtual audio_io_handle_t getOutput(audio_stream_type_t stream,
                                         uint32_t samplingRate = 0,
                                         audio_format_t format = AUDIO_FORMAT_DEFAULT,
-                                        uint32_t channels = 0,
+                                        audio_channel_mask_t channelMask = 0,
                                         audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE) = 0;
     virtual status_t startOutput(audio_io_handle_t output,
                                  audio_stream_type_t stream,
@@ -63,8 +63,7 @@
     virtual audio_io_handle_t getInput(audio_source_t inputSource,
                                     uint32_t samplingRate = 0,
                                     audio_format_t format = AUDIO_FORMAT_DEFAULT,
-                                    uint32_t channels = 0,
-                                    audio_in_acoustics_t acoustics = (audio_in_acoustics_t)0,
+                                    audio_channel_mask_t channelMask = 0,
                                     int audioSession = 0) = 0;
     virtual status_t startInput(audio_io_handle_t input) = 0;
     virtual status_t stopInput(audio_io_handle_t input) = 0;
@@ -80,8 +79,8 @@
                                           audio_devices_t device) = 0;
     virtual uint32_t getStrategyForStream(audio_stream_type_t stream) = 0;
     virtual audio_devices_t getDevicesForStream(audio_stream_type_t stream) = 0;
-    virtual audio_io_handle_t getOutputForEffect(effect_descriptor_t *desc) = 0;
-    virtual status_t registerEffect(effect_descriptor_t *desc,
+    virtual audio_io_handle_t getOutputForEffect(const effect_descriptor_t *desc) = 0;
+    virtual status_t registerEffect(const effect_descriptor_t *desc,
                                     audio_io_handle_t io,
                                     uint32_t strategy,
                                     int session,
diff --git a/include/media/IAudioRecord.h b/include/media/IAudioRecord.h
index ebc03ea..d6e3141 100644
--- a/include/media/IAudioRecord.h
+++ b/include/media/IAudioRecord.h
@@ -37,7 +37,7 @@
     /* After it's created the track is not active. Call start() to
      * make it active.
      */
-    virtual status_t    start(int event, int triggerSession) = 0;
+    virtual status_t    start(int /*AudioSystem::sync_event_t*/ event, int triggerSession) = 0;
 
     /* Stop a track. If set, the callback will cease being called and
      * obtainBuffer will return an error. Buffers that are already released
diff --git a/include/media/Visualizer.h b/include/media/Visualizer.h
index fdec5ee..aa58905 100644
--- a/include/media/Visualizer.h
+++ b/include/media/Visualizer.h
@@ -142,8 +142,6 @@
     private:
         friend class Visualizer;
         virtual bool        threadLoop();
-        virtual status_t    readyToRun();
-        virtual void        onFirstRef();
         Visualizer& mReceiver;
         Mutex       mLock;
         uint32_t mSleepTimeUs;
diff --git a/include/media/mediametadataretriever.h b/include/media/mediametadataretriever.h
index 534afce..0df77c1 100644
--- a/include/media/mediametadataretriever.h
+++ b/include/media/mediametadataretriever.h
@@ -55,6 +55,7 @@
     METADATA_KEY_TIMED_TEXT_LANGUAGES      = 21,
     METADATA_KEY_IS_DRM          = 22,
     METADATA_KEY_LOCATION        = 23,
+    METADATA_KEY_VIDEO_ROTATION  = 24,
 
     // Add more here...
 };
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 1fad383..f7cebc5 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -99,6 +99,8 @@
     // The player was started because it was used as the next player for another
     // player, which just completed playback
     MEDIA_INFO_STARTED_AS_NEXT = 2,
+    // The player just pushed the very first video frame for rendering
+    MEDIA_INFO_RENDERING_START = 3,
     // 7xx
     // The video is too complex for the decoder: it can't decode frames fast
     // enough. Possibly only the audio plays fine at this stage.
diff --git a/include/media/stagefright/timedtext/TimedTextDriver.h b/include/media/stagefright/timedtext/TimedTextDriver.h
index cde551b..f23c337 100644
--- a/include/media/stagefright/timedtext/TimedTextDriver.h
+++ b/include/media/stagefright/timedtext/TimedTextDriver.h
@@ -64,6 +64,7 @@
 
     enum State {
         UNINITIALIZED,
+        PREPARED,
         PLAYING,
         PAUSED,
     };
diff --git a/libvideoeditor/lvpp/Android.mk b/libvideoeditor/lvpp/Android.mk
index c018d74..0ed7e6c 100755
--- a/libvideoeditor/lvpp/Android.mk
+++ b/libvideoeditor/lvpp/Android.mk
@@ -59,6 +59,7 @@
     libstagefright            \
     libstagefright_foundation \
     libstagefright_omx        \
+    libsync                   \
     libui                     \
     libutils                  \
     libvideoeditor_osal       \
diff --git a/libvideoeditor/lvpp/NativeWindowRenderer.cpp b/libvideoeditor/lvpp/NativeWindowRenderer.cpp
index b2c2675..2e15ff9 100755
--- a/libvideoeditor/lvpp/NativeWindowRenderer.cpp
+++ b/libvideoeditor/lvpp/NativeWindowRenderer.cpp
@@ -22,9 +22,9 @@
 #include <cutils/log.h>
 #include <gui/SurfaceTexture.h>
 #include <gui/SurfaceTextureClient.h>
-#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MetaData.h>
+#include <media/stagefright/foundation/ADebug.h>
 #include "VideoEditorTools.h"
 
 #define CHECK_EGL_ERROR CHECK(EGL_SUCCESS == eglGetError())
@@ -382,7 +382,7 @@
     int64_t timeUs;
     CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
     native_window_set_buffers_timestamp(anw, timeUs * 1000);
-    status_t err = anw->queueBuffer(anw, buffer->graphicBuffer().get());
+    status_t err = anw->queueBuffer(anw, buffer->graphicBuffer().get(), -1);
     if (err != 0) {
         ALOGE("queueBuffer failed with error %s (%d)", strerror(-err), -err);
         return;
@@ -399,18 +399,16 @@
     native_window_set_usage(anw, GRALLOC_USAGE_SW_WRITE_OFTEN);
 
     ANativeWindowBuffer* anb;
-    anw->dequeueBuffer(anw, &anb);
+    CHECK(NO_ERROR == native_window_dequeue_buffer_and_wait(anw, &anb));
     CHECK(anb != NULL);
 
-    sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
-    CHECK(NO_ERROR == anw->lockBuffer(anw, buf->getNativeBuffer()));
-
     // Copy the buffer
     uint8_t* img = NULL;
+    sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
     buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
     copyI420Buffer(buffer, img, width, height, buf->getStride());
     buf->unlock();
-    CHECK(NO_ERROR == anw->queueBuffer(anw, buf->getNativeBuffer()));
+    CHECK(NO_ERROR == anw->queueBuffer(anw, buf->getNativeBuffer(), -1));
 }
 
 void NativeWindowRenderer::copyI420Buffer(MediaBuffer* src, uint8_t* dst,
diff --git a/libvideoeditor/lvpp/PreviewRenderer.cpp b/libvideoeditor/lvpp/PreviewRenderer.cpp
index 4aa4eb3..b1cfc8e 100755
--- a/libvideoeditor/lvpp/PreviewRenderer.cpp
+++ b/libvideoeditor/lvpp/PreviewRenderer.cpp
@@ -97,13 +97,12 @@
 void PreviewRenderer::getBufferYV12(uint8_t **data, size_t *stride) {
     int err = OK;
 
-    if ((err = mSurface->ANativeWindow::dequeueBuffer(mSurface.get(), &mBuf)) != 0) {
-        ALOGW("Surface::dequeueBuffer returned error %d", err);
+    if ((err = native_window_dequeue_buffer_and_wait(mSurface.get(),
+            &mBuf)) != 0) {
+        ALOGW("native_window_dequeue_buffer_and_wait returned error %d", err);
         return;
     }
 
-    CHECK_EQ(0, mSurface->ANativeWindow::lockBuffer(mSurface.get(), mBuf));
-
     GraphicBufferMapper &mapper = GraphicBufferMapper::get();
 
     Rect bounds(mWidth, mHeight);
@@ -131,7 +130,7 @@
     if (mBuf!= NULL) {
         CHECK_EQ(0, mapper.unlock(mBuf->handle));
 
-        if ((err = mSurface->ANativeWindow::queueBuffer(mSurface.get(), mBuf)) != 0) {
+        if ((err = mSurface->ANativeWindow::queueBuffer(mSurface.get(), mBuf, -1)) != 0) {
             ALOGW("Surface::queueBuffer returned error %d", err);
         }
     }
diff --git a/libvideoeditor/lvpp/VideoEditorAudioPlayer.cpp b/libvideoeditor/lvpp/VideoEditorAudioPlayer.cpp
index 797686c..c111ba8 100755
--- a/libvideoeditor/lvpp/VideoEditorAudioPlayer.cpp
+++ b/libvideoeditor/lvpp/VideoEditorAudioPlayer.cpp
@@ -534,9 +534,7 @@
     } else {
         mAudioTrack = new AudioTrack(
                 AUDIO_STREAM_MUSIC, mSampleRate, AUDIO_FORMAT_PCM_16_BIT,
-                (numChannels == 2)
-                    ? AUDIO_CHANNEL_OUT_STEREO
-                    : AUDIO_CHANNEL_OUT_MONO,
+                audio_channel_out_mask_from_count(numChannels),
                 0, AUDIO_OUTPUT_FLAG_NONE, &AudioCallback, this, 0);
 
         if ((err = mAudioTrack->initCheck()) != OK) {
diff --git a/libvideoeditor/vss/stagefrightshells/src/VideoEditor3gpReader.cpp b/libvideoeditor/vss/stagefrightshells/src/VideoEditor3gpReader.cpp
index 5026073..f735c0b 100755
--- a/libvideoeditor/vss/stagefrightshells/src/VideoEditor3gpReader.cpp
+++ b/libvideoeditor/vss/stagefrightshells/src/VideoEditor3gpReader.cpp
@@ -1483,11 +1483,15 @@
                     (int32_t*)&(pVideoStreamHandler->m_videoHeight));
 
                 (*pStreamHandler)  = (M4_StreamHandler*)(pVideoStreamHandler);
-                meta->findInt64(kKeyDuration,
-                    (int64_t*)&(Duration));
-                ((*pStreamHandler)->m_duration) =
-                    (int32_t)((Duration)/1000); // conversion to mS
+                meta->findInt64(kKeyDuration, (int64_t*)&(Duration));
+                ((*pStreamHandler)->m_duration) = (int32_t)((Duration)/1000); // conversion to mS
                 pC->mMaxDuration = ((*pStreamHandler)->m_duration);
+                if (pC->mMaxDuration == 0) {
+                    ALOGE("Video is too short: %lld Us", Duration);
+                    delete pVideoStreamHandler;
+                    pVideoStreamHandler = NULL;
+                    return M4ERR_PARAMETER;
+                }
                 ALOGV("VideoEditor3gpReader_getNextStreamHandler m_duration %d",
                     (*pStreamHandler)->m_duration);
 
diff --git a/media/libeffects/factory/EffectsFactory.c b/media/libeffects/factory/EffectsFactory.c
index 59cd9e3..f158929 100644
--- a/media/libeffects/factory/EffectsFactory.c
+++ b/media/libeffects/factory/EffectsFactory.c
@@ -214,7 +214,7 @@
     while (gCurLib) {
         if (gCurEffect) {
             if (index == gCurEffectIdx) {
-                memcpy(pDescriptor, gCurEffect->object, sizeof(effect_descriptor_t));
+                *pDescriptor = *(effect_descriptor_t *)gCurEffect->object;
                 ret = 0;
                 break;
             } else {
@@ -251,7 +251,7 @@
     pthread_mutex_lock(&gLibLock);
     ret = findEffect(NULL, uuid, &l, &d);
     if (ret == 0) {
-        memcpy(pDescriptor, d, sizeof(effect_descriptor_t));
+        *pDescriptor = *d;
     }
     pthread_mutex_unlock(&gLibLock);
     return ret;
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 40dffd4..1a45e35 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -180,16 +180,16 @@
     }
     if(index == LVM_BASS_BOOST){
         ALOGV("\tEffectQueryEffect processing LVM_BASS_BOOST");
-        memcpy(pDescriptor, &gBassBoostDescriptor,   sizeof(effect_descriptor_t));
+        *pDescriptor = gBassBoostDescriptor;
     }else if(index == LVM_VIRTUALIZER){
         ALOGV("\tEffectQueryEffect processing LVM_VIRTUALIZER");
-        memcpy(pDescriptor, &gVirtualizerDescriptor, sizeof(effect_descriptor_t));
+        *pDescriptor = gVirtualizerDescriptor;
     } else if(index == LVM_EQUALIZER){
         ALOGV("\tEffectQueryEffect processing LVM_EQUALIZER");
-        memcpy(pDescriptor, &gEqualizerDescriptor,   sizeof(effect_descriptor_t));
+        *pDescriptor = gEqualizerDescriptor;
     } else if(index == LVM_VOLUME){
         ALOGV("\tEffectQueryEffect processing LVM_VOLUME");
-        memcpy(pDescriptor, &gVolumeDescriptor, sizeof(effect_descriptor_t));
+        *pDescriptor = gVolumeDescriptor;
     }
     ALOGV("\tEffectQueryEffect end\n");
     return 0;
@@ -494,7 +494,7 @@
         return  -EINVAL;
     }
 
-    memcpy(pDescriptor, desc, sizeof(effect_descriptor_t));
+    *pDescriptor = *desc;
 
     return 0;
 } /* end EffectGetDescriptor */
@@ -965,7 +965,7 @@
               || pConfig->outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE);
     CHECK_ARG(pConfig->inputCfg.format == AUDIO_FORMAT_PCM_16_BIT);
 
-    memcpy(&pContext->config, pConfig, sizeof(effect_config_t));
+    pContext->config = *pConfig;
 
     switch (pConfig->inputCfg.samplingRate) {
     case 8000:
@@ -1041,7 +1041,7 @@
 
 void Effect_getConfig(EffectContext *pContext, effect_config_t *pConfig)
 {
-    memcpy(pConfig, &pContext->config, sizeof(effect_config_t));
+    *pConfig = pContext->config;
 }   /* end Effect_getConfig */
 
 //----------------------------------------------------------------------------
@@ -3272,7 +3272,7 @@
             return -EINVAL;
     }
 
-    memcpy(pDescriptor, desc, sizeof(effect_descriptor_t));
+    *pDescriptor = *desc;
 
     return 0;
 }   /* end Effect_getDescriptor */
diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
index 9599dcc..941d651 100755
--- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
@@ -206,7 +206,7 @@
         ALOGV("\tLVM_ERROR : EffectQueryEffect index out of range %d", index);
         return -ENOENT;
     }
-    memcpy(pDescriptor, gDescriptors[index], sizeof(effect_descriptor_t));
+    *pDescriptor = *gDescriptors[index];
     ALOGV("\tEffectQueryEffect end\n");
     return 0;
 }     /* end EffectQueryEffect */
@@ -330,7 +330,7 @@
 
     for (i = 0; i < length; i++) {
         if (memcmp(uuid, &gDescriptors[i]->uuid, sizeof(effect_uuid_t)) == 0) {
-            memcpy(pDescriptor, gDescriptors[i], sizeof(effect_descriptor_t));
+            *pDescriptor = *gDescriptors[i];
             ALOGV("EffectGetDescriptor - UUID matched Reverb type %d, UUID = %x",
                  i, gDescriptors[i]->uuid.timeLow);
             return 0;
@@ -645,7 +645,7 @@
     }
 
     //ALOGV("\tReverb_setConfig calling memcpy");
-    memcpy(&pContext->config, pConfig, sizeof(effect_config_t));
+    pContext->config = *pConfig;
 
 
     switch (pConfig->inputCfg.samplingRate) {
@@ -715,7 +715,7 @@
 
 void Reverb_getConfig(ReverbContext *pContext, effect_config_t *pConfig)
 {
-    memcpy(pConfig, &pContext->config, sizeof(effect_config_t));
+    *pConfig = pContext->config;
 }   /* end Reverb_getConfig */
 
 //----------------------------------------------------------------------------
@@ -2157,7 +2157,7 @@
         }
     }
 
-    memcpy(pDescriptor, desc, sizeof(effect_descriptor_t));
+    *pDescriptor = *desc;
 
     return 0;
 }   /* end Reverb_getDescriptor */
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
index cfa7f51..5709837 100755
--- a/media/libeffects/preprocessing/PreProcessing.cpp
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -1700,7 +1700,7 @@
         return -EINVAL;
     }
 
-    memcpy(pDescriptor, sDescriptors[effect->procId], sizeof(effect_descriptor_t));
+    *pDescriptor = *sDescriptors[effect->procId];
 
     return 0;
 }
@@ -1834,7 +1834,7 @@
     if (index >= PREPROC_NUM_EFFECTS) {
         return -EINVAL;
     }
-    memcpy(pDescriptor, sDescriptors[index], sizeof(effect_descriptor_t));
+    *pDescriptor = *sDescriptors[index];
     return 0;
 }
 
@@ -1905,7 +1905,7 @@
 
     ALOGV("PreProcessingLib_GetDescriptor() got fx %s", desc->name);
 
-    memcpy(pDescriptor, desc, sizeof(effect_descriptor_t));
+    *pDescriptor = *desc;
     return 0;
 }
 
diff --git a/media/libeffects/testlibs/EffectEqualizer.cpp b/media/libeffects/testlibs/EffectEqualizer.cpp
index 35a4a61..90ebe1f 100644
--- a/media/libeffects/testlibs/EffectEqualizer.cpp
+++ b/media/libeffects/testlibs/EffectEqualizer.cpp
@@ -136,7 +136,7 @@
     if (index > 0) {
         return -EINVAL;
     }
-    memcpy(pDescriptor, &gEqualizerDescriptor, sizeof(effect_descriptor_t));
+    *pDescriptor = gEqualizerDescriptor;
     return 0;
 } /* end EffectQueryNext */
 
@@ -204,7 +204,7 @@
     }
 
     if (memcmp(uuid, &gEqualizerDescriptor.uuid, sizeof(effect_uuid_t)) == 0) {
-        memcpy(pDescriptor, &gEqualizerDescriptor, sizeof(effect_descriptor_t));
+        *pDescriptor = gEqualizerDescriptor;
         return 0;
     }
 
@@ -262,7 +262,7 @@
     }
     CHECK_ARG(channelCount <= AudioBiquadFilter::MAX_CHANNELS);
 
-    memcpy(&pContext->config, pConfig, sizeof(effect_config_t));
+    pContext->config = *pConfig;
 
     pContext->pEqualizer->configure(channelCount,
                           pConfig->inputCfg.samplingRate);
@@ -290,7 +290,7 @@
 
 void Equalizer_getConfig(EqualizerContext *pContext, effect_config_t *pConfig)
 {
-    memcpy(pConfig, &pContext->config, sizeof(effect_config_t));
+    *pConfig = pContext->config;
 }   // end Equalizer_getConfig
 
 
@@ -752,7 +752,7 @@
         return -EINVAL;
     }
 
-    memcpy(pDescriptor, &android::gEqualizerDescriptor, sizeof(effect_descriptor_t));
+    *pDescriptor = android::gEqualizerDescriptor;
 
     return 0;
 }
diff --git a/media/libeffects/testlibs/EffectReverb.c b/media/libeffects/testlibs/EffectReverb.c
index 8351712..a87a834 100644
--- a/media/libeffects/testlibs/EffectReverb.c
+++ b/media/libeffects/testlibs/EffectReverb.c
@@ -194,7 +194,7 @@
 
     for (i = 0; i < length; i++) {
         if (memcmp(uuid, &gDescriptors[i]->uuid, sizeof(effect_uuid_t)) == 0) {
-            memcpy(pDescriptor, gDescriptors[i], sizeof(effect_descriptor_t));
+            *pDescriptor = *gDescriptors[i];
             ALOGV("EffectGetDescriptor - UUID matched Reverb type %d, UUID = %x",
                  i, gDescriptors[i]->uuid.timeLow);
             return 0;
@@ -440,7 +440,7 @@
         }
     }
 
-    memcpy(pDescriptor, desc, sizeof(effect_descriptor_t));
+    *pDescriptor = *desc;
 
     return 0;
 }   /* end Reverb_getDescriptor */
@@ -546,7 +546,7 @@
         return -EINVAL;
     }
 
-    memcpy(&pRvbModule->config, pConfig, sizeof(effect_config_t));
+    pRvbModule->config = *pConfig;
 
     pReverb->m_nSamplingRate = pRvbModule->config.outputCfg.samplingRate;
 
@@ -644,7 +644,7 @@
 
 void Reverb_getConfig(reverb_module_t *pRvbModule, effect_config_t *pConfig)
 {
-    memcpy(pConfig, &pRvbModule->config, sizeof(effect_config_t));
+    *pConfig = pRvbModule->config;
 }
 
 /*----------------------------------------------------------------------------
diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
index d3c69f4..44baf93 100644
--- a/media/libeffects/visualizer/EffectVisualizer.cpp
+++ b/media/libeffects/visualizer/EffectVisualizer.cpp
@@ -106,7 +106,7 @@
             pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_ACCUMULATE) return -EINVAL;
     if (pConfig->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) return -EINVAL;
 
-    memcpy(&pContext->mConfig, pConfig, sizeof(effect_config_t));
+    pContext->mConfig = *pConfig;
 
     Visualizer_reset(pContext);
 
@@ -130,7 +130,7 @@
 
 void Visualizer_getConfig(VisualizerContext *pContext, effect_config_t *pConfig)
 {
-    memcpy(pConfig, &pContext->mConfig, sizeof(effect_config_t));
+    *pConfig = pContext->mConfig;
 }
 
 
@@ -190,7 +190,7 @@
     if (index > 0) {
         return -EINVAL;
     }
-    memcpy(pDescriptor, &gVisualizerDescriptor, sizeof(effect_descriptor_t));
+    *pDescriptor = gVisualizerDescriptor;
     return 0;
 }
 
@@ -253,7 +253,7 @@
     }
 
     if (memcmp(uuid, &gVisualizerDescriptor.uuid, sizeof(effect_uuid_t)) == 0) {
-        memcpy(pDescriptor, &gVisualizerDescriptor, sizeof(effect_descriptor_t));
+        *pDescriptor = gVisualizerDescriptor;
         return 0;
     }
 
@@ -561,7 +561,7 @@
         return -EINVAL;
     }
 
-    memcpy(pDescriptor, &gVisualizerDescriptor, sizeof(effect_descriptor_t));
+    *pDescriptor = gVisualizerDescriptor;
 
     return 0;
 }   /* end Visualizer_getDescriptor */
diff --git a/media/libmedia/AudioEffect.cpp b/media/libmedia/AudioEffect.cpp
index 34451ca..680604b 100644
--- a/media/libmedia/AudioEffect.cpp
+++ b/media/libmedia/AudioEffect.cpp
@@ -122,19 +122,12 @@
     mSessionId = sessionId;
 
     memset(&mDescriptor, 0, sizeof(effect_descriptor_t));
-    memcpy(&mDescriptor.type, EFFECT_UUID_NULL, sizeof(effect_uuid_t));
-    memcpy(&mDescriptor.uuid, EFFECT_UUID_NULL, sizeof(effect_uuid_t));
-
-    if (type != NULL) {
-        memcpy(&mDescriptor.type, type, sizeof(effect_uuid_t));
-    }
-    if (uuid != NULL) {
-        memcpy(&mDescriptor.uuid, uuid, sizeof(effect_uuid_t));
-    }
+    mDescriptor.type = *(type != NULL ? type : EFFECT_UUID_NULL);
+    mDescriptor.uuid = *(uuid != NULL ? uuid : EFFECT_UUID_NULL);
 
     mIEffectClient = new EffectClient(this);
 
-    iEffect = audioFlinger->createEffect(getpid(), (effect_descriptor_t *)&mDescriptor,
+    iEffect = audioFlinger->createEffect(getpid(), &mDescriptor,
             mIEffectClient, priority, io, mSessionId, &mStatus, &mId, &enabled);
 
     if (iEffect == 0 || (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS)) {
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 0562f8e..5060525 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -18,29 +18,19 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "AudioRecord"
 
-#include <stdint.h>
+#include <sys/resource.h>
 #include <sys/types.h>
 
-#include <sched.h>
-#include <sys/resource.h>
+#include <binder/IPCThreadState.h>
+#include <cutils/atomic.h>
+#include <cutils/compiler.h>
+#include <media/AudioRecord.h>
+#include <media/AudioSystem.h>
+#include <system/audio.h>
+#include <utils/Log.h>
 
 #include <private/media/AudioTrackShared.h>
 
-#include <media/AudioSystem.h>
-#include <media/AudioRecord.h>
-#include <media/mediarecorder.h>
-
-#include <binder/IServiceManager.h>
-#include <utils/Log.h>
-#include <binder/Parcel.h>
-#include <binder/IPCThreadState.h>
-#include <utils/Timers.h>
-#include <utils/Atomic.h>
-
-#include <system/audio.h>
-#include <cutils/bitops.h>
-#include <cutils/compiler.h>
-
 namespace android {
 // ---------------------------------------------------------------------------
 
@@ -49,18 +39,23 @@
         int* frameCount,
         uint32_t sampleRate,
         audio_format_t format,
-        int channelCount)
+        audio_channel_mask_t channelMask)
 {
+    if (frameCount == NULL) return BAD_VALUE;
+
+    // default to 0 in case of error
+    *frameCount = 0;
+
     size_t size = 0;
-    if (AudioSystem::getInputBufferSize(sampleRate, format, channelCount, &size)
+    if (AudioSystem::getInputBufferSize(sampleRate, format, channelMask, &size)
             != NO_ERROR) {
         ALOGE("AudioSystem could not query the input buffer size.");
         return NO_INIT;
     }
 
     if (size == 0) {
-        ALOGE("Unsupported configuration: sampleRate %d, format %d, channelCount %d",
-            sampleRate, format, channelCount);
+        ALOGE("Unsupported configuration: sampleRate %d, format %d, channelMask %#x",
+            sampleRate, format, channelMask);
         return BAD_VALUE;
     }
 
@@ -68,6 +63,7 @@
     size <<= 1;
 
     if (audio_is_linear_pcm(format)) {
+        int channelCount = popcount(channelMask);
         size /= channelCount * audio_bytes_per_sample(format);
     }
 
@@ -87,9 +83,8 @@
         audio_source_t inputSource,
         uint32_t sampleRate,
         audio_format_t format,
-        uint32_t channelMask,
+        audio_channel_mask_t channelMask,
         int frameCount,
-        record_flags flags,
         callback_t cbf,
         void* user,
         int notificationFrames,
@@ -98,7 +93,7 @@
       mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT)
 {
     mStatus = set(inputSource, sampleRate, format, channelMask,
-            frameCount, flags, cbf, user, notificationFrames, sessionId);
+            frameCount, cbf, user, notificationFrames, sessionId);
 }
 
 AudioRecord::~AudioRecord()
@@ -108,9 +103,10 @@
         // it is looping on buffer empty condition in obtainBuffer().
         // Otherwise the callback thread will never exit.
         stop();
-        if (mClientRecordThread != 0) {
-            mClientRecordThread->requestExitAndWait();
-            mClientRecordThread.clear();
+        if (mAudioRecordThread != 0) {
+            mAudioRecordThread->requestExit();  // see comment in AudioRecord.h
+            mAudioRecordThread->requestExitAndWait();
+            mAudioRecordThread.clear();
         }
         mAudioRecord.clear();
         IPCThreadState::self()->flushCommands();
@@ -122,9 +118,8 @@
         audio_source_t inputSource,
         uint32_t sampleRate,
         audio_format_t format,
-        uint32_t channelMask,
+        audio_channel_mask_t channelMask,
         int frameCount,
-        record_flags flags,
         callback_t cbf,
         void* user,
         int notificationFrames,
@@ -132,7 +127,7 @@
         int sessionId)
 {
 
-    ALOGV("set(): sampleRate %d, channelMask %d, frameCount %d",sampleRate, channelMask, frameCount);
+    ALOGV("set(): sampleRate %d, channelMask %#x, frameCount %d",sampleRate, channelMask, frameCount);
 
     AutoMutex lock(mLock);
 
@@ -174,7 +169,6 @@
                                                     sampleRate,
                                                     format,
                                                     channelMask,
-                                                    (audio_in_acoustics_t)flags,
                                                     mSessionId);
     if (input == 0) {
         ALOGE("Could not get audio input for record source %d", inputSource);
@@ -207,7 +201,8 @@
     }
 
     if (cbf != NULL) {
-        mClientRecordThread = new ClientRecordThread(*this, threadCanCallJava);
+        mAudioRecordThread = new AudioRecordThread(*this, threadCanCallJava);
+        mAudioRecordThread->run("AudioRecord", ANDROID_PRIORITY_AUDIO);
     }
 
     mStatus = NO_ERROR;
@@ -217,7 +212,7 @@
     mFrameCount = mCblk->frameCount;
     mChannelCount = (uint8_t)channelCount;
     mChannelMask = channelMask;
-    mActive = 0;
+    mActive = false;
     mCbf = cbf;
     mNotificationFrames = notificationFrames;
     mRemainingFrames = notificationFrames;
@@ -229,7 +224,6 @@
     mNewPosition = 0;
     mUpdatePeriod = 0;
     mInputSource = inputSource;
-    mFlags = flags;
     mInput = input;
     AudioSystem::acquireAudioSessionId(mSessionId);
 
@@ -282,41 +276,19 @@
 status_t AudioRecord::start(AudioSystem::sync_event_t event, int triggerSession)
 {
     status_t ret = NO_ERROR;
-    sp<ClientRecordThread> t = mClientRecordThread;
+    sp<AudioRecordThread> t = mAudioRecordThread;
 
     ALOGV("start, sync event %d trigger session %d", event, triggerSession);
 
-    if (t != 0) {
-        if (t->exitPending()) {
-            if (t->requestExitAndWait() == WOULD_BLOCK) {
-                ALOGE("AudioRecord::start called from thread");
-                return WOULD_BLOCK;
-            }
-        }
-    }
-
     AutoMutex lock(mLock);
     // acquire a strong reference on the IAudioRecord and IMemory so that they cannot be destroyed
     // while we are accessing the cblk
     sp<IAudioRecord> audioRecord = mAudioRecord;
     sp<IMemory> iMem = mCblkMemory;
     audio_track_cblk_t* cblk = mCblk;
-    if (mActive == 0) {
-        mActive = 1;
 
-        pid_t tid;
-        if (t != 0) {
-            mReadyToRun = WOULD_BLOCK;
-            t->run("AudioRecord", ANDROID_PRIORITY_AUDIO);
-            tid = t->getTid();  // pid_t is unknown until run()
-            ALOGV("getTid=%d", tid);
-            if (tid == -1) {
-                tid = 0;
-            }
-            // thread blocks in readyToRun()
-        } else {
-            tid = 0;    // not gettid()
-        }
+    if (!mActive) {
+        mActive = true;
 
         cblk->lock.lock();
         if (!(cblk->flags & CBLK_INVALID_MSK)) {
@@ -338,58 +310,51 @@
                                             AudioSystem::kSyncRecordStartTimeOutMs;
             cblk->waitTimeMs = 0;
             if (t != 0) {
-                // thread unblocks in readyToRun() and returns NO_ERROR
-                mReadyToRun = NO_ERROR;
-                mCondition.signal();
+                t->resume();
             } else {
                 mPreviousPriority = getpriority(PRIO_PROCESS, 0);
                 get_sched_policy(0, &mPreviousSchedulingGroup);
                 androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
             }
         } else {
-            mActive = 0;
-            // thread unblocks in readyToRun() and returns NO_INIT
-            mReadyToRun = NO_INIT;
-            mCondition.signal();
+            mActive = false;
         }
     }
 
     return ret;
 }
 
-status_t AudioRecord::stop()
+void AudioRecord::stop()
 {
-    sp<ClientRecordThread> t = mClientRecordThread;
+    sp<AudioRecordThread> t = mAudioRecordThread;
 
     ALOGV("stop");
 
     AutoMutex lock(mLock);
-    if (mActive == 1) {
-        mActive = 0;
+    if (mActive) {
+        mActive = false;
         mCblk->cv.signal();
         mAudioRecord->stop();
         // the record head position will reset to 0, so if a marker is set, we need
         // to activate it again
         mMarkerReached = false;
         if (t != 0) {
-            t->requestExit();
+            t->pause();
         } else {
             setpriority(PRIO_PROCESS, 0, mPreviousPriority);
             set_sched_policy(0, mPreviousSchedulingGroup);
         }
     }
-
-    return NO_ERROR;
 }
 
 bool AudioRecord::stopped() const
 {
+    AutoMutex lock(mLock);
     return !mActive;
 }
 
 uint32_t AudioRecord::getSampleRate() const
 {
-    AutoMutex lock(mLock);
     return mCblk->sampleRate;
 }
 
@@ -397,6 +362,7 @@
 {
     if (mCbf == NULL) return INVALID_OPERATION;
 
+    AutoMutex lock(mLock);
     mMarkerPosition = marker;
     mMarkerReached = false;
 
@@ -407,6 +373,7 @@
 {
     if (marker == NULL) return BAD_VALUE;
 
+    AutoMutex lock(mLock);
     *marker = mMarkerPosition;
 
     return NO_ERROR;
@@ -418,6 +385,8 @@
 
     uint32_t curPosition;
     getPosition(&curPosition);
+
+    AutoMutex lock(mLock);
     mNewPosition = curPosition + updatePeriod;
     mUpdatePeriod = updatePeriod;
 
@@ -428,6 +397,7 @@
 {
     if (updatePeriod == NULL) return BAD_VALUE;
 
+    AutoMutex lock(mLock);
     *updatePeriod = mUpdatePeriod;
 
     return NO_ERROR;
@@ -445,10 +415,8 @@
 
 unsigned int AudioRecord::getInputFramesLost() const
 {
-    if (mActive)
-        return AudioSystem::getInputFramesLost(mInput);
-    else
-        return 0;
+    // no need to check mActive, because if inactive this will return 0, which is what we want
+    return AudioSystem::getInputFramesLost(mInput);
 }
 
 // -------------------------------------------------------------------------
@@ -457,7 +425,7 @@
 status_t AudioRecord::openRecord_l(
         uint32_t sampleRate,
         audio_format_t format,
-        uint32_t channelMask,
+        audio_channel_mask_t channelMask,
         int frameCount,
         audio_io_handle_t input)
 {
@@ -467,13 +435,20 @@
         return NO_INIT;
     }
 
+    pid_t tid = -1;
+    // FIXME see similar logic at AudioTrack
+
+    int originalSessionId = mSessionId;
     sp<IAudioRecord> record = audioFlinger->openRecord(getpid(), input,
                                                        sampleRate, format,
                                                        channelMask,
                                                        frameCount,
                                                        IAudioFlinger::TRACK_DEFAULT,
+                                                       tid,
                                                        &mSessionId,
                                                        &status);
+    ALOGE_IF(originalSessionId != 0 && mSessionId != originalSessionId,
+            "session ID changed from %d to %d", originalSessionId, mSessionId);
 
     if (record == 0) {
         ALOGE("AudioFlinger could not create record track, status: %d", status);
@@ -499,7 +474,7 @@
 status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
 {
     AutoMutex lock(mLock);
-    int active;
+    bool active;
     status_t result = NO_ERROR;
     audio_track_cblk_t* cblk = mCblk;
     uint32_t framesReq = audioBuffer->frameCount;
@@ -528,7 +503,7 @@
                 result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs));
                 cblk->lock.unlock();
                 mLock.lock();
-                if (mActive == 0) {
+                if (!mActive) {
                     return status_t(STOPPED);
                 }
                 cblk->lock.lock();
@@ -613,13 +588,13 @@
                                 mCblk->sampleRate,
                                 mFormat,
                                 mChannelMask,
-                                (audio_in_acoustics_t)mFlags,
                                 mSessionId);
     return mInput;
 }
 
 int AudioRecord::getSessionId() const
 {
+    // no lock needed because session ID doesn't change after first set()
     return mSessionId;
 }
 
@@ -678,7 +653,7 @@
 
 // -------------------------------------------------------------------------
 
-bool AudioRecord::processAudioBuffer(const sp<ClientRecordThread>& thread)
+bool AudioRecord::processAudioBuffer(const sp<AudioRecordThread>& thread)
 {
     Buffer audioBuffer;
     uint32_t frames = mRemainingFrames;
@@ -690,22 +665,32 @@
     sp<IAudioRecord> audioRecord = mAudioRecord;
     sp<IMemory> iMem = mCblkMemory;
     audio_track_cblk_t* cblk = mCblk;
+    bool active = mActive;
+    uint32_t markerPosition = mMarkerPosition;
+    uint32_t newPosition = mNewPosition;
+    uint32_t user = cblk->user;
+    // determine whether a marker callback will be needed, while locked
+    bool needMarker = !mMarkerReached && (mMarkerPosition > 0) && (user >= mMarkerPosition);
+    if (needMarker) {
+        mMarkerReached = true;
+    }
+    // determine the number of new position callback(s) that will be needed, while locked
+    uint32_t updatePeriod = mUpdatePeriod;
+    uint32_t needNewPos = updatePeriod > 0 && user >= newPosition ?
+            ((user - newPosition) / updatePeriod) + 1 : 0;
+    mNewPosition = newPosition + updatePeriod * needNewPos;
     mLock.unlock();
 
-    // Manage marker callback
-    if (!mMarkerReached && (mMarkerPosition > 0)) {
-        if (cblk->user >= mMarkerPosition) {
-            mCbf(EVENT_MARKER, mUserData, (void *)&mMarkerPosition);
-            mMarkerReached = true;
-        }
+    // perform marker callback, while unlocked
+    if (needMarker) {
+        mCbf(EVENT_MARKER, mUserData, &markerPosition);
     }
 
-    // Manage new position callback
-    if (mUpdatePeriod > 0) {
-        while (cblk->user >= mNewPosition) {
-            mCbf(EVENT_NEW_POS, mUserData, (void *)&mNewPosition);
-            mNewPosition += mUpdatePeriod;
-        }
+    // perform new position callback(s), while unlocked
+    for (; needNewPos > 0; --needNewPos) {
+        uint32_t temp = newPosition;
+        mCbf(EVENT_NEW_POS, mUserData, &temp);
+        newPosition += updatePeriod;
     }
 
     do {
@@ -748,10 +733,12 @@
 
 
     // Manage overrun callback
-    if (mActive && (cblk->framesAvailable() == 0)) {
+    if (active && (cblk->framesAvailable() == 0)) {
+        // The value of active is stale, but we are almost sure to be active here because
+        // otherwise we would have exited when obtainBuffer returned STOPPED earlier.
         ALOGV("Overrun user: %x, server: %x, flags %04x", cblk->user, cblk->server, cblk->flags);
         if (!(android_atomic_or(CBLK_UNDERRUN_ON, &cblk->flags) & CBLK_UNDERRUN_MSK)) {
-            mCbf(EVENT_OVERRUN, mUserData, 0);
+            mCbf(EVENT_OVERRUN, mUserData, NULL);
         }
     }
 
@@ -805,7 +792,7 @@
             result = NO_ERROR;
             cblk->lock.unlock();
         }
-        if (result != NO_ERROR || mActive == 0) {
+        if (result != NO_ERROR || !mActive) {
             result = status_t(STOPPED);
         }
     }
@@ -825,23 +812,51 @@
 
 // =========================================================================
 
-AudioRecord::ClientRecordThread::ClientRecordThread(AudioRecord& receiver, bool bCanCallJava)
-    : Thread(bCanCallJava), mReceiver(receiver)
+AudioRecord::AudioRecordThread::AudioRecordThread(AudioRecord& receiver, bool bCanCallJava)
+    : Thread(bCanCallJava), mReceiver(receiver), mPaused(true)
 {
 }
 
-bool AudioRecord::ClientRecordThread::threadLoop()
+AudioRecord::AudioRecordThread::~AudioRecordThread()
 {
-    return mReceiver.processAudioBuffer(this);
 }
 
-status_t AudioRecord::ClientRecordThread::readyToRun()
+bool AudioRecord::AudioRecordThread::threadLoop()
 {
-    AutoMutex(mReceiver.mLock);
-    while (mReceiver.mReadyToRun == WOULD_BLOCK) {
-        mReceiver.mCondition.wait(mReceiver.mLock);
+    {
+        AutoMutex _l(mMyLock);
+        if (mPaused) {
+            mMyCond.wait(mMyLock);
+            // caller will check for exitPending()
+            return true;
+        }
     }
-    return mReceiver.mReadyToRun;
+    if (!mReceiver.processAudioBuffer(this)) {
+        pause();
+    }
+    return true;
+}
+
+void AudioRecord::AudioRecordThread::requestExit()
+{
+    // must be in this order to avoid a race condition
+    Thread::requestExit();
+    resume();
+}
+
+void AudioRecord::AudioRecordThread::pause()
+{
+    AutoMutex _l(mMyLock);
+    mPaused = true;
+}
+
+void AudioRecord::AudioRecordThread::resume()
+{
+    AutoMutex _l(mMyLock);
+    if (mPaused) {
+        mPaused = false;
+        mMyCond.signal();
+    }
 }
 
 // -------------------------------------------------------------------------
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 4c41ba5..6e0c620 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -41,7 +41,7 @@
 // Cached values for recording queries, all protected by gLock
 uint32_t AudioSystem::gPrevInSamplingRate = 16000;
 audio_format_t AudioSystem::gPrevInFormat = AUDIO_FORMAT_PCM_16_BIT;
-int AudioSystem::gPrevInChannelCount = 1;
+audio_channel_mask_t AudioSystem::gPrevInChannelMask = AUDIO_CHANNEL_IN_MONO;
 size_t AudioSystem::gInBuffSize = 0;
 
 
@@ -334,25 +334,25 @@
     return NO_ERROR;
 }
 
-status_t AudioSystem::getInputBufferSize(uint32_t sampleRate, audio_format_t format, int channelCount,
-    size_t* buffSize)
+status_t AudioSystem::getInputBufferSize(uint32_t sampleRate, audio_format_t format,
+        audio_channel_mask_t channelMask, size_t* buffSize)
 {
     gLock.lock();
     // Do we have a stale gInBufferSize or are we requesting the input buffer size for new values
     size_t inBuffSize = gInBuffSize;
     if ((inBuffSize == 0) || (sampleRate != gPrevInSamplingRate) || (format != gPrevInFormat)
-        || (channelCount != gPrevInChannelCount)) {
+        || (channelMask != gPrevInChannelMask)) {
         gLock.unlock();
         const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
         if (af == 0) {
             return PERMISSION_DENIED;
         }
-        inBuffSize = af->getInputBufferSize(sampleRate, format, channelCount);
+        inBuffSize = af->getInputBufferSize(sampleRate, format, channelMask);
         gLock.lock();
         // save the request params
         gPrevInSamplingRate = sampleRate;
         gPrevInFormat = format;
-        gPrevInChannelCount = channelCount;
+        gPrevInChannelMask = channelMask;
 
         gInBuffSize = inBuffSize;
     }
@@ -449,7 +449,7 @@
 
         OutputDescriptor *outputDesc =  new OutputDescriptor(*desc);
         gOutputs.add(ioHandle, outputDesc);
-        ALOGV("ioConfigChanged() new output samplingRate %d, format %d channels %d frameCount %d latency %d",
+        ALOGV("ioConfigChanged() new output samplingRate %d, format %d channels %#x frameCount %d latency %d",
                 outputDesc->samplingRate, outputDesc->format, outputDesc->channels, outputDesc->frameCount, outputDesc->latency);
         } break;
     case OUTPUT_CLOSED: {
@@ -471,7 +471,7 @@
         if (param2 == NULL) break;
         desc = (const OutputDescriptor *)param2;
 
-        ALOGV("ioConfigChanged() new config for output %d samplingRate %d, format %d channels %d frameCount %d latency %d",
+        ALOGV("ioConfigChanged() new config for output %d samplingRate %d, format %d channels %#x frameCount %d latency %d",
                 ioHandle, desc->samplingRate, desc->format,
                 desc->channels, desc->frameCount, desc->latency);
         OutputDescriptor *outputDesc = gOutputs.valueAt(index);
@@ -588,12 +588,12 @@
 audio_io_handle_t AudioSystem::getOutput(audio_stream_type_t stream,
                                     uint32_t samplingRate,
                                     audio_format_t format,
-                                    uint32_t channels,
+                                    audio_channel_mask_t channelMask,
                                     audio_output_flags_t flags)
 {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
     if (aps == 0) return 0;
-    return aps->getOutput(stream, samplingRate, format, channels, flags);
+    return aps->getOutput(stream, samplingRate, format, channelMask, flags);
 }
 
 status_t AudioSystem::startOutput(audio_io_handle_t output,
@@ -624,13 +624,12 @@
 audio_io_handle_t AudioSystem::getInput(audio_source_t inputSource,
                                     uint32_t samplingRate,
                                     audio_format_t format,
-                                    uint32_t channels,
-                                    audio_in_acoustics_t acoustics,
+                                    audio_channel_mask_t channelMask,
                                     int sessionId)
 {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
     if (aps == 0) return 0;
-    return aps->getInput(inputSource, samplingRate, format, channels, acoustics, sessionId);
+    return aps->getInput(inputSource, samplingRate, format, channelMask, sessionId);
 }
 
 status_t AudioSystem::startInput(audio_io_handle_t input)
@@ -695,14 +694,14 @@
     return aps->getDevicesForStream(stream);
 }
 
-audio_io_handle_t AudioSystem::getOutputForEffect(effect_descriptor_t *desc)
+audio_io_handle_t AudioSystem::getOutputForEffect(const effect_descriptor_t *desc)
 {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
     if (aps == 0) return PERMISSION_DENIED;
     return aps->getOutputForEffect(desc);
 }
 
-status_t AudioSystem::registerEffect(effect_descriptor_t *desc,
+status_t AudioSystem::registerEffect(const effect_descriptor_t *desc,
                                 audio_io_handle_t io,
                                 uint32_t strategy,
                                 int session,
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index e5a60f5..0ca035f 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -54,6 +54,11 @@
         audio_stream_type_t streamType,
         uint32_t sampleRate)
 {
+    if (frameCount == NULL) return BAD_VALUE;
+
+    // default to 0 in case of error
+    *frameCount = 0;
+
     // FIXME merge with similar code in createTrack_l(), except we're missing
     //       some information here that is available in createTrack_l():
     //          audio_io_handle_t output
@@ -98,7 +103,7 @@
         audio_stream_type_t streamType,
         uint32_t sampleRate,
         audio_format_t format,
-        int channelMask,
+        audio_channel_mask_t channelMask,
         int frameCount,
         audio_output_flags_t flags,
         callback_t cbf,
@@ -131,7 +136,8 @@
       mIsTimed(false),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT)
 {
-    mStatus = set((audio_stream_type_t)streamType, sampleRate, (audio_format_t)format, channelMask,
+    mStatus = set((audio_stream_type_t)streamType, sampleRate, (audio_format_t)format,
+            (audio_channel_mask_t) channelMask,
             frameCount, (audio_output_flags_t)flags, cbf, user, notificationFrames,
             0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId);
 }
@@ -140,7 +146,7 @@
         audio_stream_type_t streamType,
         uint32_t sampleRate,
         audio_format_t format,
-        int channelMask,
+        audio_channel_mask_t channelMask,
         const sp<IMemory>& sharedBuffer,
         audio_output_flags_t flags,
         callback_t cbf,
@@ -181,7 +187,7 @@
         audio_stream_type_t streamType,
         uint32_t sampleRate,
         audio_format_t format,
-        int channelMask,
+        audio_channel_mask_t channelMask,
         int frameCount,
         audio_output_flags_t flags,
         callback_t cbf,
@@ -247,7 +253,7 @@
     }
 
     if (!audio_is_output_channel(channelMask)) {
-        ALOGE("Invalid channel mask");
+        ALOGE("Invalid channel mask %#x", channelMask);
         return BAD_VALUE;
     }
     uint32_t channelCount = popcount(channelMask);
@@ -272,34 +278,29 @@
     mFlags = flags;
     mCbf = cbf;
 
-    if (cbf != NULL) {
-        mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);
-        mAudioTrackThread->run("AudioTrack", ANDROID_PRIORITY_AUDIO, 0 /*stack*/);
-    }
-
     // create the IAudioTrack
     status_t status = createTrack_l(streamType,
                                   sampleRate,
                                   format,
-                                  (uint32_t)channelMask,
+                                  channelMask,
                                   frameCount,
                                   flags,
                                   sharedBuffer,
                                   output);
-
     if (status != NO_ERROR) {
-        if (mAudioTrackThread != 0) {
-            mAudioTrackThread->requestExit();
-            mAudioTrackThread.clear();
-        }
         return status;
     }
 
+    if (cbf != NULL) {
+        mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);
+        mAudioTrackThread->run("AudioTrack", ANDROID_PRIORITY_AUDIO);
+    }
+
     mStatus = NO_ERROR;
 
     mStreamType = streamType;
     mFormat = format;
-    mChannelMask = (uint32_t)channelMask;
+    mChannelMask = channelMask;
     mChannelCount = channelCount;
     mSharedBuffer = sharedBuffer;
     mMuted = false;
@@ -367,7 +368,6 @@
 void AudioTrack::start()
 {
     sp<AudioTrackThread> t = mAudioTrackThread;
-    status_t status = NO_ERROR;
 
     ALOGV("start %p", this);
 
@@ -395,6 +395,7 @@
         }
 
         ALOGV("start %p before lock cblk %p", this, mCblk);
+        status_t status = NO_ERROR;
         if (!(cblk->flags & CBLK_INVALID_MSK)) {
             cblk->lock.unlock();
             ALOGV("mAudioTrack->start()");
@@ -744,7 +745,7 @@
         audio_stream_type_t streamType,
         uint32_t sampleRate,
         audio_format_t format,
-        uint32_t channelMask,
+        audio_channel_mask_t channelMask,
         int frameCount,
         audio_output_flags_t flags,
         const sp<IMemory>& sharedBuffer,
@@ -1472,15 +1473,6 @@
     return true;
 }
 
-status_t AudioTrack::AudioTrackThread::readyToRun()
-{
-    return NO_ERROR;
-}
-
-void AudioTrack::AudioTrackThread::onFirstRef()
-{
-}
-
 void AudioTrack::AudioTrackThread::requestExit()
 {
     // must be in this order to avoid a race condition
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index e8dd438..71e7c31 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -32,7 +32,7 @@
     CREATE_TRACK = IBinder::FIRST_CALL_TRANSACTION,
     OPEN_RECORD,
     SAMPLE_RATE,
-    CHANNEL_COUNT,
+    CHANNEL_COUNT,  // obsolete
     FORMAT,
     FRAME_COUNT,
     LATENCY,
@@ -86,7 +86,7 @@
                                 audio_stream_type_t streamType,
                                 uint32_t sampleRate,
                                 audio_format_t format,
-                                uint32_t channelMask,
+                                audio_channel_mask_t channelMask,
                                 int frameCount,
                                 track_flags_t flags,
                                 const sp<IMemory>& sharedBuffer,
@@ -135,9 +135,10 @@
                                 audio_io_handle_t input,
                                 uint32_t sampleRate,
                                 audio_format_t format,
-                                uint32_t channelMask,
+                                audio_channel_mask_t channelMask,
                                 int frameCount,
                                 track_flags_t flags,
+                                pid_t tid,
                                 int *sessionId,
                                 status_t *status)
     {
@@ -151,6 +152,7 @@
         data.writeInt32(channelMask);
         data.writeInt32(frameCount);
         data.writeInt32(flags);
+        data.writeInt32((int32_t) tid);
         int lSessionId = 0;
         if (sessionId != NULL) {
             lSessionId = *sessionId;
@@ -182,6 +184,7 @@
         return reply.readInt32();
     }
 
+#if 0
     virtual int channelCount(audio_io_handle_t output) const
     {
         Parcel data, reply;
@@ -190,6 +193,7 @@
         remote()->transact(CHANNEL_COUNT, data, &reply);
         return reply.readInt32();
     }
+#endif
 
     virtual audio_format_t format(audio_io_handle_t output) const
     {
@@ -347,13 +351,14 @@
         remote()->transact(REGISTER_CLIENT, data, &reply);
     }
 
-    virtual size_t getInputBufferSize(uint32_t sampleRate, audio_format_t format, int channelCount) const
+    virtual size_t getInputBufferSize(uint32_t sampleRate, audio_format_t format,
+            audio_channel_mask_t channelMask) const
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
         data.writeInt32(sampleRate);
         data.writeInt32(format);
-        data.writeInt32(channelCount);
+        data.writeInt32(channelMask);
         remote()->transact(GET_INPUTBUFFERSIZE, data, &reply);
         return reply.readInt32();
     }
@@ -698,7 +703,7 @@
             int streamType = data.readInt32();
             uint32_t sampleRate = data.readInt32();
             audio_format_t format = (audio_format_t) data.readInt32();
-            int channelCount = data.readInt32();
+            audio_channel_mask_t channelMask = data.readInt32();
             size_t bufferCount = data.readInt32();
             track_flags_t flags = (track_flags_t) data.readInt32();
             sp<IMemory> buffer = interface_cast<IMemory>(data.readStrongBinder());
@@ -708,7 +713,7 @@
             status_t status;
             sp<IAudioTrack> track = createTrack(pid,
                     (audio_stream_type_t) streamType, sampleRate, format,
-                    channelCount, bufferCount, flags, buffer, output, tid, &sessionId, &status);
+                    channelMask, bufferCount, flags, buffer, output, tid, &sessionId, &status);
             reply->writeInt32(sessionId);
             reply->writeInt32(status);
             reply->writeStrongBinder(track->asBinder());
@@ -720,13 +725,14 @@
             audio_io_handle_t input = (audio_io_handle_t) data.readInt32();
             uint32_t sampleRate = data.readInt32();
             audio_format_t format = (audio_format_t) data.readInt32();
-            int channelCount = data.readInt32();
+            audio_channel_mask_t channelMask = data.readInt32();
             size_t bufferCount = data.readInt32();
             track_flags_t flags = (track_flags_t) data.readInt32();
+            pid_t tid = (pid_t) data.readInt32();
             int sessionId = data.readInt32();
             status_t status;
             sp<IAudioRecord> record = openRecord(pid, input,
-                    sampleRate, format, channelCount, bufferCount, flags, &sessionId, &status);
+                    sampleRate, format, channelMask, bufferCount, flags, tid, &sessionId, &status);
             reply->writeInt32(sessionId);
             reply->writeInt32(status);
             reply->writeStrongBinder(record->asBinder());
@@ -737,11 +743,13 @@
             reply->writeInt32( sampleRate((audio_io_handle_t) data.readInt32()) );
             return NO_ERROR;
         } break;
+#if 0
         case CHANNEL_COUNT: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             reply->writeInt32( channelCount((audio_io_handle_t) data.readInt32()) );
             return NO_ERROR;
         } break;
+#endif
         case FORMAT: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             reply->writeInt32( format((audio_io_handle_t) data.readInt32()) );
@@ -846,8 +854,8 @@
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             uint32_t sampleRate = data.readInt32();
             audio_format_t format = (audio_format_t) data.readInt32();
-            int channelCount = data.readInt32();
-            reply->writeInt32( getInputBufferSize(sampleRate, format, channelCount) );
+            audio_channel_mask_t channelMask = data.readInt32();
+            reply->writeInt32( getInputBufferSize(sampleRate, format, channelMask) );
             return NO_ERROR;
         } break;
         case OPEN_OUTPUT: {
diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp
index 7aab8d6..31c5d27 100644
--- a/media/libmedia/IAudioPolicyService.cpp
+++ b/media/libmedia/IAudioPolicyService.cpp
@@ -123,7 +123,7 @@
                                         audio_stream_type_t stream,
                                         uint32_t samplingRate,
                                         audio_format_t format,
-                                        uint32_t channels,
+                                        audio_channel_mask_t channelMask,
                                         audio_output_flags_t flags)
     {
         Parcel data, reply;
@@ -131,7 +131,7 @@
         data.writeInt32(static_cast <uint32_t>(stream));
         data.writeInt32(samplingRate);
         data.writeInt32(static_cast <uint32_t>(format));
-        data.writeInt32(channels);
+        data.writeInt32(channelMask);
         data.writeInt32(static_cast <uint32_t>(flags));
         remote()->transact(GET_OUTPUT, data, &reply);
         return static_cast <audio_io_handle_t> (reply.readInt32());
@@ -175,8 +175,7 @@
                                     audio_source_t inputSource,
                                     uint32_t samplingRate,
                                     audio_format_t format,
-                                    uint32_t channels,
-                                    audio_in_acoustics_t acoustics,
+                                    audio_channel_mask_t channelMask,
                                     int audioSession)
     {
         Parcel data, reply;
@@ -184,8 +183,7 @@
         data.writeInt32((int32_t) inputSource);
         data.writeInt32(samplingRate);
         data.writeInt32(static_cast <uint32_t>(format));
-        data.writeInt32(channels);
-        data.writeInt32(static_cast <uint32_t>(acoustics));
+        data.writeInt32(channelMask);
         data.writeInt32(audioSession);
         remote()->transact(GET_INPUT, data, &reply);
         return static_cast <audio_io_handle_t> (reply.readInt32());
@@ -276,7 +274,7 @@
         return (audio_devices_t) reply.readInt32();
     }
 
-    virtual audio_io_handle_t getOutputForEffect(effect_descriptor_t *desc)
+    virtual audio_io_handle_t getOutputForEffect(const effect_descriptor_t *desc)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
@@ -285,7 +283,7 @@
         return static_cast <audio_io_handle_t> (reply.readInt32());
     }
 
-    virtual status_t registerEffect(effect_descriptor_t *desc,
+    virtual status_t registerEffect(const effect_descriptor_t *desc,
                                         audio_io_handle_t io,
                                         uint32_t strategy,
                                         int session,
@@ -417,14 +415,14 @@
                     static_cast <audio_stream_type_t>(data.readInt32());
             uint32_t samplingRate = data.readInt32();
             audio_format_t format = (audio_format_t) data.readInt32();
-            uint32_t channels = data.readInt32();
+            audio_channel_mask_t channelMask = data.readInt32();
             audio_output_flags_t flags =
                     static_cast <audio_output_flags_t>(data.readInt32());
 
             audio_io_handle_t output = getOutput(stream,
                                                  samplingRate,
                                                  format,
-                                                 channels,
+                                                 channelMask,
                                                  flags);
             reply->writeInt32(static_cast <int>(output));
             return NO_ERROR;
@@ -464,15 +462,12 @@
             audio_source_t inputSource = (audio_source_t) data.readInt32();
             uint32_t samplingRate = data.readInt32();
             audio_format_t format = (audio_format_t) data.readInt32();
-            uint32_t channels = data.readInt32();
-            audio_in_acoustics_t acoustics =
-                    static_cast <audio_in_acoustics_t>(data.readInt32());
+            audio_channel_mask_t channelMask = data.readInt32();
             int audioSession = data.readInt32();
             audio_io_handle_t input = getInput(inputSource,
                                                samplingRate,
                                                format,
-                                               channels,
-                                               acoustics,
+                                               channelMask,
                                                audioSession);
             reply->writeInt32(static_cast <int>(input));
             return NO_ERROR;
diff --git a/media/libmedia/IAudioRecord.cpp b/media/libmedia/IAudioRecord.cpp
index 57a80a9..0d06e98 100644
--- a/media/libmedia/IAudioRecord.cpp
+++ b/media/libmedia/IAudioRecord.cpp
@@ -42,7 +42,7 @@
     {
     }
 
-    virtual status_t start(int event, int triggerSession)
+    virtual status_t start(int /*AudioSystem::sync_event_t*/ event, int triggerSession)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioRecord::getInterfaceDescriptor());
@@ -92,7 +92,7 @@
         } break;
         case START: {
             CHECK_INTERFACE(IAudioRecord, data, reply);
-            int event = data.readInt32();
+            int /*AudioSystem::sync_event_t*/ event = data.readInt32();
             int triggerSession = data.readInt32();
             reply->writeInt32(start(event, triggerSession));
             return NO_ERROR;
diff --git a/media/libmedia/Visualizer.cpp b/media/libmedia/Visualizer.cpp
index de0bf7d..8196e10 100644
--- a/media/libmedia/Visualizer.cpp
+++ b/media/libmedia/Visualizer.cpp
@@ -353,13 +353,4 @@
     return false;
 }
 
-status_t Visualizer::CaptureThread::readyToRun()
-{
-    return NO_ERROR;
-}
-
-void Visualizer::CaptureThread::onFirstRef()
-{
-}
-
 }; // namespace android
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 727fd0d..e49c218 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -1410,7 +1410,6 @@
 
     uint32_t encoder_flags = 0;
     if (mIsMetaDataStoredInVideoBuffers) {
-        encoder_flags |= OMXCodec::kHardwareCodecsOnly;
         encoder_flags |= OMXCodec::kStoreMetaDataInVideoBuffers;
     }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 86e122f..daf60f6 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -258,7 +258,9 @@
             ALOGV("scanning sources haveAudio=%d, haveVideo=%d",
                  mAudioDecoder != NULL, mVideoDecoder != NULL);
 
-            instantiateDecoder(false, &mVideoDecoder);
+            if (mNativeWindow != NULL) {
+                instantiateDecoder(false, &mVideoDecoder);
+            }
 
             if (mAudioSink != NULL) {
                 instantiateDecoder(true, &mAudioDecoder);
@@ -279,7 +281,8 @@
                 break;
             }
 
-            if (mAudioDecoder == NULL || mVideoDecoder == NULL) {
+            if (mAudioDecoder == NULL && mAudioSink != NULL ||
+                mVideoDecoder == NULL && mNativeWindow != NULL) {
                 msg->post(100000ll);
                 mScanSourcesPending = true;
             }
@@ -500,6 +503,8 @@
                 CHECK(msg->findInt32("audio", &audio));
 
                 ALOGV("renderer %s flush completed.", audio ? "audio" : "video");
+            } else if (what == Renderer::kWhatVideoRenderingStart) {
+                notifyListener(MEDIA_INFO, MEDIA_INFO_RENDERING_START, 0);
             }
             break;
         }
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 1f13955..8a75f83 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -47,6 +47,7 @@
       mHasVideo(false),
       mSyncQueues(false),
       mPaused(false),
+      mVideoRenderingStarted(false),
       mLastPositionUpdateUs(-1ll),
       mVideoLateByUs(0ll) {
 }
@@ -387,9 +388,20 @@
     mVideoQueue.erase(mVideoQueue.begin());
     entry = NULL;
 
+    if (!mVideoRenderingStarted) {
+        mVideoRenderingStarted = true;
+        notifyVideoRenderingStart();
+    }
+
     notifyPosition();
 }
 
+void NuPlayer::Renderer::notifyVideoRenderingStart() {
+    sp<AMessage> notify = mNotify->dup();
+    notify->setInt32("what", kWhatVideoRenderingStart);
+    notify->post();
+}
+
 void NuPlayer::Renderer::notifyEOS(bool audio, status_t finalResult) {
     sp<AMessage> notify = mNotify->dup();
     notify->setInt32("what", kWhatEOS);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index 268628b..e4368c7 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -45,9 +45,10 @@
     void resume();
 
     enum {
-        kWhatEOS                = 'eos ',
-        kWhatFlushComplete      = 'fluC',
-        kWhatPosition           = 'posi',
+        kWhatEOS                 = 'eos ',
+        kWhatFlushComplete       = 'fluC',
+        kWhatPosition            = 'posi',
+        kWhatVideoRenderingStart = 'vdrd',
     };
 
 protected:
@@ -99,6 +100,7 @@
     bool mSyncQueues;
 
     bool mPaused;
+    bool mVideoRenderingStarted;
 
     int64_t mLastPositionUpdateUs;
     int64_t mVideoLateByUs;
@@ -120,6 +122,7 @@
     void notifyFlushComplete(bool audio);
     void notifyPosition();
     void notifyVideoLateBy(int64_t lateByUs);
+    void notifyVideoRenderingStart();
 
     void flushQueue(List<QueueEntry> *queue);
     bool dropBufferWhileFlushing(bool audio, const sp<AMessage> &msg);
diff --git a/media/libstagefright/AACWriter.cpp b/media/libstagefright/AACWriter.cpp
index 284ba01..33b7bd5 100644
--- a/media/libstagefright/AACWriter.cpp
+++ b/media/libstagefright/AACWriter.cpp
@@ -28,6 +28,8 @@
 #include <media/stagefright/MetaData.h>
 #include <media/mediarecorder.h>
 #include <sys/prctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 #include <fcntl.h>
 
 namespace android {
@@ -44,7 +46,7 @@
 
     ALOGV("AACWriter Constructor");
 
-    mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR);
+    mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
     if (mFd >= 0) {
         mInitCheck = OK;
     }
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index c4743a1..f96a429 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -595,7 +595,7 @@
     // Dequeue buffers and send them to OMX
     for (OMX_U32 i = 0; i < def.nBufferCountActual; i++) {
         ANativeWindowBuffer *buf;
-        err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf);
+        err = native_window_dequeue_buffer_and_wait(mNativeWindow.get(), &buf);
         if (err != 0) {
             ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), -err);
             break;
@@ -653,7 +653,7 @@
          mComponentName.c_str(), info->mBufferID);
 
     int err = mNativeWindow->cancelBuffer(
-        mNativeWindow.get(), info->mGraphicBuffer.get());
+        mNativeWindow.get(), info->mGraphicBuffer.get(), -1);
 
     CHECK_EQ(err, 0);
 
@@ -664,7 +664,8 @@
 
 ACodec::BufferInfo *ACodec::dequeueBufferFromNativeWindow() {
     ANativeWindowBuffer *buf;
-    if (mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf) != 0) {
+    int fenceFd = -1;
+    if (native_window_dequeue_buffer_and_wait(mNativeWindow.get(), &buf) != 0) {
         ALOGE("dequeueBuffer failed.");
         return NULL;
     }
@@ -1357,7 +1358,8 @@
            || format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar
            || format.eColorFormat == OMX_COLOR_FormatCbYCrY
            || format.eColorFormat == OMX_TI_COLOR_FormatYUV420PackedSemiPlanar
-           || format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar);
+           || format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar
+           || format.eColorFormat == OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka);
 
     return mOMX->setParameter(
             mNode, OMX_IndexParamVideoPortFormat,
@@ -2188,7 +2190,8 @@
     // on the screen and then been replaced, so an previous video frames are
     // guaranteed NOT to be currently displayed.
     for (int i = 0; i < numBufs + 1; i++) {
-        err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &anb);
+        int fenceFd = -1;
+        err = native_window_dequeue_buffer_and_wait(mNativeWindow.get(), &anb);
         if (err != NO_ERROR) {
             ALOGE("error pushing blank frames: dequeueBuffer failed: %s (%d)",
                     strerror(-err), -err);
@@ -2196,13 +2199,6 @@
         }
 
         sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
-        err = mNativeWindow->lockBuffer(mNativeWindow.get(),
-                buf->getNativeBuffer());
-        if (err != NO_ERROR) {
-            ALOGE("error pushing blank frames: lockBuffer failed: %s (%d)",
-                    strerror(-err), -err);
-            goto error;
-        }
 
         // Fill the buffer with the a 1x1 checkerboard pattern ;)
         uint32_t* img = NULL;
@@ -2223,7 +2219,7 @@
         }
 
         err = mNativeWindow->queueBuffer(mNativeWindow.get(),
-                buf->getNativeBuffer());
+                buf->getNativeBuffer(), -1);
         if (err != NO_ERROR) {
             ALOGE("error pushing blank frames: queueBuffer failed: %s (%d)",
                     strerror(-err), -err);
@@ -2238,7 +2234,7 @@
     if (err != NO_ERROR) {
         // Clean up after an error.
         if (anb != NULL) {
-            mNativeWindow->cancelBuffer(mNativeWindow.get(), anb);
+            mNativeWindow->cancelBuffer(mNativeWindow.get(), anb, -1);
         }
 
         native_window_api_disconnect(mNativeWindow.get(),
@@ -2751,7 +2747,7 @@
         status_t err;
         if ((err = mCodec->mNativeWindow->queueBuffer(
                     mCodec->mNativeWindow.get(),
-                    info->mGraphicBuffer.get())) == OK) {
+                    info->mGraphicBuffer.get(), -1)) == OK) {
             info->mStatus = BufferInfo::OWNED_BY_NATIVE_WINDOW;
         } else {
             mCodec->signalError(OMX_ErrorUndefined, err);
@@ -3253,11 +3249,6 @@
             if (info->mStatus == BufferInfo::OWNED_BY_NATIVE_WINDOW) {
                 continue;
             }
-
-            status_t err = mCodec->mNativeWindow->lockBuffer(
-                    mCodec->mNativeWindow.get(),
-                    info->mGraphicBuffer.get());
-            CHECK_EQ(err, (status_t)OK);
         } else {
             CHECK_EQ((int)info->mStatus, (int)BufferInfo::OWNED_BY_US);
         }
diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp
index ca85640..15a7143 100644
--- a/media/libstagefright/AMRWriter.cpp
+++ b/media/libstagefright/AMRWriter.cpp
@@ -36,7 +36,7 @@
       mPaused(false),
       mResumed(false) {
 
-    mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR);
+    mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
     if (mFd >= 0) {
         mInitCheck = OK;
     }
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 8ad1cb9..e5b4d75 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -81,6 +81,7 @@
         libssl \
         libstagefright_omx \
         libstagefright_yuv \
+        libsync \
         libui \
         libutils \
         libvorbisidec \
@@ -97,12 +98,12 @@
         libstagefright_id3 \
         libFLAC \
 
-ifneq ($(TARGET_BUILD_PDK), true)
-LOCAL_STATIC_LIBRARIES += \
-	libstagefright_chromium_http
-LOCAL_SHARED_LIBRARIES += \
-        libchromium_net
+LOCAL_SRC_FILES += \
+        chromium_http_stub.cpp
 LOCAL_CPPFLAGS += -DCHROMIUM_AVAILABLE=1
+
+ifneq ($(TARGET_BUILD_PDK), true)
+LOCAL_REQUIRED_MODULES := libstagefright_chromium_http
 endif
 
 LOCAL_SHARED_LIBRARIES += libstlport
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index 72d797e..ed142a4 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -48,7 +48,8 @@
 
 AudioSource::AudioSource(
         audio_source_t inputSource, uint32_t sampleRate, uint32_t channelCount)
-    : mStarted(false),
+    : mRecord(NULL),
+      mStarted(false),
       mSampleRate(sampleRate),
       mPrevSampleTimeUs(0),
       mNumFramesReceived(0),
@@ -61,7 +62,7 @@
     status_t status = AudioRecord::getMinFrameCount(&minFrameCount,
                                            sampleRate,
                                            AUDIO_FORMAT_PCM_16_BIT,
-                                           channelCount);
+                                           audio_channel_in_mask_from_count(channelCount));
     if (status == OK) {
         // make sure that the AudioRecord callback never returns more than the maximum
         // buffer size
@@ -73,15 +74,10 @@
             bufCount++;
         }
 
-        AudioRecord::record_flags flags = (AudioRecord::record_flags)
-                        (AudioRecord::RECORD_AGC_ENABLE |
-                         AudioRecord::RECORD_NS_ENABLE  |
-                         AudioRecord::RECORD_IIR_ENABLE);
         mRecord = new AudioRecord(
                     inputSource, sampleRate, AUDIO_FORMAT_PCM_16_BIT,
                     audio_channel_in_mask_from_count(channelCount),
                     bufCount * frameCount,
-                    flags,
                     AudioRecordCallbackFunction,
                     this,
                     frameCount);
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 0f346d8..664d5dd 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -130,7 +130,7 @@
         CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
         native_window_set_buffers_timestamp(mNativeWindow.get(), timeUs * 1000);
         status_t err = mNativeWindow->queueBuffer(
-                mNativeWindow.get(), buffer->graphicBuffer().get());
+                mNativeWindow.get(), buffer->graphicBuffer().get(), -1);
         if (err != 0) {
             ALOGE("queueBuffer failed with error %s (%d)", strerror(-err),
                     -err);
@@ -183,6 +183,7 @@
     : mQueueStarted(false),
       mUIDValid(false),
       mTimeSource(NULL),
+      mVideoRenderingStarted(false),
       mVideoRendererIsPreview(false),
       mAudioPlayer(NULL),
       mDisplayWidth(0),
@@ -468,6 +469,7 @@
 }
 
 void AwesomePlayer::reset_l() {
+    mVideoRenderingStarted = false;
     mActiveAudioTrackIndex = -1;
     mDisplayWidth = 0;
     mDisplayHeight = 0;
@@ -710,7 +712,6 @@
                              kHighWaterMarkBytes);
                         modifyFlags(CACHE_UNDERRUN, CLEAR);
                         play_l();
-                        notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
                     } else if (mFlags & PREPARING) {
                         ALOGV("cache has filled up (> %d), prepare is done",
                              kHighWaterMarkBytes);
@@ -770,7 +771,6 @@
                           cachedDurationUs / 1E6);
                     play_l();
                 }
-                notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
             } else if (mFlags & PREPARING) {
                 ALOGV("cache has filled up (%.2f secs), prepare is done",
                      cachedDurationUs / 1E6);
@@ -1807,6 +1807,11 @@
     if (mVideoRenderer != NULL) {
         mSinceLastDropped++;
         mVideoRenderer->render(mVideoBuffer);
+        if (!mVideoRenderingStarted) {
+            mVideoRenderingStarted = true;
+            notifyListener_l(MEDIA_INFO, MEDIA_INFO_RENDERING_START);
+        }
+
     }
 
     mVideoBuffer->release();
@@ -2626,6 +2631,9 @@
             mFlags |= value;
             break;
         case CLEAR:
+            if ((value & CACHE_UNDERRUN) && (mFlags & CACHE_UNDERRUN)) {
+                notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
+            }
             mFlags &= ~value;
             break;
         case ASSIGN:
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 3ddad93..a604c8f 100755
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -111,6 +111,10 @@
        return OMX_TI_COLOR_FormatYUV420PackedSemiPlanar;
     }
 
+    if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_ANDROID_OPAQUE)) {
+        return OMX_COLOR_FormatAndroidOpaque;
+    }
+
     ALOGE("Uknown color format (%s), please add it to "
          "CameraSource::getColorFormat", colorFormat);
 
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index c75f100..1de808e 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -17,7 +17,7 @@
 #include "include/AMRExtractor.h"
 
 #if CHROMIUM_AVAILABLE
-#include "include/DataUriSource.h"
+#include "include/chromium_http_stub.h"
 #endif
 
 #include "include/MP3Extractor.h"
@@ -173,7 +173,7 @@
 
 # if CHROMIUM_AVAILABLE
     } else if (!strncasecmp("data:", uri, 5)) {
-        source = new DataUriSource(uri);
+        source = createDataUriSource(uri);
 #endif
     } else {
         // Assume it's a filename.
diff --git a/media/libstagefright/FLACExtractor.cpp b/media/libstagefright/FLACExtractor.cpp
index 668d7f7..29bb056 100644
--- a/media/libstagefright/FLACExtractor.cpp
+++ b/media/libstagefright/FLACExtractor.cpp
@@ -350,7 +350,7 @@
         for (FLAC__uint32 i = 0; i < vc->num_comments; ++i) {
             FLAC__StreamMetadata_VorbisComment_Entry *vce;
             vce = &vc->comments[i];
-            if (mFileMetadata != 0) {
+            if (mFileMetadata != 0 && vce->entry != NULL) {
                 parseVorbisComment(mFileMetadata, (const char *) vce->entry,
                         vce->length);
             }
diff --git a/media/libstagefright/HTTPBase.cpp b/media/libstagefright/HTTPBase.cpp
index d7eea3f..40bfc55 100644
--- a/media/libstagefright/HTTPBase.cpp
+++ b/media/libstagefright/HTTPBase.cpp
@@ -21,7 +21,7 @@
 #include "include/HTTPBase.h"
 
 #if CHROMIUM_AVAILABLE
-#include "include/ChromiumHTTPDataSource.h"
+#include "include/chromium_http_stub.h"
 #endif
 
 #include <media/stagefright/foundation/ADebug.h>
@@ -46,7 +46,10 @@
 // static
 sp<HTTPBase> HTTPBase::Create(uint32_t flags) {
 #if CHROMIUM_AVAILABLE
-        return new ChromiumHTTPDataSource(flags);
+        HTTPBase *dataSource = createChromiumHTTPDataSource(flags);
+        if (dataSource) {
+           return dataSource;
+        }
 #endif
     {
         TRESPASS();
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 755b502..5aad99f 100755
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -42,6 +42,7 @@
 
 namespace android {
 
+static const int64_t kMinStreamableFileSizeInBytes = 5 * 1024 * 1024;
 static const int64_t kMax32BitFileSize = 0x007fffffffLL;
 static const uint8_t kNalUnitTypeSeqParamSet = 0x07;
 static const uint8_t kNalUnitTypePicParamSet = 0x08;
@@ -75,6 +76,128 @@
         kSampleArraySize = 1000,
     };
 
+    // A helper class to handle faster write box with table entries
+    template<class TYPE>
+    struct ListTableEntries {
+        ListTableEntries(uint32_t elementCapacity, uint32_t entryCapacity)
+            : mElementCapacity(elementCapacity),
+            mEntryCapacity(entryCapacity),
+            mTotalNumTableEntries(0),
+            mNumValuesInCurrEntry(0),
+            mCurrTableEntriesElement(NULL) {
+            CHECK_GT(mElementCapacity, 0);
+            CHECK_GT(mEntryCapacity, 0);
+        }
+
+        // Free the allocated memory.
+        ~ListTableEntries() {
+            while (!mTableEntryList.empty()) {
+                typename List<TYPE *>::iterator it = mTableEntryList.begin();
+                delete[] (*it);
+                mTableEntryList.erase(it);
+            }
+        }
+
+        // Replace the value at the given position by the given value.
+        // There must be an existing value at the given position.
+        // @arg value must be in network byte order
+        // @arg pos location the value must be in.
+        void set(const TYPE& value, uint32_t pos) {
+            CHECK_LT(pos, mTotalNumTableEntries * mEntryCapacity);
+
+            typename List<TYPE *>::iterator it = mTableEntryList.begin();
+            uint32_t iterations = (pos / (mElementCapacity * mEntryCapacity));
+            while (it != mTableEntryList.end() && iterations > 0) {
+                ++it;
+                --iterations;
+            }
+            CHECK(it != mTableEntryList.end());
+            CHECK_EQ(iterations, 0);
+
+            (*it)[(pos % (mElementCapacity * mEntryCapacity))] = value;
+        }
+
+        // Get the value at the given position by the given value.
+        // @arg value the retrieved value at the position in network byte order.
+        // @arg pos location the value must be in.
+        // @return true if a value is found.
+        bool get(TYPE& value, uint32_t pos) const {
+            if (pos >= mTotalNumTableEntries * mEntryCapacity) {
+                return false;
+            }
+
+            typename List<TYPE *>::iterator it = mTableEntryList.begin();
+            uint32_t iterations = (pos / (mElementCapacity * mEntryCapacity));
+            while (it != mTableEntryList.end() && iterations > 0) {
+                ++it;
+                --iterations;
+            }
+            CHECK(it != mTableEntryList.end());
+            CHECK_EQ(iterations, 0);
+
+            value = (*it)[(pos % (mElementCapacity * mEntryCapacity))];
+            return true;
+        }
+
+        // Store a single value.
+        // @arg value must be in network byte order.
+        void add(const TYPE& value) {
+            CHECK_LT(mNumValuesInCurrEntry, mElementCapacity);
+            uint32_t nEntries = mTotalNumTableEntries % mElementCapacity;
+            uint32_t nValues  = mNumValuesInCurrEntry % mEntryCapacity;
+            if (nEntries == 0 && nValues == 0) {
+                mCurrTableEntriesElement = new TYPE[mEntryCapacity * mElementCapacity];
+                CHECK(mCurrTableEntriesElement != NULL);
+                mTableEntryList.push_back(mCurrTableEntriesElement);
+            }
+
+            uint32_t pos = nEntries * mEntryCapacity + nValues;
+            mCurrTableEntriesElement[pos] = value;
+
+            ++mNumValuesInCurrEntry;
+            if ((mNumValuesInCurrEntry % mEntryCapacity) == 0) {
+                ++mTotalNumTableEntries;
+                mNumValuesInCurrEntry = 0;
+            }
+        }
+
+        // Write out the table entries:
+        // 1. the number of entries goes first
+        // 2. followed by the values in the table enties in order
+        // @arg writer the writer to actual write to the storage
+        void write(MPEG4Writer *writer) const {
+            CHECK_EQ(mNumValuesInCurrEntry % mEntryCapacity, 0);
+            uint32_t nEntries = mTotalNumTableEntries;
+            writer->writeInt32(nEntries);
+            for (typename List<TYPE *>::iterator it = mTableEntryList.begin();
+                it != mTableEntryList.end(); ++it) {
+                CHECK_GT(nEntries, 0);
+                if (nEntries >= mElementCapacity) {
+                    writer->write(*it, sizeof(TYPE) * mEntryCapacity, mElementCapacity);
+                    nEntries -= mElementCapacity;
+                } else {
+                    writer->write(*it, sizeof(TYPE) * mEntryCapacity, nEntries);
+                    break;
+                }
+            }
+        }
+
+        // Return the number of entries in the table.
+        uint32_t count() const { return mTotalNumTableEntries; }
+
+    private:
+        uint32_t         mElementCapacity;  // # entries in an element
+        uint32_t         mEntryCapacity;    // # of values in each entry
+        uint32_t         mTotalNumTableEntries;
+        uint32_t         mNumValuesInCurrEntry;  // up to mEntryCapacity
+        TYPE             *mCurrTableEntriesElement;
+        mutable List<TYPE *>     mTableEntryList;
+
+        DISALLOW_EVIL_CONSTRUCTORS(ListTableEntries);
+    };
+
+
+
     MPEG4Writer *mOwner;
     sp<MetaData> mMeta;
     sp<MediaSource> mSource;
@@ -90,67 +213,25 @@
     int64_t mMaxChunkDurationUs;
 
     bool mIsRealTimeRecording;
-    int64_t mMaxTimeStampUs;
     int64_t mEstimatedTrackSizeBytes;
     int64_t mMdatSizeBytes;
     int32_t mTimeScale;
 
     pthread_t mThread;
 
-    /*
-     * mNumSamples is used to track the total number of samples in
-     * mSampleSizes List.
-     *
-     * A linked list of fixed sized array is used here to reduce the time
-     * to write out stsz box.
-     */
-    uint32_t            mNumSamples;
-    uint32_t*           mCurrentSampleSizeArr;
-    List<uint32_t *>    mSampleSizes;
-    bool                mSamplesHaveSameSize;
 
     List<MediaBuffer *> mChunkSamples;
 
-    size_t              mNumStcoTableEntries;
-    List<off64_t>         mChunkOffsets;
+    bool                mSamplesHaveSameSize;
+    ListTableEntries<uint32_t> *mStszTableEntries;
 
-    size_t              mNumStscTableEntries;
-    struct StscTableEntry {
+    ListTableEntries<uint32_t> *mStcoTableEntries;
+    ListTableEntries<off64_t> *mCo64TableEntries;
+    ListTableEntries<uint32_t> *mStscTableEntries;
+    ListTableEntries<uint32_t> *mStssTableEntries;
+    ListTableEntries<uint32_t> *mSttsTableEntries;
+    ListTableEntries<uint32_t> *mCttsTableEntries;
 
-        StscTableEntry(uint32_t chunk, uint32_t samples, uint32_t id)
-            : firstChunk(chunk),
-              samplesPerChunk(samples),
-              sampleDescriptionId(id) {}
-
-        uint32_t firstChunk;
-        uint32_t samplesPerChunk;
-        uint32_t sampleDescriptionId;
-    };
-    List<StscTableEntry> mStscTableEntries;
-
-    size_t        mNumStssTableEntries;
-    List<int32_t> mStssTableEntries;
-
-    struct SttsTableEntry {
-
-        SttsTableEntry(uint32_t count, uint32_t duration)
-            : sampleCount(count), sampleDuration(duration) {}
-
-        uint32_t sampleCount;
-        uint32_t sampleDuration;  // time scale based
-    };
-    size_t        mNumSttsTableEntries;
-    List<SttsTableEntry> mSttsTableEntries;
-
-    struct CttsTableEntry {
-        CttsTableEntry(uint32_t count, int32_t timescaledDur)
-            : sampleCount(count), sampleDuration(timescaledDur) {}
-
-        uint32_t sampleCount;
-        uint32_t sampleDuration;  // time scale based
-    };
-    size_t        mNumCttsTableEntries;
-    List<CttsTableEntry> mCttsTableEntries;
     int64_t mMinCttsOffsetTimeUs;
     int64_t mMaxCttsOffsetTimeUs;
 
@@ -269,7 +350,7 @@
       mAreGeoTagsAvailable(false),
       mStartTimeOffsetMs(-1) {
 
-    mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR);
+    mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
     if (mFd >= 0) {
         mInitCheck = OK;
     }
@@ -333,6 +414,10 @@
     snprintf(buffer, SIZE, "       reached EOS: %s\n",
             mReachedEOS? "true": "false");
     result.append(buffer);
+    snprintf(buffer, SIZE, "       frames encoded : %d\n", mStszTableEntries->count());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "       duration encoded : %lld us\n", mTrackDurationUs);
+    result.append(buffer);
     ::write(fd, result.string(), result.size());
     return OK;
 }
@@ -487,8 +572,16 @@
     CHECK_GT(mTimeScale, 0);
     ALOGV("movie time scale: %d", mTimeScale);
 
-    mStreamableFile = true;
-    mWriteMoovBoxToMemory = false;
+    /*
+     * When the requested file size limit is small, the priority
+     * is to meet the file size limit requirement, rather than
+     * to make the file streamable.
+     */
+    mStreamableFile =
+        (mMaxFileSizeLimitBytes != 0 &&
+         mMaxFileSizeLimitBytes >= kMinStreamableFileSizeInBytes);
+
+    mWriteMoovBoxToMemory = mStreamableFile;
     mMoovBoxBuffer = NULL;
     mMoovBoxBufferOffset = 0;
 
@@ -504,11 +597,16 @@
         mEstimatedMoovBoxSize = estimateMoovBoxSize(bitRate);
     }
     CHECK_GE(mEstimatedMoovBoxSize, 8);
-    lseek64(mFd, mFreeBoxOffset, SEEK_SET);
-    writeInt32(mEstimatedMoovBoxSize);
-    write("free", 4);
+    if (mStreamableFile) {
+        // Reserve a 'free' box only for streamable file
+        lseek64(mFd, mFreeBoxOffset, SEEK_SET);
+        writeInt32(mEstimatedMoovBoxSize);
+        write("free", 4);
+        mMdatOffset = mFreeBoxOffset + mEstimatedMoovBoxSize;
+    } else {
+        mMdatOffset = mOffset;
+    }
 
-    mMdatOffset = mFreeBoxOffset + mEstimatedMoovBoxSize;
     mOffset = mMdatOffset;
     lseek64(mFd, mMdatOffset, SEEK_SET);
     if (mUse32BitOffset) {
@@ -689,7 +787,7 @@
     lseek64(mFd, mOffset, SEEK_SET);
 
     const off64_t moovOffset = mOffset;
-    mWriteMoovBoxToMemory = true;
+    mWriteMoovBoxToMemory = mStreamableFile;
     mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize);
     mMoovBoxBufferOffset = 0;
     CHECK(mMoovBoxBuffer != NULL);
@@ -1062,6 +1160,10 @@
         nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes();
     }
 
+    if (!mStreamableFile) {
+        // Add 1024 bytes as error tolerance
+        return nTotalBytesEstimate + 1024 >= mMaxFileSizeLimitBytes;
+    }
     // Be conservative in the estimate: do not exceed 95% of
     // the target file limit. For small target file size limit, though,
     // this will not help.
@@ -1131,6 +1233,13 @@
       mTrackDurationUs(0),
       mEstimatedTrackSizeBytes(0),
       mSamplesHaveSameSize(true),
+      mStszTableEntries(new ListTableEntries<uint32_t>(1000, 1)),
+      mStcoTableEntries(new ListTableEntries<uint32_t>(1000, 1)),
+      mCo64TableEntries(new ListTableEntries<off64_t>(1000, 1)),
+      mStscTableEntries(new ListTableEntries<uint32_t>(1000, 3)),
+      mStssTableEntries(new ListTableEntries<uint32_t>(1000, 1)),
+      mSttsTableEntries(new ListTableEntries<uint32_t>(1000, 2)),
+      mCttsTableEntries(new ListTableEntries<uint32_t>(1000, 2)),
       mCodecSpecificData(NULL),
       mCodecSpecificDataSize(0),
       mGotAllCodecSpecificData(false),
@@ -1150,20 +1259,20 @@
 
 void MPEG4Writer::Track::updateTrackSizeEstimate() {
 
-    int64_t stcoBoxSizeBytes = mOwner->use32BitFileOffset()
-                                ? mNumStcoTableEntries * 4
-                                : mNumStcoTableEntries * 8;
-
-    int64_t stszBoxSizeBytes = mSamplesHaveSameSize? 4: (mNumSamples * 4);
+    uint32_t stcoBoxCount = (mOwner->use32BitFileOffset()
+                            ? mStcoTableEntries->count()
+                            : mCo64TableEntries->count());
+    int64_t stcoBoxSizeBytes = stcoBoxCount * 4;
+    int64_t stszBoxSizeBytes = mSamplesHaveSameSize? 4: (mStszTableEntries->count() * 4);
 
     mEstimatedTrackSizeBytes = mMdatSizeBytes;  // media data size
     if (!mOwner->isFileStreamable()) {
         // Reserved free space is not large enough to hold
         // all meta data and thus wasted.
-        mEstimatedTrackSizeBytes += mNumStscTableEntries * 12 +  // stsc box size
-                                    mNumStssTableEntries * 4 +   // stss box size
-                                    mNumSttsTableEntries * 8 +   // stts box size
-                                    mNumCttsTableEntries * 8 +   // ctts box size
+        mEstimatedTrackSizeBytes += mStscTableEntries->count() * 12 +  // stsc box size
+                                    mStssTableEntries->count() * 4 +   // stss box size
+                                    mSttsTableEntries->count() * 8 +   // stts box size
+                                    mCttsTableEntries->count() * 8 +   // ctts box size
                                     stcoBoxSizeBytes +           // stco box size
                                     stszBoxSizeBytes;            // stsz box size
     }
@@ -1172,14 +1281,13 @@
 void MPEG4Writer::Track::addOneStscTableEntry(
         size_t chunkId, size_t sampleId) {
 
-        StscTableEntry stscEntry(chunkId, sampleId, 1);
-        mStscTableEntries.push_back(stscEntry);
-        ++mNumStscTableEntries;
+        mStscTableEntries->add(htonl(chunkId));
+        mStscTableEntries->add(htonl(sampleId));
+        mStscTableEntries->add(htonl(1));
 }
 
 void MPEG4Writer::Track::addOneStssTableEntry(size_t sampleId) {
-    mStssTableEntries.push_back(sampleId);
-    ++mNumStssTableEntries;
+    mStssTableEntries->add(htonl(sampleId));
 }
 
 void MPEG4Writer::Track::addOneSttsTableEntry(
@@ -1188,9 +1296,8 @@
     if (duration == 0) {
         ALOGW("0-duration samples found: %d", sampleCount);
     }
-    SttsTableEntry sttsEntry(sampleCount, duration);
-    mSttsTableEntries.push_back(sttsEntry);
-    ++mNumSttsTableEntries;
+    mSttsTableEntries->add(htonl(sampleCount));
+    mSttsTableEntries->add(htonl(duration));
 }
 
 void MPEG4Writer::Track::addOneCttsTableEntry(
@@ -1199,14 +1306,17 @@
     if (mIsAudio) {
         return;
     }
-    CttsTableEntry cttsEntry(sampleCount, duration);
-    mCttsTableEntries.push_back(cttsEntry);
-    ++mNumCttsTableEntries;
+    mCttsTableEntries->add(htonl(sampleCount));
+    mCttsTableEntries->add(htonl(duration));
 }
 
 void MPEG4Writer::Track::addChunkOffset(off64_t offset) {
-    ++mNumStcoTableEntries;
-    mChunkOffsets.push_back(offset);
+    if (mOwner->use32BitFileOffset()) {
+        uint32_t value = offset;
+        mStcoTableEntries->add(htonl(value));
+    } else {
+        mCo64TableEntries->add(hton64(offset));
+    }
 }
 
 void MPEG4Writer::Track::setTimeScale() {
@@ -1265,16 +1375,26 @@
 MPEG4Writer::Track::~Track() {
     stop();
 
+    delete mStszTableEntries;
+    delete mStcoTableEntries;
+    delete mCo64TableEntries;
+    delete mStscTableEntries;
+    delete mSttsTableEntries;
+    delete mStssTableEntries;
+    delete mCttsTableEntries;
+
+    mStszTableEntries = NULL;
+    mStcoTableEntries = NULL;
+    mCo64TableEntries = NULL;
+    mStscTableEntries = NULL;
+    mSttsTableEntries = NULL;
+    mStssTableEntries = NULL;
+    mCttsTableEntries = NULL;
+
     if (mCodecSpecificData != NULL) {
         free(mCodecSpecificData);
         mCodecSpecificData = NULL;
     }
-
-    while (!mSampleSizes.empty()) {
-        List<uint32_t *>::iterator it = mSampleSizes.begin();
-        delete[] (*it);
-        mSampleSizes.erase(it);
-    }
 }
 
 void MPEG4Writer::Track::initTrackingProgressStatus(MetaData *params) {
@@ -1517,13 +1637,7 @@
     mTrackDurationUs = 0;
     mReachedEOS = false;
     mEstimatedTrackSizeBytes = 0;
-    mNumStcoTableEntries = 0;
-    mNumStssTableEntries = 0;
-    mNumStscTableEntries = 0;
-    mNumSttsTableEntries = 0;
-    mNumCttsTableEntries = 0;
     mMdatSizeBytes = 0;
-
     mMaxChunkDurationUs = 0;
 
     pthread_create(&mThread, &attr, ThreadWrapper, this);
@@ -1859,6 +1973,7 @@
     int64_t currCttsOffsetTimeTicks = 0;   // Timescale based ticks
     int64_t lastCttsOffsetTimeTicks = -1;  // Timescale based ticks
     int32_t cttsSampleCount = 0;           // Sample count in the current ctts table entry
+    uint32_t lastSamplesPerChunk = 0;
 
     if (mIsAudio) {
         prctl(PR_SET_NAME, (unsigned long)"AudioTrackEncoding", 0, 0, 0);
@@ -1869,7 +1984,6 @@
 
     sp<MetaData> meta_data;
 
-    mNumSamples = 0;
     status_t err = OK;
     MediaBuffer *buffer;
     while (!mDone && (err = mSource->read(&buffer)) == OK) {
@@ -1958,7 +2072,7 @@
         CHECK(meta_data->findInt64(kKeyTime, &timestampUs));
 
 ////////////////////////////////////////////////////////////////////////////////
-        if (mNumSamples == 0) {
+        if (mStszTableEntries->count() == 0) {
             mFirstSampleTimeRealUs = systemTime() / 1000;
             mStartTimestampUs = timestampUs;
             mOwner->setStartTimestampUs(mStartTimestampUs);
@@ -1996,7 +2110,7 @@
             currCttsOffsetTimeTicks =
                     (cttsOffsetTimeUs * mTimeScale + 500000LL) / 1000000LL;
             CHECK_LE(currCttsOffsetTimeTicks, 0x0FFFFFFFFLL);
-            if (mNumSamples == 0) {
+            if (mStszTableEntries->count() == 0) {
                 // Force the first ctts table entry to have one single entry
                 // so that we can do adjustment for the initial track start
                 // time offset easily in writeCttsBox().
@@ -2014,7 +2128,7 @@
             }
 
             // Update ctts time offset range
-            if (mNumSamples == 0) {
+            if (mStszTableEntries->count() == 0) {
                 mMinCttsOffsetTimeUs = currCttsOffsetTimeTicks;
                 mMaxCttsOffsetTimeUs = currCttsOffsetTimeTicks;
             } else {
@@ -2048,22 +2162,18 @@
         currDurationTicks =
             ((timestampUs * mTimeScale + 500000LL) / 1000000LL -
                 (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL);
-        CHECK_GE(currDurationTicks, 0ll);
-
-        if ((mNumSamples % kSampleArraySize) == 0) {
-            uint32_t *arr = new uint32_t[kSampleArraySize];
-            CHECK(arr != NULL);
-            mSampleSizes.push_back(arr);
-            mCurrentSampleSizeArr = arr;
+        if (currDurationTicks < 0ll) {
+            ALOGE("timestampUs %lld < lastTimestampUs %lld for %s track",
+                timestampUs, lastTimestampUs, mIsAudio? "Audio": "Video");
+            return UNKNOWN_ERROR;
         }
 
-        mCurrentSampleSizeArr[mNumSamples % kSampleArraySize] = htonl(sampleSize);
-        ++mNumSamples;
-        if (mNumSamples > 2) {
+        mStszTableEntries->add(htonl(sampleSize));
+        if (mStszTableEntries->count() > 2) {
 
             // Force the first sample to have its own stts entry so that
             // we can adjust its value later to maintain the A/V sync.
-            if (mNumSamples == 3 || currDurationTicks != lastDurationTicks) {
+            if (mStszTableEntries->count() == 3 || currDurationTicks != lastDurationTicks) {
                 addOneSttsTableEntry(sampleCount, lastDurationTicks);
                 sampleCount = 1;
             } else {
@@ -2072,7 +2182,7 @@
 
         }
         if (mSamplesHaveSameSize) {
-            if (mNumSamples >= 2 && previousSampleSize != sampleSize) {
+            if (mStszTableEntries->count() >= 2 && previousSampleSize != sampleSize) {
                 mSamplesHaveSameSize = false;
             }
             previousSampleSize = sampleSize;
@@ -2084,7 +2194,7 @@
         lastTimestampUs = timestampUs;
 
         if (isSync != 0) {
-            addOneStssTableEntry(mNumSamples);
+            addOneStssTableEntry(mStszTableEntries->count());
         }
 
         if (mTrackingProgressStatus) {
@@ -2096,7 +2206,12 @@
         if (!hasMultipleTracks) {
             off64_t offset = mIsAvc? mOwner->addLengthPrefixedSample_l(copy)
                                  : mOwner->addSample_l(copy);
-            if (mChunkOffsets.empty()) {
+
+            uint32_t count = (mOwner->use32BitFileOffset()
+                        ? mStcoTableEntries->count()
+                        : mCo64TableEntries->count());
+
+            if (count == 0) {
                 addChunkOffset(offset);
             }
             copy->release();
@@ -2119,9 +2234,9 @@
                     }
                     ++nChunks;
                     if (nChunks == 1 ||  // First chunk
-                        (--(mStscTableEntries.end()))->samplesPerChunk !=
-                         mChunkSamples.size()) {
-                        addOneStscTableEntry(nChunks, mChunkSamples.size());
+                        lastSamplesPerChunk != mChunkSamples.size()) {
+                        lastSamplesPerChunk = mChunkSamples.size();
+                        addOneStscTableEntry(nChunks, lastSamplesPerChunk);
                     }
                     bufferChunk(timestampUs);
                     chunkTimestampUs = timestampUs;
@@ -2139,7 +2254,7 @@
 
     // Last chunk
     if (!hasMultipleTracks) {
-        addOneStscTableEntry(1, mNumSamples);
+        addOneStscTableEntry(1, mStszTableEntries->count());
     } else if (!mChunkSamples.empty()) {
         addOneStscTableEntry(++nChunks, mChunkSamples.size());
         bufferChunk(timestampUs);
@@ -2148,14 +2263,14 @@
     // We don't really know how long the last frame lasts, since
     // there is no frame time after it, just repeat the previous
     // frame's duration.
-    if (mNumSamples == 1) {
+    if (mStszTableEntries->count() == 1) {
         lastDurationUs = 0;  // A single sample's duration
         lastDurationTicks = 0;
     } else {
         ++sampleCount;  // Count for the last sample
     }
 
-    if (mNumSamples <= 2) {
+    if (mStszTableEntries->count() <= 2) {
         addOneSttsTableEntry(1, lastDurationTicks);
         if (sampleCount - 1 > 0) {
             addOneSttsTableEntry(sampleCount - 1, lastDurationTicks);
@@ -2178,7 +2293,7 @@
     sendTrackSummary(hasMultipleTracks);
 
     ALOGI("Received total/0-length (%d/%d) buffers and encoded %d frames. - %s",
-            count, nZeroLengthFrames, mNumSamples, mIsAudio? "audio": "video");
+            count, nZeroLengthFrames, mStszTableEntries->count(), mIsAudio? "audio": "video");
     if (mIsAudio) {
         ALOGI("Audio track drift time: %lld us", mOwner->getDriftTimeUs());
     }
@@ -2190,12 +2305,12 @@
 }
 
 bool MPEG4Writer::Track::isTrackMalFormed() const {
-    if (mSampleSizes.empty()) {                      // no samples written
+    if (mStszTableEntries->count() == 0) {                      // no samples written
         ALOGE("The number of recorded samples is 0");
         return true;
     }
 
-    if (!mIsAudio && mNumStssTableEntries == 0) {  // no sync frames for video
+    if (!mIsAudio && mStssTableEntries->count() == 0) {  // no sync frames for video
         ALOGE("There are no sync frames for video track");
         return true;
     }
@@ -2226,7 +2341,7 @@
 
     mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
                     trackNum | MEDIA_RECORDER_TRACK_INFO_ENCODED_FRAMES,
-                    mNumSamples);
+                    mStszTableEntries->count());
 
     {
         // The system delay time excluding the requested initial delay that
@@ -2264,6 +2379,7 @@
 
 void MPEG4Writer::Track::trackProgressStatus(int64_t timeUs, status_t err) {
     ALOGV("trackProgressStatus: %lld us", timeUs);
+
     if (mTrackEveryTimeDurationUs > 0 &&
         timeUs - mPreviousTrackTimeUs >= mTrackEveryTimeDurationUs) {
         ALOGV("Fire time tracking progress status at %lld us", timeUs);
@@ -2734,21 +2850,11 @@
 void MPEG4Writer::Track::writeSttsBox() {
     mOwner->beginBox("stts");
     mOwner->writeInt32(0);  // version=0, flags=0
-    mOwner->writeInt32(mNumSttsTableEntries);
-
-    // Compensate for small start time difference from different media tracks
-    List<SttsTableEntry>::iterator it = mSttsTableEntries.begin();
-    CHECK(it != mSttsTableEntries.end() && it->sampleCount == 1);
-    mOwner->writeInt32(it->sampleCount);
-    mOwner->writeInt32(getStartTimeOffsetScaledTime() + it->sampleDuration);
-
-    int64_t totalCount = 1;
-    while (++it != mSttsTableEntries.end()) {
-        mOwner->writeInt32(it->sampleCount);
-        mOwner->writeInt32(it->sampleDuration);
-        totalCount += it->sampleCount;
-    }
-    CHECK_EQ(totalCount, mNumSamples);
+    uint32_t duration;
+    CHECK(mSttsTableEntries->get(duration, 1));
+    duration = htonl(duration);  // Back to host byte order
+    mSttsTableEntries->set(htonl(duration + getStartTimeOffsetScaledTime()), 1);
+    mSttsTableEntries->write(mOwner);
     mOwner->endBox();  // stts
 }
 
@@ -2763,101 +2869,52 @@
     }
 
     // Do not write ctts box when there is no need to have it.
-    if ((mNumCttsTableEntries == 1 &&
-        mCttsTableEntries.begin()->sampleDuration == 0) ||
-        mNumCttsTableEntries == 0) {
+    if (mCttsTableEntries->count() == 0) {
         return;
     }
 
-    ALOGD("ctts box has %d entries with range [%lld, %lld]",
-            mNumCttsTableEntries, mMinCttsOffsetTimeUs, mMaxCttsOffsetTimeUs);
+    ALOGV("ctts box has %d entries with range [%lld, %lld]",
+            mCttsTableEntries->count(), mMinCttsOffsetTimeUs, mMaxCttsOffsetTimeUs);
 
     mOwner->beginBox("ctts");
-    // Version 1 allows to use negative offset time value, but
-    // we are sticking to version 0 for now.
     mOwner->writeInt32(0);  // version=0, flags=0
-    mOwner->writeInt32(mNumCttsTableEntries);
-
-    // Compensate for small start time difference from different media tracks
-    List<CttsTableEntry>::iterator it = mCttsTableEntries.begin();
-    CHECK(it != mCttsTableEntries.end() && it->sampleCount == 1);
-    mOwner->writeInt32(it->sampleCount);
-    mOwner->writeInt32(getStartTimeOffsetScaledTime() +
-            it->sampleDuration - mMinCttsOffsetTimeUs);
-
-    int64_t totalCount = 1;
-    while (++it != mCttsTableEntries.end()) {
-        mOwner->writeInt32(it->sampleCount);
-        mOwner->writeInt32(it->sampleDuration - mMinCttsOffsetTimeUs);
-        totalCount += it->sampleCount;
-    }
-    CHECK_EQ(totalCount, mNumSamples);
+    uint32_t duration;
+    CHECK(mCttsTableEntries->get(duration, 1));
+    duration = htonl(duration);  // Back host byte order
+    mCttsTableEntries->set(htonl(duration + getStartTimeOffsetScaledTime() - mMinCttsOffsetTimeUs), 1);
+    mCttsTableEntries->write(mOwner);
     mOwner->endBox();  // ctts
 }
 
 void MPEG4Writer::Track::writeStssBox() {
     mOwner->beginBox("stss");
     mOwner->writeInt32(0);  // version=0, flags=0
-    mOwner->writeInt32(mNumStssTableEntries);  // number of sync frames
-    for (List<int32_t>::iterator it = mStssTableEntries.begin();
-        it != mStssTableEntries.end(); ++it) {
-        mOwner->writeInt32(*it);
-    }
+    mStssTableEntries->write(mOwner);
     mOwner->endBox();  // stss
 }
 
 void MPEG4Writer::Track::writeStszBox() {
-    ALOGD("writeStszBox for %s track", isAudio()? "Audio": "Video");
     mOwner->beginBox("stsz");
     mOwner->writeInt32(0);  // version=0, flags=0
-    if (mSamplesHaveSameSize) {
-        CHECK(mCurrentSampleSizeArr != 0);
-        mOwner->write(mCurrentSampleSizeArr, 4, 1);  // default sample size
-    } else {
-        mOwner->writeInt32(0);
-    }
-    mOwner->writeInt32(mNumSamples);
-    uint32_t nSamples = mNumSamples;
-    if (!mSamplesHaveSameSize) {
-        for (List<uint32_t *>::iterator it = mSampleSizes.begin();
-            it != mSampleSizes.end(); ++it) {
-            if (nSamples >= kSampleArraySize) {
-                mOwner->write(*it, 4, kSampleArraySize);
-                nSamples -= kSampleArraySize;
-            } else {
-                mOwner->write(*it, 4, nSamples);
-                break;
-            }
-        }
-    }
+    mOwner->writeInt32(0);
+    mStszTableEntries->write(mOwner);
     mOwner->endBox();  // stsz
-    ALOGD("writeStszBox: X");
 }
 
 void MPEG4Writer::Track::writeStscBox() {
     mOwner->beginBox("stsc");
     mOwner->writeInt32(0);  // version=0, flags=0
-    mOwner->writeInt32(mNumStscTableEntries);
-    for (List<StscTableEntry>::iterator it = mStscTableEntries.begin();
-        it != mStscTableEntries.end(); ++it) {
-        mOwner->writeInt32(it->firstChunk);
-        mOwner->writeInt32(it->samplesPerChunk);
-        mOwner->writeInt32(it->sampleDescriptionId);
-    }
+    mStscTableEntries->write(mOwner);
     mOwner->endBox();  // stsc
 }
 
 void MPEG4Writer::Track::writeStcoBox(bool use32BitOffset) {
     mOwner->beginBox(use32BitOffset? "stco": "co64");
     mOwner->writeInt32(0);  // version=0, flags=0
-    mOwner->writeInt32(mNumStcoTableEntries);
-    for (List<off64_t>::iterator it = mChunkOffsets.begin();
-        it != mChunkOffsets.end(); ++it) {
-        if (use32BitOffset) {
-            mOwner->writeInt32(static_cast<int32_t>(*it));
-        } else {
-            mOwner->writeInt64((*it));
-        }
+    if (use32BitOffset) {
+        mStcoTableEntries->write(mOwner);
+    } else {
+        mCo64TableEntries->write(mOwner);
     }
     mOwner->endBox();  // stco or co64
 }
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index 29e1d21..64e5403 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -110,6 +110,12 @@
         // give us data in a call to MediaSource::read(), unlike its
         // default mode that we use from AwesomePlayer.
         static_cast<WVMExtractor *>(mImpl.get())->setCryptoPluginMode(true);
+    } else if (mImpl->getDrmFlag()) {
+        // For all other drm content, we don't want to expose decrypted
+        // content to Java application.
+        mImpl.clear();
+        mImpl = NULL;
+        return ERROR_UNSUPPORTED;
     }
 
     mDataSource = dataSource;
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index fde7ebf..2f5e9a4 100755
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -301,6 +301,9 @@
             &matchingCodecs, &matchingCodecQuirks);
 
     if (matchingCodecs.isEmpty()) {
+        ALOGV("No matching codecs! (mime: %s, createEncoder: %s, "
+                "matchComponentName: %s, flags: 0x%x)",
+                mime, createEncoder ? "true" : "false", matchComponentName, flags);
         return NULL;
     }
 
@@ -1214,7 +1217,8 @@
                || format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar
                || format.eColorFormat == OMX_COLOR_FormatCbYCrY
                || format.eColorFormat == OMX_TI_COLOR_FormatYUV420PackedSemiPlanar
-               || format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar);
+               || format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar
+               || format.eColorFormat == OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka);
 
         err = mOMX->setParameter(
                 mNode, OMX_IndexParamVideoPortFormat,
@@ -1776,7 +1780,7 @@
     // Dequeue buffers and send them to OMX
     for (OMX_U32 i = 0; i < def.nBufferCountActual; i++) {
         ANativeWindowBuffer* buf;
-        err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf);
+        err = native_window_dequeue_buffer_and_wait(mNativeWindow.get(), &buf);
         if (err != 0) {
             ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), -err);
             break;
@@ -1832,7 +1836,7 @@
     CHECK_EQ((int)info->mStatus, (int)OWNED_BY_US);
     CODEC_LOGV("Calling cancelBuffer on buffer %p", info->mBuffer);
     int err = mNativeWindow->cancelBuffer(
-        mNativeWindow.get(), info->mMediaBuffer->graphicBuffer().get());
+        mNativeWindow.get(), info->mMediaBuffer->graphicBuffer().get(), -1);
     if (err != 0) {
       CODEC_LOGE("cancelBuffer failed w/ error 0x%08x", err);
 
@@ -1846,7 +1850,8 @@
 OMXCodec::BufferInfo* OMXCodec::dequeueBufferFromNativeWindow() {
     // Dequeue the next buffer from the native window.
     ANativeWindowBuffer* buf;
-    int err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf);
+    int fenceFd = -1;
+    int err = native_window_dequeue_buffer_and_wait(mNativeWindow.get(), &buf);
     if (err != 0) {
       CODEC_LOGE("dequeueBuffer failed w/ error 0x%08x", err);
 
@@ -1950,7 +1955,8 @@
     // on the screen and then been replaced, so an previous video frames are
     // guaranteed NOT to be currently displayed.
     for (int i = 0; i < numBufs + 1; i++) {
-        err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &anb);
+        int fenceFd = -1;
+        err = native_window_dequeue_buffer_and_wait(mNativeWindow.get(), &anb);
         if (err != NO_ERROR) {
             ALOGE("error pushing blank frames: dequeueBuffer failed: %s (%d)",
                     strerror(-err), -err);
@@ -1958,13 +1964,6 @@
         }
 
         sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
-        err = mNativeWindow->lockBuffer(mNativeWindow.get(),
-                buf->getNativeBuffer());
-        if (err != NO_ERROR) {
-            ALOGE("error pushing blank frames: lockBuffer failed: %s (%d)",
-                    strerror(-err), -err);
-            goto error;
-        }
 
         // Fill the buffer with the a 1x1 checkerboard pattern ;)
         uint32_t* img = NULL;
@@ -1985,7 +1984,7 @@
         }
 
         err = mNativeWindow->queueBuffer(mNativeWindow.get(),
-                buf->getNativeBuffer());
+                buf->getNativeBuffer(), -1);
         if (err != NO_ERROR) {
             ALOGE("error pushing blank frames: queueBuffer failed: %s (%d)",
                     strerror(-err), -err);
@@ -2000,7 +1999,7 @@
     if (err != NO_ERROR) {
         // Clean up after an error.
         if (anb != NULL) {
-            mNativeWindow->cancelBuffer(mNativeWindow.get(), anb);
+            mNativeWindow->cancelBuffer(mNativeWindow.get(), anb, -1);
         }
 
         native_window_api_disconnect(mNativeWindow.get(),
@@ -2049,8 +2048,14 @@
 
 void OMXCodec::on_message(const omx_message &msg) {
     if (mState == ERROR) {
-        ALOGW("Dropping OMX message - we're in ERROR state.");
-        return;
+        /*
+         * only drop EVENT messages, EBD and FBD are still
+         * processed for bookkeeping purposes
+         */
+        if (msg.type == omx_message::EVENT) {
+            ALOGW("Dropping OMX EVENT message - we're in ERROR state.");
+            return;
+        }
     }
 
     switch (msg.type) {
@@ -3199,23 +3204,6 @@
         return;
     }
 
-    if (info->mMediaBuffer != NULL) {
-        sp<GraphicBuffer> graphicBuffer = info->mMediaBuffer->graphicBuffer();
-        if (graphicBuffer != 0) {
-            // When using a native buffer we need to lock the buffer before
-            // giving it to OMX.
-            CODEC_LOGV("Calling lockBuffer on %p", info->mBuffer);
-            int err = mNativeWindow->lockBuffer(mNativeWindow.get(),
-                    graphicBuffer.get());
-            if (err != 0) {
-                CODEC_LOGE("lockBuffer failed w/ error 0x%08x", err);
-
-                setState(ERROR);
-                return;
-            }
-        }
-    }
-
     CODEC_LOGV("Calling fillBuffer on buffer %p", info->mBuffer);
     status_t err = mOMX->fillBuffer(mNode, info->mBuffer);
 
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index 7951496..c9ef4d9 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -462,6 +462,7 @@
     int32_t videoWidth = -1;
     int32_t videoHeight = -1;
     int32_t audioBitrate = -1;
+    int32_t rotationAngle = -1;
 
     // The overall duration is the duration of the longest track.
     int64_t maxDurationUs = 0;
@@ -489,6 +490,9 @@
 
                 CHECK(trackMeta->findInt32(kKeyWidth, &videoWidth));
                 CHECK(trackMeta->findInt32(kKeyHeight, &videoHeight));
+                if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) {
+                    rotationAngle = 0;
+                }
             } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
                 const char *lang;
                 trackMeta->findCString(kKeyMediaLanguage, &lang);
@@ -521,6 +525,9 @@
 
         sprintf(tmp, "%d", videoHeight);
         mMetaData.add(METADATA_KEY_VIDEO_HEIGHT, String8(tmp));
+
+        sprintf(tmp, "%d", rotationAngle);
+        mMetaData.add(METADATA_KEY_VIDEO_ROTATION, String8(tmp));
     }
 
     if (numTracks == 1 && hasAudio && audioBitrate >= 0) {
diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
index 300d2fc..f1f444e 100644
--- a/media/libstagefright/SurfaceMediaSource.cpp
+++ b/media/libstagefright/SurfaceMediaSource.cpp
@@ -244,7 +244,8 @@
                 if (mStartTimeNs > 0) {
                     if (item.mTimestamp < mStartTimeNs) {
                         // This frame predates start of record, discard
-                        mBufferQueue->releaseBuffer(item.mBuf, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
+                        mBufferQueue->releaseBuffer(item.mBuf, EGL_NO_DISPLAY,
+                                EGL_NO_SYNC_KHR, Fence::NO_FENCE);
                         continue;
                     }
                     mStartTimeNs = item.mTimestamp - mStartTimeNs;
@@ -333,7 +334,8 @@
             ALOGV("Slot %d returned, matches handle = %p", id,
                     mBufferSlot[id]->handle);
 
-            mBufferQueue->releaseBuffer(id, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
+            mBufferQueue->releaseBuffer(id, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR,
+                    Fence::NO_FENCE);
 
             buffer->setObserver(0);
             buffer->release();
diff --git a/media/libstagefright/chromium_http/Android.mk b/media/libstagefright/chromium_http/Android.mk
index 6ab2a00..2c6d84c 100644
--- a/media/libstagefright/chromium_http/Android.mk
+++ b/media/libstagefright/chromium_http/Android.mk
@@ -6,7 +6,8 @@
 LOCAL_SRC_FILES:=       \
         DataUriSource.cpp \
         ChromiumHTTPDataSource.cpp \
-        support.cpp
+        support.cpp \
+        chromium_http_stub.cpp
 
 LOCAL_C_INCLUDES:= \
         $(TOP)/frameworks/av/media/libstagefright \
@@ -16,10 +17,20 @@
 
 LOCAL_CFLAGS += -Wno-multichar
 
-LOCAL_SHARED_LIBRARIES += libstlport
+LOCAL_SHARED_LIBRARIES += \
+        libstlport \
+        libchromium_net \
+        libutils \
+        libcutils \
+        libstagefright_foundation \
+        libstagefright \
+        libdrmframework
+
 include external/stlport/libstlport.mk
 
 LOCAL_MODULE:= libstagefright_chromium_http
 
-include $(BUILD_STATIC_LIBRARY)
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
 endif
diff --git a/media/libstagefright/chromium_http/chromium_http_stub.cpp b/media/libstagefright/chromium_http/chromium_http_stub.cpp
new file mode 100644
index 0000000..560a61f
--- /dev/null
+++ b/media/libstagefright/chromium_http/chromium_http_stub.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include <dlfcn.h>
+
+#include <include/chromium_http_stub.h>
+#include <include/ChromiumHTTPDataSource.h>
+#include <include/DataUriSource.h>
+
+namespace android {
+
+HTTPBase *createChromiumHTTPDataSource(uint32_t flags) {
+    return new ChromiumHTTPDataSource(flags);
+}
+
+DataSource *createDataUriSource(const char *uri) {
+    return new DataUriSource(uri);
+}
+
+}
diff --git a/media/libstagefright/chromium_http_stub.cpp b/media/libstagefright/chromium_http_stub.cpp
new file mode 100644
index 0000000..cbd8796
--- /dev/null
+++ b/media/libstagefright/chromium_http_stub.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include <dlfcn.h>
+
+#include <media/stagefright/DataSource.h>
+
+#include "include/chromium_http_stub.h"
+#include "include/HTTPBase.h"
+
+namespace android {
+
+static bool gFirst = true;
+static void *gHandle;
+static Mutex gLibMutex;
+
+HTTPBase *(*gLib_createChromiumHTTPDataSource)(uint32_t flags);
+DataSource *(*gLib_createDataUriSource)(const char *uri);
+
+static bool load_libstagefright_chromium_http() {
+    Mutex::Autolock autoLock(gLibMutex);
+    void *sym;
+
+    if (!gFirst) {
+        return (gHandle != NULL);
+    }
+
+    gFirst = false;
+
+    gHandle = dlopen("libstagefright_chromium_http.so", RTLD_NOW);
+    if (gHandle == NULL) {
+        return false;
+    }
+
+    sym = dlsym(gHandle, "createChromiumHTTPDataSource");
+    if (sym == NULL) {
+        gHandle = NULL;
+        return false;
+    }
+    gLib_createChromiumHTTPDataSource = (HTTPBase *(*)(uint32_t))sym;
+
+    sym = dlsym(gHandle, "createDataUriSource");
+    if (sym == NULL) {
+        gHandle = NULL;
+        return false;
+    }
+    gLib_createDataUriSource = (DataSource *(*)(const char *))sym;
+
+    return true;
+}
+
+HTTPBase *createChromiumHTTPDataSource(uint32_t flags) {
+    if (!load_libstagefright_chromium_http()) {
+        return NULL;
+    }
+
+    return gLib_createChromiumHTTPDataSource(flags);
+}
+
+DataSource *createDataUriSource(const char *uri) {
+    if (!load_libstagefright_chromium_http()) {
+        return NULL;
+    }
+
+    return gLib_createDataUriSource(uri);
+}
+
+}
diff --git a/media/libstagefright/codecs/avc/enc/Android.mk b/media/libstagefright/codecs/avc/enc/Android.mk
index 48923cf..0aecfa8 100644
--- a/media/libstagefright/codecs/avc/enc/Android.mk
+++ b/media/libstagefright/codecs/avc/enc/Android.mk
@@ -42,6 +42,7 @@
 
 LOCAL_C_INCLUDES := \
         frameworks/av/media/libstagefright/include \
+        frameworks/native/include/media/hardware \
         frameworks/native/include/media/openmax \
         $(LOCAL_PATH)/src \
         $(LOCAL_PATH)/include \
@@ -63,6 +64,7 @@
         libstagefright_foundation \
         libstagefright_omx \
         libutils \
+        libui
 
 
 LOCAL_MODULE := libstagefright_soft_h264enc
diff --git a/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp b/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp
index c6f658d..117f3f1 100644
--- a/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp
+++ b/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp
@@ -22,11 +22,15 @@
 #include "avcenc_int.h"
 #include "OMX_Video.h"
 
+#include <HardwareAPI.h>
+#include <MetadataBufferType.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
+#include <ui/Rect.h>
+#include <ui/GraphicBufferMapper.h>
 
 #include "SoftAVCEncoder.h"
 
@@ -171,6 +175,7 @@
       mVideoFrameRate(30),
       mVideoBitRate(192000),
       mVideoColorFormat(OMX_COLOR_FormatYUV420Planar),
+      mStoreMetaDataInBuffers(false),
       mIDRFrameRefreshIntervalInSec(1),
       mAVCEncProfile(AVC_BASELINE),
       mAVCEncLevel(AVC_LEVEL2),
@@ -448,7 +453,7 @@
                 return OMX_ErrorUndefined;
             }
 
-            if (formatParams->nIndex > 1) {
+            if (formatParams->nIndex > 2) {
                 return OMX_ErrorNoMore;
             }
 
@@ -456,8 +461,10 @@
                 formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused;
                 if (formatParams->nIndex == 0) {
                     formatParams->eColorFormat = OMX_COLOR_FormatYUV420Planar;
-                } else {
+                } else if (formatParams->nIndex == 1) {
                     formatParams->eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
+                } else {
+                    formatParams->eColorFormat = OMX_COLOR_FormatAndroidOpaque;
                 }
             } else {
                 formatParams->eCompressionFormat = OMX_VIDEO_CodingAVC;
@@ -529,7 +536,9 @@
 
 OMX_ERRORTYPE SoftAVCEncoder::internalSetParameter(
         OMX_INDEXTYPE index, const OMX_PTR params) {
-    switch (index) {
+    int32_t indexFull = index;
+
+    switch (indexFull) {
         case OMX_IndexParamVideoErrorCorrection:
         {
             return OMX_ErrorNotImplemented;
@@ -560,7 +569,8 @@
             if (def->nPortIndex == 0) {
                 if (def->format.video.eCompressionFormat != OMX_VIDEO_CodingUnused ||
                     (def->format.video.eColorFormat != OMX_COLOR_FormatYUV420Planar &&
-                     def->format.video.eColorFormat != OMX_COLOR_FormatYUV420SemiPlanar)) {
+                     def->format.video.eColorFormat != OMX_COLOR_FormatYUV420SemiPlanar &&
+                     def->format.video.eColorFormat != OMX_COLOR_FormatAndroidOpaque)) {
                     return OMX_ErrorUndefined;
                 }
             } else {
@@ -610,7 +620,7 @@
                 return OMX_ErrorUndefined;
             }
 
-            if (formatParams->nIndex > 1) {
+            if (formatParams->nIndex > 2) {
                 return OMX_ErrorNoMore;
             }
 
@@ -619,7 +629,9 @@
                     ((formatParams->nIndex == 0 &&
                       formatParams->eColorFormat != OMX_COLOR_FormatYUV420Planar) ||
                     (formatParams->nIndex == 1 &&
-                     formatParams->eColorFormat != OMX_COLOR_FormatYUV420SemiPlanar))) {
+                     formatParams->eColorFormat != OMX_COLOR_FormatYUV420SemiPlanar) ||
+                    (formatParams->nIndex == 2 &&
+                     formatParams->eColorFormat != OMX_COLOR_FormatAndroidOpaque) )) {
                     return OMX_ErrorUndefined;
                 }
                 mVideoColorFormat = formatParams->eColorFormat;
@@ -666,6 +678,31 @@
             return OMX_ErrorNone;
         }
 
+        case kStoreMetaDataExtensionIndex:
+        {
+            StoreMetaDataInBuffersParams *storeParams =
+                    (StoreMetaDataInBuffersParams*)params;
+            if (storeParams->nPortIndex != 0) {
+                ALOGE("%s: StoreMetadataInBuffersParams.nPortIndex not zero!",
+                        __FUNCTION__);
+                return OMX_ErrorUndefined;
+            }
+
+            mStoreMetaDataInBuffers = storeParams->bStoreMetaData;
+            ALOGV("StoreMetaDataInBuffers set to: %s",
+                    mStoreMetaDataInBuffers ? " true" : "false");
+
+            if (mStoreMetaDataInBuffers) {
+                mVideoColorFormat == OMX_COLOR_FormatYUV420SemiPlanar;
+                if (mInputFrameData == NULL) {
+                    mInputFrameData =
+                            (uint8_t *) malloc((mVideoWidth * mVideoHeight * 3 ) >> 1);
+                }
+            }
+
+            return OMX_ErrorNone;
+        }
+
         default:
             return SimpleSoftOMXComponent::internalSetParameter(index, params);
     }
@@ -744,6 +781,8 @@
             }
         }
 
+        buffer_handle_t srcBuffer; // for MetaDataMode only
+
         // Get next input video frame
         if (mReadyForNextFrame) {
             // Save the input buffer info so that it can be
@@ -764,8 +803,28 @@
                 videoInput.height = ((mVideoHeight  + 15) >> 4) << 4;
                 videoInput.pitch = ((mVideoWidth + 15) >> 4) << 4;
                 videoInput.coding_timestamp = (inHeader->nTimeStamp + 500) / 1000;  // in ms
-                const void *inData = inHeader->pBuffer + inHeader->nOffset;
-                uint8_t *inputData = (uint8_t *) inData;
+                uint8_t *inputData = NULL;
+                if (mStoreMetaDataInBuffers) {
+                    if (inHeader->nFilledLen != 8) {
+                        ALOGE("MetaData buffer is wrong size! "
+                                "(got %lu bytes, expected 8)", inHeader->nFilledLen);
+                        mSignalledError = true;
+                        notify(OMX_EventError, OMX_ErrorUndefined, 0, 0);
+                        return;
+                    }
+                    inputData =
+                            extractGrallocData(inHeader->pBuffer + inHeader->nOffset,
+                                    &srcBuffer);
+                    if (inputData == NULL) {
+                        ALOGE("Unable to extract gralloc buffer in metadata mode");
+                        mSignalledError = true;
+                        notify(OMX_EventError, OMX_ErrorUndefined, 0, 0);
+                        return;
+                    }
+                    // TODO: Verify/convert pixel format enum
+                } else {
+                    inputData = (uint8_t *)inHeader->pBuffer + inHeader->nOffset;
+                }
 
                 if (mVideoColorFormat != OMX_COLOR_FormatYUV420Planar) {
                     ConvertYUV420SemiPlanarToYUV420Planar(
@@ -790,12 +849,14 @@
                     if (encoderStatus < AVCENC_SUCCESS) {
                         ALOGE("encoderStatus = %d at line %d", encoderStatus, __LINE__);
                         mSignalledError = true;
+                        releaseGrallocData(srcBuffer);
                         notify(OMX_EventError, OMX_ErrorUndefined, 0, 0);
                         return;
                     } else {
                         ALOGV("encoderStatus = %d at line %d", encoderStatus, __LINE__);
                         inQueue.erase(inQueue.begin());
                         inInfo->mOwnedByUs = false;
+                        releaseGrallocData(srcBuffer);
                         notifyEmptyBufferDone(inHeader);
                         return;
                     }
@@ -829,6 +890,7 @@
             if (encoderStatus < AVCENC_SUCCESS) {
                 ALOGE("encoderStatus = %d at line %d", encoderStatus, __LINE__);
                 mSignalledError = true;
+                releaseGrallocData(srcBuffer);
                 notify(OMX_EventError, OMX_ErrorUndefined, 0, 0);
                 return;
             }
@@ -838,6 +900,7 @@
 
         inQueue.erase(inQueue.begin());
         inInfo->mOwnedByUs = false;
+        releaseGrallocData(srcBuffer);
         notifyEmptyBufferDone(inHeader);
 
         outQueue.erase(outQueue.begin());
@@ -881,6 +944,47 @@
     ALOGV("signalBufferReturned: %p", buffer);
 }
 
+OMX_ERRORTYPE SoftAVCEncoder::getExtensionIndex(
+        const char *name, OMX_INDEXTYPE *index) {
+    if (!strcmp(name, "OMX.google.android.index.storeMetaDataInBuffers")) {
+        *(int32_t*)index = kStoreMetaDataExtensionIndex;
+        return OMX_ErrorNone;
+    }
+    return OMX_ErrorUndefined;
+}
+
+uint8_t *SoftAVCEncoder::extractGrallocData(void *data, buffer_handle_t *buffer) {
+    OMX_U32 type = *(OMX_U32*)data;
+    status_t res;
+    if (type != kMetadataBufferTypeGrallocSource) {
+        ALOGE("Data passed in with metadata mode does not have type "
+                "kMetadataBufferTypeGrallocSource (%d), has type %ld instead",
+                kMetadataBufferTypeGrallocSource, type);
+        return NULL;
+    }
+    buffer_handle_t imgBuffer = *(buffer_handle_t*)((uint8_t*)data + 4);
+
+    const Rect rect(mVideoWidth, mVideoHeight);
+    uint8_t *img;
+    res = GraphicBufferMapper::get().lock(imgBuffer,
+            GRALLOC_USAGE_HW_VIDEO_ENCODER,
+            rect, (void**)&img);
+    if (res != OK) {
+        ALOGE("%s: Unable to lock image buffer %p for access", __FUNCTION__,
+                imgBuffer);
+        return NULL;
+    }
+
+    *buffer = imgBuffer;
+    return img;
+}
+
+void SoftAVCEncoder::releaseGrallocData(buffer_handle_t buffer) {
+    if (mStoreMetaDataInBuffers) {
+        GraphicBufferMapper::get().unlock(buffer);
+    }
+}
+
 }  // namespace android
 
 android::SoftOMXComponent *createSoftOMXComponent(
diff --git a/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.h b/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.h
index a2587c6..23d5ff1 100644
--- a/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.h
+++ b/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.h
@@ -45,6 +45,10 @@
 
     virtual void onQueueFilled(OMX_U32 portIndex);
 
+    // Override SoftOMXComponent methods
+
+    virtual OMX_ERRORTYPE getExtensionIndex(
+            const char *name, OMX_INDEXTYPE *index);
 
     // Implement MediaBufferObserver
     virtual void signalBufferReturned(MediaBuffer *buffer);
@@ -63,6 +67,10 @@
         kNumBuffers = 2,
     };
 
+    enum {
+        kStoreMetaDataExtensionIndex = OMX_IndexVendorStartUnused + 1
+    };
+
     // OMX input buffer's timestamp and flags
     typedef struct {
         int64_t mTimeUs;
@@ -74,6 +82,7 @@
     int32_t  mVideoFrameRate;
     int32_t  mVideoBitRate;
     int32_t  mVideoColorFormat;
+    bool     mStoreMetaDataInBuffers;
     int32_t  mIDRFrameRefreshIntervalInSec;
     AVCProfile mAVCEncProfile;
     AVCLevel   mAVCEncLevel;
@@ -100,6 +109,9 @@
     OMX_ERRORTYPE releaseEncoder();
     void releaseOutputBuffers();
 
+    uint8_t* extractGrallocData(void *data, buffer_handle_t *buffer);
+    void releaseGrallocData(buffer_handle_t buffer);
+
     DISALLOW_EVIL_CONSTRUCTORS(SoftAVCEncoder);
 };
 
diff --git a/media/libstagefright/codecs/m4v_h263/enc/Android.mk b/media/libstagefright/codecs/m4v_h263/enc/Android.mk
index 484180d..865cc9c 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/Android.mk
+++ b/media/libstagefright/codecs/m4v_h263/enc/Android.mk
@@ -45,6 +45,7 @@
 LOCAL_C_INCLUDES := \
         frameworks/av/media/libstagefright/include \
         frameworks/native/include/media/openmax \
+        frameworks/native/include/media/hardware \
         $(LOCAL_PATH)/src \
         $(LOCAL_PATH)/include \
         $(LOCAL_PATH)/../common/include \
@@ -64,6 +65,7 @@
         libstagefright_foundation \
         libstagefright_omx \
         libutils \
+        libui
 
 
 LOCAL_MODULE := libstagefright_soft_mpeg4enc
diff --git a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
index a5a2332..8bc0275 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
+++ b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
@@ -21,11 +21,15 @@
 #include "mp4enc_api.h"
 #include "OMX_Video.h"
 
+#include <HardwareAPI.h>
+#include <MetadataBufferType.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
+#include <ui/Rect.h>
+#include <ui/GraphicBufferMapper.h>
 
 #include "SoftMPEG4Encoder.h"
 
@@ -82,6 +86,7 @@
       mVideoFrameRate(30),
       mVideoBitRate(192000),
       mVideoColorFormat(OMX_COLOR_FormatYUV420Planar),
+      mStoreMetaDataInBuffers(false),
       mIDRFrameRefreshIntervalInSec(1),
       mNumInputFrames(-1),
       mStarted(false),
@@ -321,7 +326,7 @@
                 return OMX_ErrorUndefined;
             }
 
-            if (formatParams->nIndex > 1) {
+            if (formatParams->nIndex > 2) {
                 return OMX_ErrorNoMore;
             }
 
@@ -329,8 +334,10 @@
                 formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused;
                 if (formatParams->nIndex == 0) {
                     formatParams->eColorFormat = OMX_COLOR_FormatYUV420Planar;
-                } else {
+                } else if (formatParams->nIndex == 1) {
                     formatParams->eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
+                } else {
+                    formatParams->eColorFormat = OMX_COLOR_FormatAndroidOpaque;
                 }
             } else {
                 formatParams->eCompressionFormat =
@@ -420,7 +427,9 @@
 
 OMX_ERRORTYPE SoftMPEG4Encoder::internalSetParameter(
         OMX_INDEXTYPE index, const OMX_PTR params) {
-    switch (index) {
+    int32_t indexFull = index;
+
+    switch (indexFull) {
         case OMX_IndexParamVideoErrorCorrection:
         {
             return OMX_ErrorNotImplemented;
@@ -451,7 +460,8 @@
             if (def->nPortIndex == 0) {
                 if (def->format.video.eCompressionFormat != OMX_VIDEO_CodingUnused ||
                     (def->format.video.eColorFormat != OMX_COLOR_FormatYUV420Planar &&
-                     def->format.video.eColorFormat != OMX_COLOR_FormatYUV420SemiPlanar)) {
+                     def->format.video.eColorFormat != OMX_COLOR_FormatYUV420SemiPlanar &&
+                     def->format.video.eColorFormat != OMX_COLOR_FormatAndroidOpaque)) {
                     return OMX_ErrorUndefined;
                 }
             } else {
@@ -505,7 +515,7 @@
                 return OMX_ErrorUndefined;
             }
 
-            if (formatParams->nIndex > 1) {
+            if (formatParams->nIndex > 2) {
                 return OMX_ErrorNoMore;
             }
 
@@ -514,7 +524,9 @@
                     ((formatParams->nIndex == 0 &&
                       formatParams->eColorFormat != OMX_COLOR_FormatYUV420Planar) ||
                     (formatParams->nIndex == 1 &&
-                     formatParams->eColorFormat != OMX_COLOR_FormatYUV420SemiPlanar))) {
+                     formatParams->eColorFormat != OMX_COLOR_FormatYUV420SemiPlanar) ||
+                    (formatParams->nIndex == 2 &&
+                     formatParams->eColorFormat != OMX_COLOR_FormatAndroidOpaque) )) {
                     return OMX_ErrorUndefined;
                 }
                 mVideoColorFormat = formatParams->eColorFormat;
@@ -578,6 +590,31 @@
             return OMX_ErrorNone;
         }
 
+        case kStoreMetaDataExtensionIndex:
+        {
+            StoreMetaDataInBuffersParams *storeParams =
+                    (StoreMetaDataInBuffersParams*)params;
+            if (storeParams->nPortIndex != 0) {
+                ALOGE("%s: StoreMetadataInBuffersParams.nPortIndex not zero!",
+                        __FUNCTION__);
+                return OMX_ErrorUndefined;
+            }
+
+            mStoreMetaDataInBuffers = storeParams->bStoreMetaData;
+            ALOGV("StoreMetaDataInBuffers set to: %s",
+                    mStoreMetaDataInBuffers ? " true" : "false");
+
+            if (mStoreMetaDataInBuffers) {
+                mVideoColorFormat == OMX_COLOR_FormatYUV420SemiPlanar;
+                if (mInputFrameData == NULL) {
+                    mInputFrameData =
+                            (uint8_t *) malloc((mVideoWidth * mVideoHeight * 3 ) >> 1);
+                }
+            }
+
+            return OMX_ErrorNone;
+        }
+
         default:
             return SimpleSoftOMXComponent::internalSetParameter(index, params);
     }
@@ -640,9 +677,31 @@
             mSawInputEOS = true;
         }
 
+        buffer_handle_t srcBuffer; // for MetaDataMode only
         if (inHeader->nFilledLen > 0) {
-            const void *inData = inHeader->pBuffer + inHeader->nOffset;
-            uint8_t *inputData = (uint8_t *) inData;
+            uint8_t *inputData = NULL;
+            if (mStoreMetaDataInBuffers) {
+                if (inHeader->nFilledLen != 8) {
+                    ALOGE("MetaData buffer is wrong size! "
+                            "(got %lu bytes, expected 8)", inHeader->nFilledLen);
+                    mSignalledError = true;
+                    notify(OMX_EventError, OMX_ErrorUndefined, 0, 0);
+                    return;
+                }
+                inputData =
+                        extractGrallocData(inHeader->pBuffer + inHeader->nOffset,
+                                &srcBuffer);
+                if (inputData == NULL) {
+                    ALOGE("Unable to extract gralloc buffer in metadata mode");
+                    mSignalledError = true;
+                    notify(OMX_EventError, OMX_ErrorUndefined, 0, 0);
+                        return;
+                }
+                // TODO: Verify/convert pixel format enum
+            } else {
+                inputData = (uint8_t *)inHeader->pBuffer + inHeader->nOffset;
+            }
+
             if (mVideoColorFormat != OMX_COLOR_FormatYUV420Planar) {
                 ConvertYUV420SemiPlanarToYUV420Planar(
                     inputData, mInputFrameData, mVideoWidth, mVideoHeight);
@@ -683,6 +742,7 @@
 
         inQueue.erase(inQueue.begin());
         inInfo->mOwnedByUs = false;
+        releaseGrallocData(srcBuffer);
         notifyEmptyBufferDone(inHeader);
 
         outQueue.erase(outQueue.begin());
@@ -697,6 +757,47 @@
     }
 }
 
+OMX_ERRORTYPE SoftMPEG4Encoder::getExtensionIndex(
+        const char *name, OMX_INDEXTYPE *index) {
+    if (!strcmp(name, "OMX.google.android.index.storeMetaDataInBuffers")) {
+        *(int32_t*)index = kStoreMetaDataExtensionIndex;
+        return OMX_ErrorNone;
+    }
+    return OMX_ErrorUndefined;
+}
+
+uint8_t *SoftMPEG4Encoder::extractGrallocData(void *data, buffer_handle_t *buffer) {
+    OMX_U32 type = *(OMX_U32*)data;
+    status_t res;
+    if (type != kMetadataBufferTypeGrallocSource) {
+        ALOGE("Data passed in with metadata mode does not have type "
+                "kMetadataBufferTypeGrallocSource (%d), has type %ld instead",
+                kMetadataBufferTypeGrallocSource, type);
+        return NULL;
+    }
+    buffer_handle_t imgBuffer = *(buffer_handle_t*)((uint8_t*)data + 4);
+
+    const Rect rect(mVideoWidth, mVideoHeight);
+    uint8_t *img;
+    res = GraphicBufferMapper::get().lock(imgBuffer,
+            GRALLOC_USAGE_HW_VIDEO_ENCODER,
+            rect, (void**)&img);
+    if (res != OK) {
+        ALOGE("%s: Unable to lock image buffer %p for access", __FUNCTION__,
+                imgBuffer);
+        return NULL;
+    }
+
+    *buffer = imgBuffer;
+    return img;
+}
+
+void SoftMPEG4Encoder::releaseGrallocData(buffer_handle_t buffer) {
+    if (mStoreMetaDataInBuffers) {
+        GraphicBufferMapper::get().unlock(buffer);
+    }
+}
+
 }  // namespace android
 
 android::SoftOMXComponent *createSoftOMXComponent(
diff --git a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h
index 3e90d54..cc4ea8f 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h
+++ b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h
@@ -43,6 +43,11 @@
 
     virtual void onQueueFilled(OMX_U32 portIndex);
 
+    // Override SoftOMXComponent methods
+
+    virtual OMX_ERRORTYPE getExtensionIndex(
+            const char *name, OMX_INDEXTYPE *index);
+
 protected:
     virtual ~SoftMPEG4Encoder();
 
@@ -51,6 +56,10 @@
         kNumBuffers = 2,
     };
 
+    enum {
+        kStoreMetaDataExtensionIndex = OMX_IndexVendorStartUnused + 1
+    };
+
     // OMX input buffer's timestamp and flags
     typedef struct {
         int64_t mTimeUs;
@@ -63,6 +72,7 @@
     int32_t  mVideoFrameRate;
     int32_t  mVideoBitRate;
     int32_t  mVideoColorFormat;
+    bool     mStoreMetaDataInBuffers;
     int32_t  mIDRFrameRefreshIntervalInSec;
 
     int64_t  mNumInputFrames;
@@ -80,6 +90,9 @@
     OMX_ERRORTYPE initEncoder();
     OMX_ERRORTYPE releaseEncoder();
 
+    uint8_t* extractGrallocData(void *data, buffer_handle_t *buffer);
+    void releaseGrallocData(buffer_handle_t buffer);
+
     DISALLOW_EVIL_CONSTRUCTORS(SoftMPEG4Encoder);
 };
 
diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
index 8673bad..2704a37 100644
--- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp
+++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
@@ -141,13 +141,12 @@
         const void *data, size_t size, void *platformPrivate) {
     ANativeWindowBuffer *buf;
     int err;
-    if ((err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf)) != 0) {
+    if ((err = native_window_dequeue_buffer_and_wait(mNativeWindow.get(),
+            &buf)) != 0) {
         ALOGW("Surface::dequeueBuffer returned error %d", err);
         return;
     }
 
-    CHECK_EQ(0, mNativeWindow->lockBuffer(mNativeWindow.get(), buf));
-
     GraphicBufferMapper &mapper = GraphicBufferMapper::get();
 
     Rect bounds(mCropWidth, mCropHeight);
@@ -231,7 +230,8 @@
 
     CHECK_EQ(0, mapper.unlock(buf->handle));
 
-    if ((err = mNativeWindow->queueBuffer(mNativeWindow.get(), buf)) != 0) {
+    if ((err = mNativeWindow->queueBuffer(mNativeWindow.get(), buf,
+            -1)) != 0) {
         ALOGW("Surface::queueBuffer returned error %d", err);
     }
     buf = NULL;
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 68380a8..1422687 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -166,6 +166,7 @@
     sp<MediaSource> mVideoTrack;
     sp<MediaSource> mVideoSource;
     sp<AwesomeRenderer> mVideoRenderer;
+    bool mVideoRenderingStarted;
     bool mVideoRendererIsPreview;
 
     ssize_t mActiveAudioTrackIndex;
diff --git a/media/libstagefright/include/chromium_http_stub.h b/media/libstagefright/include/chromium_http_stub.h
new file mode 100644
index 0000000..869d4ac
--- /dev/null
+++ b/media/libstagefright/include/chromium_http_stub.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CHROMIUM_HTTP_STUB_H_
+#define CHROMIUM_HTTP_STUB_H_
+
+#include <include/HTTPBase.h>
+#include <media/stagefright/DataSource.h>
+
+namespace android {
+extern "C" {
+HTTPBase *createChromiumHTTPDataSource(uint32_t flags);
+DataSource *createDataUriSource(const char *uri);
+}
+}
+
+#endif
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index 681e321..29bc733 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -252,13 +252,16 @@
 status_t OMX::freeNode(node_id node) {
     OMXNodeInstance *instance = findInstance(node);
 
-    ssize_t index = mLiveNodes.indexOfKey(instance->observer()->asBinder());
-    if (index < 0) {
-        // This could conceivably happen if the observer dies at roughly the
-        // same time that a client attempts to free the node explicitly.
-        return OK;
+    {
+        Mutex::Autolock autoLock(mLock);
+        ssize_t index = mLiveNodes.indexOfKey(instance->observer()->asBinder());
+        if (index < 0) {
+            // This could conceivably happen if the observer dies at roughly the
+            // same time that a client attempts to free the node explicitly.
+            return OK;
+        }
+        mLiveNodes.removeItemsAt(index);
     }
-    mLiveNodes.removeItemsAt(index);
 
     instance->observer()->asBinder()->unlinkToDeath(this);
 
@@ -266,7 +269,7 @@
 
     {
         Mutex::Autolock autoLock(mLock);
-        index = mDispatchers.indexOfKey(node);
+        ssize_t index = mDispatchers.indexOfKey(node);
         CHECK(index >= 0);
         mDispatchers.removeItemsAt(index);
     }
diff --git a/media/libstagefright/tests/Android.mk b/media/libstagefright/tests/Android.mk
index a1e6be7..57fff0b 100644
--- a/media/libstagefright/tests/Android.mk
+++ b/media/libstagefright/tests/Android.mk
@@ -20,9 +20,10 @@
 	libgui \
 	libmedia \
 	libstagefright \
-	libstagefright_omx \
 	libstagefright_foundation \
+	libstagefright_omx \
 	libstlport \
+	libsync \
 	libui \
 	libutils \
 
diff --git a/media/libstagefright/tests/SurfaceMediaSource_test.cpp b/media/libstagefright/tests/SurfaceMediaSource_test.cpp
index 466f521..cc2aca7 100644
--- a/media/libstagefright/tests/SurfaceMediaSource_test.cpp
+++ b/media/libstagefright/tests/SurfaceMediaSource_test.cpp
@@ -509,31 +509,31 @@
 // cpu YV12 buffer
 void SurfaceMediaSourceTest::oneBufferPass(int width, int height ) {
     ANativeWindowBuffer* anb;
-    ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+    ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
     ASSERT_TRUE(anb != NULL);
 
-    sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
-    ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
 
     // Fill the buffer with the a checkerboard pattern
     uint8_t* img = NULL;
+    sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
     buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
     SurfaceMediaSourceTest::fillYV12Buffer(img, width, height, buf->getStride());
     buf->unlock();
 
-    ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
+    ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer(),
+            -1));
 }
 
 // Dequeuing and queuing the buffer without really filling it in.
 void SurfaceMediaSourceTest::oneBufferPassNoFill(int width, int height ) {
     ANativeWindowBuffer* anb;
-    ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+    ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
     ASSERT_TRUE(anb != NULL);
 
-    sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
-    // ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
     // We do not fill the buffer in. Just queue it back.
-    ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
+    sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
+    ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer(),
+            -1));
 }
 
 // Fill a YV12 buffer with a multi-colored checkerboard pattern
@@ -652,7 +652,7 @@
     ANativeWindowBuffer* anb;
 
     // Note: make sure we get an ERROR back when dequeuing!
-    ASSERT_NE(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+    ASSERT_NE(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
 }
 
 // pass multiple buffers from the native_window the SurfaceMediaSource
diff --git a/media/libstagefright/timedtext/TimedTextDriver.cpp b/media/libstagefright/timedtext/TimedTextDriver.cpp
index 42ca1f5..54ce7ac 100644
--- a/media/libstagefright/timedtext/TimedTextDriver.cpp
+++ b/media/libstagefright/timedtext/TimedTextDriver.cpp
@@ -61,7 +61,7 @@
     source = mTextSourceVector.valueFor(index);
     mPlayer->setDataSource(source);
     if (mState == UNINITIALIZED) {
-        mState = PAUSED;
+        mState = PREPARED;
     }
     mCurrentTrackIndex = index;
     return OK;
@@ -74,42 +74,47 @@
             return INVALID_OPERATION;
         case PLAYING:
             return OK;
-        case PAUSED:
+        case PREPARED:
             mPlayer->start();
-            break;
+            mState = PLAYING;
+            return OK;
+        case PAUSED:
+            mPlayer->resume();
+            mState = PLAYING;
+            return OK;
         default:
             TRESPASS();
     }
-    mState = PLAYING;
-    return OK;
+    return UNKNOWN_ERROR;
 }
 
-// TODO: Test if pause() works properly.
-// Scenario 1: start - pause - resume
-// Scenario 2: start - seek
-// Scenario 3: start - pause - seek - resume
 status_t TimedTextDriver::pause() {
     Mutex::Autolock autoLock(mLock);
+    ALOGV("%s() is called", __FUNCTION__);
     switch (mState) {
         case UNINITIALIZED:
             return INVALID_OPERATION;
         case PLAYING:
             mPlayer->pause();
-            break;
+            mState = PAUSED;
+            return OK;
+        case PREPARED:
+            return INVALID_OPERATION;
         case PAUSED:
             return OK;
         default:
             TRESPASS();
     }
-    mState = PAUSED;
-    return OK;
+    return UNKNOWN_ERROR;
 }
 
 status_t TimedTextDriver::selectTrack(size_t index) {
     status_t ret = OK;
     Mutex::Autolock autoLock(mLock);
+    ALOGV("%s() is called", __FUNCTION__);
     switch (mState) {
         case UNINITIALIZED:
+        case PREPARED:
         case PAUSED:
             ret = selectTrack_l(index);
             break;
@@ -128,21 +133,50 @@
 }
 
 status_t TimedTextDriver::unselectTrack(size_t index) {
+    Mutex::Autolock autoLock(mLock);
+    ALOGV("%s() is called", __FUNCTION__);
     if (mCurrentTrackIndex != index) {
         return INVALID_OPERATION;
     }
-    status_t err = pause();
-    if (err != OK) {
-        return err;
+    switch (mState) {
+        case UNINITIALIZED:
+            return INVALID_OPERATION;
+        case PLAYING:
+            mPlayer->pause();
+            mState = UNINITIALIZED;
+            return OK;
+        case PREPARED:
+        case PAUSED:
+            mState = UNINITIALIZED;
+            return OK;
+        default:
+            TRESPASS();
     }
-    Mutex::Autolock autoLock(mLock);
-    mState = UNINITIALIZED;
-    return OK;
+    return UNKNOWN_ERROR;
 }
 
 status_t TimedTextDriver::seekToAsync(int64_t timeUs) {
-    mPlayer->seekToAsync(timeUs);
-    return OK;
+    Mutex::Autolock autoLock(mLock);
+    ALOGV("%s() is called", __FUNCTION__);
+    switch (mState) {
+        case UNINITIALIZED:
+            return INVALID_OPERATION;
+        case PREPARED:
+            mPlayer->seekToAsync(timeUs);
+            mPlayer->pause();
+            mState = PAUSED;
+            return OK;
+        case PAUSED:
+            mPlayer->seekToAsync(timeUs);
+            mPlayer->pause();
+            return OK;
+        case PLAYING:
+            mPlayer->seekToAsync(timeUs);
+            return OK;
+        defaut:
+            TRESPASS();
+    }
+    return UNKNOWN_ERROR;
 }
 
 status_t TimedTextDriver::addInBandTextSource(
diff --git a/media/libstagefright/timedtext/TimedTextPlayer.cpp b/media/libstagefright/timedtext/TimedTextPlayer.cpp
index 9b001cc..df7eb39 100644
--- a/media/libstagefright/timedtext/TimedTextPlayer.cpp
+++ b/media/libstagefright/timedtext/TimedTextPlayer.cpp
@@ -18,6 +18,7 @@
 #define LOG_TAG "TimedTextPlayer"
 #include <utils/Log.h>
 
+#include <limits.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/timedtext/TimedTextDriver.h>
@@ -30,12 +31,18 @@
 
 namespace android {
 
+// Event should be fired a bit earlier considering the processing time till
+// application actually gets the notification message.
 static const int64_t kAdjustmentProcessingTimeUs = 100000ll;
+static const int64_t kMaxDelayUs = 5000000ll;
 static const int64_t kWaitTimeUsToRetryRead = 100000ll;
+static const int64_t kInvalidTimeUs = INT_MIN;
 
 TimedTextPlayer::TimedTextPlayer(const wp<MediaPlayerBase> &listener)
     : mListener(listener),
       mSource(NULL),
+      mPendingSeekTimeUs(kInvalidTimeUs),
+      mPaused(false),
       mSendSubtitleGeneration(0) {
 }
 
@@ -48,15 +55,17 @@
 }
 
 void TimedTextPlayer::start() {
-    sp<AMessage> msg = new AMessage(kWhatSeek, id());
-    msg->setInt64("seekTimeUs", -1);
-    msg->post();
+    (new AMessage(kWhatStart, id()))->post();
 }
 
 void TimedTextPlayer::pause() {
     (new AMessage(kWhatPause, id()))->post();
 }
 
+void TimedTextPlayer::resume() {
+    (new AMessage(kWhatResume, id()))->post();
+}
+
 void TimedTextPlayer::seekToAsync(int64_t timeUs) {
     sp<AMessage> msg = new AMessage(kWhatSeek, id());
     msg->setInt64("seekTimeUs", timeUs);
@@ -72,10 +81,43 @@
 void TimedTextPlayer::onMessageReceived(const sp<AMessage> &msg) {
     switch (msg->what()) {
         case kWhatPause: {
+            mPaused = true;
+            break;
+        }
+        case kWhatResume: {
+            mPaused = false;
+            if (mPendingSeekTimeUs != kInvalidTimeUs) {
+                seekToAsync(mPendingSeekTimeUs);
+                mPendingSeekTimeUs = kInvalidTimeUs;
+            } else {
+                doRead();
+            }
+            break;
+        }
+        case kWhatStart: {
+            sp<MediaPlayerBase> listener = mListener.promote();
+            if (listener == NULL) {
+                ALOGE("Listener is NULL when kWhatStart is received.");
+                break;
+            }
+            mPaused = false;
+            mPendingSeekTimeUs = kInvalidTimeUs;
+            int32_t positionMs = 0;
+            listener->getCurrentPosition(&positionMs);
+            int64_t seekTimeUs = positionMs * 1000ll;
+
+            notifyListener();
             mSendSubtitleGeneration++;
+            doSeekAndRead(seekTimeUs);
             break;
         }
         case kWhatRetryRead: {
+            int32_t generation = -1;
+            CHECK(msg->findInt32("generation", &generation));
+            if (generation != mSendSubtitleGeneration) {
+                // Drop obsolete msg.
+                break;
+            }
             int64_t seekTimeUs;
             int seekMode;
             if (msg->findInt64("seekTimeUs", &seekTimeUs) &&
@@ -91,9 +133,11 @@
             break;
         }
         case kWhatSeek: {
-            int64_t seekTimeUs = 0;
+            int64_t seekTimeUs = kInvalidTimeUs;
+            // Clear a displayed timed text before seeking.
+            notifyListener();
             msg->findInt64("seekTimeUs", &seekTimeUs);
-            if (seekTimeUs < 0) {
+            if (seekTimeUs == kInvalidTimeUs) {
                 sp<MediaPlayerBase> listener = mListener.promote();
                 if (listener != NULL) {
                     int32_t positionMs = 0;
@@ -101,6 +145,11 @@
                     seekTimeUs = positionMs * 1000ll;
                 }
             }
+            if (mPaused) {
+                mPendingSeekTimeUs = seekTimeUs;
+                break;
+            }
+            mSendSubtitleGeneration++;
             doSeekAndRead(seekTimeUs);
             break;
         }
@@ -108,8 +157,19 @@
             int32_t generation;
             CHECK(msg->findInt32("generation", &generation));
             if (generation != mSendSubtitleGeneration) {
-              // Drop obsolete msg.
-              break;
+                // Drop obsolete msg.
+                break;
+            }
+            // If current time doesn't reach to the fire time,
+            // re-post the message with the adjusted delay time.
+            int64_t fireTimeUs = kInvalidTimeUs;
+            if (msg->findInt64("fireTimeUs", &fireTimeUs)) {
+                // TODO: check if fireTimeUs is not kInvalidTimeUs.
+                int64_t delayUs = delayUsFromCurrentTime(fireTimeUs);
+                if (delayUs > 0) {
+                    msg->post(delayUs);
+                    break;
+                }
             }
             sp<RefBase> obj;
             if (msg->findObject("subtitle", &obj)) {
@@ -162,12 +222,14 @@
     if (err == WOULD_BLOCK) {
         sp<AMessage> msg = new AMessage(kWhatRetryRead, id());
         if (options != NULL) {
-            int64_t seekTimeUs;
-            MediaSource::ReadOptions::SeekMode seekMode;
+            int64_t seekTimeUs = kInvalidTimeUs;
+            MediaSource::ReadOptions::SeekMode seekMode =
+                MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC;
             CHECK(options->getSeekTo(&seekTimeUs, &seekMode));
             msg->setInt64("seekTimeUs", seekTimeUs);
             msg->setInt32("seekMode", seekMode);
         }
+        msg->setInt32("generation", mSendSubtitleGeneration);
         msg->post(kWaitTimeUsToRetryRead);
         return;
     } else if (err != OK) {
@@ -185,49 +247,57 @@
 }
 
 void TimedTextPlayer::postTextEvent(const sp<ParcelEvent>& parcel, int64_t timeUs) {
-    sp<MediaPlayerBase> listener = mListener.promote();
-    if (listener != NULL) {
-        int64_t positionUs, delayUs;
-        int32_t positionMs = 0;
-        listener->getCurrentPosition(&positionMs);
-        positionUs = positionMs * 1000ll;
-
-        if (timeUs <= positionUs + kAdjustmentProcessingTimeUs) {
-            delayUs = 0;
-        } else {
-            delayUs = timeUs - positionUs - kAdjustmentProcessingTimeUs;
-        }
-        postTextEventDelayUs(parcel, delayUs);
+    int64_t delayUs = delayUsFromCurrentTime(timeUs);
+    sp<AMessage> msg = new AMessage(kWhatSendSubtitle, id());
+    msg->setInt32("generation", mSendSubtitleGeneration);
+    if (parcel != NULL) {
+        msg->setObject("subtitle", parcel);
     }
+    msg->setInt64("fireTimeUs", timeUs);
+    msg->post(delayUs);
 }
 
-void TimedTextPlayer::postTextEventDelayUs(const sp<ParcelEvent>& parcel, int64_t delayUs) {
+int64_t TimedTextPlayer::delayUsFromCurrentTime(int64_t fireTimeUs) {
     sp<MediaPlayerBase> listener = mListener.promote();
-    if (listener != NULL) {
-        sp<AMessage> msg = new AMessage(kWhatSendSubtitle, id());
-        msg->setInt32("generation", mSendSubtitleGeneration);
-        if (parcel != NULL) {
-            msg->setObject("subtitle", parcel);
+    if (listener == NULL) {
+        // TODO: it may be better to return kInvalidTimeUs
+        ALOGE("%s: Listener is NULL.", __FUNCTION__, fireTimeUs);
+        return 0;
+    }
+    int32_t positionMs = 0;
+    listener->getCurrentPosition(&positionMs);
+    int64_t positionUs = positionMs * 1000ll;
+
+    if (fireTimeUs <= positionUs + kAdjustmentProcessingTimeUs) {
+        return 0;
+    } else {
+        int64_t delayUs = fireTimeUs - positionUs - kAdjustmentProcessingTimeUs;
+        if (delayUs > kMaxDelayUs) {
+            return kMaxDelayUs;
         }
-        msg->post(delayUs);
+        return delayUs;
     }
 }
 
 void TimedTextPlayer::notifyError(int error) {
     sp<MediaPlayerBase> listener = mListener.promote();
-    if (listener != NULL) {
-        listener->sendEvent(MEDIA_INFO, MEDIA_INFO_TIMED_TEXT_ERROR, error);
+    if (listener == NULL) {
+        ALOGE("%s(error=%d): Listener is NULL.", __FUNCTION__, error);
+        return;
     }
+    listener->sendEvent(MEDIA_INFO, MEDIA_INFO_TIMED_TEXT_ERROR, error);
 }
 
 void TimedTextPlayer::notifyListener(const Parcel *parcel) {
     sp<MediaPlayerBase> listener = mListener.promote();
-    if (listener != NULL) {
-        if (parcel != NULL && (parcel->dataSize() > 0)) {
-            listener->sendEvent(MEDIA_TIMED_TEXT, 0, 0, parcel);
-        } else {  // send an empty timed text to clear the screen
-            listener->sendEvent(MEDIA_TIMED_TEXT);
-        }
+    if (listener == NULL) {
+        ALOGE("%s: Listener is NULL.", __FUNCTION__);
+        return;
+    }
+    if (parcel != NULL && (parcel->dataSize() > 0)) {
+        listener->sendEvent(MEDIA_TIMED_TEXT, 0, 0, parcel);
+    } else {  // send an empty timed text to clear the screen
+        listener->sendEvent(MEDIA_TIMED_TEXT);
     }
 }
 
diff --git a/media/libstagefright/timedtext/TimedTextPlayer.h b/media/libstagefright/timedtext/TimedTextPlayer.h
index b7e15f8..ec8ed25 100644
--- a/media/libstagefright/timedtext/TimedTextPlayer.h
+++ b/media/libstagefright/timedtext/TimedTextPlayer.h
@@ -40,6 +40,7 @@
 
     void start();
     void pause();
+    void resume();
     void seekToAsync(int64_t timeUs);
     void setDataSource(sp<TimedTextSource> source);
 
@@ -49,6 +50,8 @@
 private:
     enum {
         kWhatPause = 'paus',
+        kWhatResume = 'resm',
+        kWhatStart = 'strt',
         kWhatSeek = 'seek',
         kWhatRetryRead = 'read',
         kWhatSendSubtitle = 'send',
@@ -62,13 +65,15 @@
 
     wp<MediaPlayerBase> mListener;
     sp<TimedTextSource> mSource;
+    int64_t mPendingSeekTimeUs;
+    bool mPaused;
     int32_t mSendSubtitleGeneration;
 
     void doSeekAndRead(int64_t seekTimeUs);
     void doRead(MediaSource::ReadOptions* options = NULL);
     void onTextEvent();
     void postTextEvent(const sp<ParcelEvent>& parcel = NULL, int64_t timeUs = -1);
-    void postTextEventDelayUs(const sp<ParcelEvent>& parcel = NULL, int64_t delayUs = -1);
+    int64_t delayUsFromCurrentTime(int64_t fireTimeUs);
     void notifyError(int error = 0);
     void notifyListener(const Parcel *parcel = NULL);
 
diff --git a/media/libstagefright/timedtext/TimedTextSRTSource.cpp b/media/libstagefright/timedtext/TimedTextSRTSource.cpp
index 1f5d037..eac23ba 100644
--- a/media/libstagefright/timedtext/TimedTextSRTSource.cpp
+++ b/media/libstagefright/timedtext/TimedTextSRTSource.cpp
@@ -79,6 +79,10 @@
     return OK;
 }
 
+sp<MetaData> TimedTextSRTSource::getFormat() {
+    return mMetaData;
+}
+
 status_t TimedTextSRTSource::scanFile() {
     off64_t offset = 0;
     int64_t startTimeUs;
@@ -155,18 +159,16 @@
     while (needMoreData) {
         if ((err = readNextLine(offset, &data)) != OK) {
             if (err == ERROR_END_OF_STREAM) {
-                needMoreData = false;
+                break;
             } else {
                 return err;
             }
         }
 
-        if (needMoreData) {
-            data.trim();
-            if (data.empty()) {
-                // it's an empty line used to separate two subtitles
-                needMoreData = false;
-            }
+        data.trim();
+        if (data.empty()) {
+            // it's an empty line used to separate two subtitles
+            needMoreData = false;
         }
     }
     info->textLen = *offset - info->offset;
@@ -221,35 +223,24 @@
     if (options != NULL && options->getSeekTo(&seekTimeUs, &mode)) {
         int64_t lastEndTimeUs =
                 mTextVector.valueAt(mTextVector.size() - 1).endTimeUs;
-        int64_t firstStartTimeUs = mTextVector.keyAt(0);
-        if (seekTimeUs < 0 || seekTimeUs > lastEndTimeUs) {
+        if (seekTimeUs < 0) {
             return ERROR_OUT_OF_RANGE;
-        } else if (seekTimeUs < firstStartTimeUs) {
-            mIndex = 0;
+        } else if (seekTimeUs >= lastEndTimeUs) {
+            return ERROR_END_OF_STREAM;
         } else {
             // binary search
             size_t low = 0;
             size_t high = mTextVector.size() - 1;
             size_t mid = 0;
-            int64_t currTimeUs;
 
             while (low <= high) {
                 mid = low + (high - low)/2;
-                currTimeUs = mTextVector.keyAt(mid);
-                const int64_t diffTime = currTimeUs - seekTimeUs;
-
-                if (diffTime == 0) {
+                int diff = compareExtendedRangeAndTime(mid, seekTimeUs);
+                if (diff == 0) {
                     break;
-                } else if (diffTime < 0) {
+                } else if (diff < 0) {
                     low = mid + 1;
                 } else {
-                    if ((high == mid + 1)
-                        && (seekTimeUs < mTextVector.keyAt(high))) {
-                        break;
-                    }
-                    if (mid < 1) {
-                        break;
-                    }
                     high = mid - 1;
                 }
             }
@@ -260,6 +251,7 @@
     if (mIndex >= mTextVector.size()) {
         return ERROR_END_OF_STREAM;
     }
+
     const TextInfo &info = mTextVector.valueAt(mIndex);
     *startTimeUs = mTextVector.keyAt(mIndex);
     *endTimeUs = info.endTimeUs;
@@ -289,8 +281,18 @@
     return OK;
 }
 
-sp<MetaData> TimedTextSRTSource::getFormat() {
-    return mMetaData;
+int TimedTextSRTSource::compareExtendedRangeAndTime(size_t index, int64_t timeUs) {
+    CHECK_LT(index, mTextVector.size());
+    int64_t endTimeUs = mTextVector.valueAt(index).endTimeUs;
+    int64_t startTimeUs = (index > 0) ?
+            mTextVector.valueAt(index - 1).endTimeUs : 0;
+    if (timeUs >= startTimeUs && timeUs < endTimeUs) {
+        return 0;
+    } else if (endTimeUs <= timeUs) {
+        return -1;
+    } else {
+        return 1;
+    }
 }
 
 }  // namespace android
diff --git a/media/libstagefright/timedtext/TimedTextSRTSource.h b/media/libstagefright/timedtext/TimedTextSRTSource.h
index 9eeab39..598c200 100644
--- a/media/libstagefright/timedtext/TimedTextSRTSource.h
+++ b/media/libstagefright/timedtext/TimedTextSRTSource.h
@@ -70,6 +70,25 @@
     status_t extractAndAppendLocalDescriptions(
             int64_t timeUs, const AString &text, Parcel *parcel);
 
+    // Compares the time range of the subtitle at index to the given timeUs.
+    // The time range of the subtitle to match with given timeUs is extended to
+    // [endTimeUs of the previous subtitle, endTimeUs of current subtitle).
+    //
+    // This compare function is used to find a next subtitle when read() is
+    // called with seek options. Note that timeUs within gap ranges, such as
+    // [200, 300) in the below example, will be matched to the closest future
+    // subtitle, [300, 400).
+    //
+    // For instance, assuming there are 3 subtitles in mTextVector,
+    // 0: [100, 200)      ----> [0, 200)
+    // 1: [300, 400)      ----> [200, 400)
+    // 2: [500, 600)      ----> [400, 600)
+    // If the 'index' parameter contains 1, this function
+    // returns 0, if timeUs is in [200, 400)
+    // returns -1, if timeUs >= 400,
+    // returns 1, if timeUs < 200.
+    int compareExtendedRangeAndTime(size_t index, int64_t timeUs);
+
     DISALLOW_EVIL_CONSTRUCTORS(TimedTextSRTSource);
 };
 
diff --git a/media/libstagefright/timedtext/test/Android.mk b/media/libstagefright/timedtext/test/Android.mk
new file mode 100644
index 0000000..a5e7ba2
--- /dev/null
+++ b/media/libstagefright/timedtext/test/Android.mk
@@ -0,0 +1,27 @@
+LOCAL_PATH:= $(call my-dir)
+
+# ================================================================
+# Unit tests for libstagefright_timedtext
+# See also /development/testrunner/test_defs.xml
+# ================================================================
+
+# ================================================================
+# A test for TimedTextSRTSource
+# ================================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := TimedTextSRTSource_test
+
+LOCAL_MODULE_TAGS := eng tests
+
+LOCAL_SRC_FILES := TimedTextSRTSource_test.cpp
+
+LOCAL_C_INCLUDES := \
+    $(TOP)/external/expat/lib \
+    $(TOP)/frameworks/base/media/libstagefright/timedtext
+
+LOCAL_SHARED_LIBRARIES := \
+    libexpat \
+    libstagefright
+
+include $(BUILD_NATIVE_TEST)
diff --git a/media/libstagefright/timedtext/test/TimedTextSRTSource_test.cpp b/media/libstagefright/timedtext/test/TimedTextSRTSource_test.cpp
new file mode 100644
index 0000000..40e93c7
--- /dev/null
+++ b/media/libstagefright/timedtext/test/TimedTextSRTSource_test.cpp
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "TimedTextSRTSource_test"
+#include <utils/Log.h>
+
+#include <gtest/gtest.h>
+
+#include <binder/Parcel.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/misc.h>
+
+#include <TimedTextSource.h>
+#include <TimedTextSRTSource.h>
+
+namespace android {
+namespace test {
+
+static const int kSecToUsec = 1000000;
+static const int kSecToMsec = 1000;
+static const int kMsecToUsec = 1000;
+
+/* SRT format (http://en.wikipedia.org/wiki/SubRip)
+ *   Subtitle number
+ *   Start time --> End time
+ *   Text of subtitle (one or more lines)
+ *   Blank lines
+ */
+static const char *kSRTString =
+    "1\n00:00:1,000 --> 00:00:1,500\n1\n\n"
+    "2\n00:00:2,000 --> 00:00:2,500\n2\n\n"
+    "3\n00:00:3,000 --> 00:00:3,500\n3\n\n"
+    "4\n00:00:4,000 --> 00:00:4,500\n4\n\n"
+    "5\n00:00:5,000 --> 00:00:5,500\n5\n\n"
+    // edge case : previos end time = next start time
+    "6\n00:00:5,500 --> 00:00:5,800\n6\n\n"
+    "7\n00:00:5,800 --> 00:00:6,000\n7\n\n"
+    "8\n00:00:6,000 --> 00:00:7,000\n8\n\n";
+
+class SRTDataSourceStub : public DataSource {
+public:
+    SRTDataSourceStub(const char *data, size_t size) :
+        mData(data), mSize(size) {}
+    virtual ~SRTDataSourceStub() {}
+
+    virtual status_t initCheck() const {
+        return OK;
+    }
+
+    virtual ssize_t readAt(off64_t offset, void *data, size_t size) {
+        if (offset >= mSize) return 0;
+
+        ssize_t avail = mSize - offset;
+        if (avail > size) {
+            avail = size;
+        }
+        memcpy(data, mData + offset, avail);
+        return avail;
+    }
+
+private:
+    const char *mData;
+    size_t mSize;
+};
+
+class TimedTextSRTSourceTest : public testing::Test {
+protected:
+    void SetUp() {
+        sp<DataSource> stub= new SRTDataSourceStub(
+                kSRTString,
+                strlen(kSRTString));
+        mSource = new TimedTextSRTSource(stub);
+        mSource->start();
+    }
+
+    void CheckStartTimeMs(const Parcel& parcel, int32_t timeMs) {
+        int32_t intval;
+        parcel.setDataPosition(8);
+        parcel.readInt32(&intval);
+        EXPECT_EQ(timeMs, intval);
+    }
+
+    void CheckDataEquals(const Parcel& parcel, const char* content) {
+        int32_t intval;
+        parcel.setDataPosition(16);
+        parcel.readInt32(&intval);
+        parcel.setDataPosition(24);
+        const char* data = (const char*) parcel.readInplace(intval);
+
+        int32_t content_len = strlen(content);
+        EXPECT_EQ(content_len, intval);
+        EXPECT_TRUE(strncmp(data, content, content_len) == 0);
+    }
+
+    sp<TimedTextSource> mSource;
+    int64_t startTimeUs;
+    int64_t endTimeUs;
+    Parcel parcel;
+    AString subtitle;
+    status_t err;
+};
+
+TEST_F(TimedTextSRTSourceTest, readAll) {
+    for (int i = 1; i <= 5; i++) {
+        err = mSource->read(&startTimeUs, &endTimeUs, &parcel);
+        EXPECT_EQ(OK, err);
+        CheckStartTimeMs(parcel, i * kSecToMsec);
+        subtitle = StringPrintf("%d\n\n", i);
+        CheckDataEquals(parcel, subtitle.c_str());
+    }
+    // read edge cases
+    err = mSource->read(&startTimeUs, &endTimeUs, &parcel);
+    EXPECT_EQ(OK, err);
+    CheckStartTimeMs(parcel, 5500);
+    subtitle = StringPrintf("6\n\n");
+    CheckDataEquals(parcel, subtitle.c_str());
+
+    err = mSource->read(&startTimeUs, &endTimeUs, &parcel);
+    EXPECT_EQ(OK, err);
+    CheckStartTimeMs(parcel, 5800);
+    subtitle = StringPrintf("7\n\n");
+    CheckDataEquals(parcel, subtitle.c_str());
+
+    err = mSource->read(&startTimeUs, &endTimeUs, &parcel);
+    EXPECT_EQ(OK, err);
+    CheckStartTimeMs(parcel, 6000);
+    subtitle = StringPrintf("8\n\n");
+    CheckDataEquals(parcel, subtitle.c_str());
+
+    err = mSource->read(&startTimeUs, &endTimeUs, &parcel);
+    EXPECT_EQ(ERROR_END_OF_STREAM, err);
+}
+
+TEST_F(TimedTextSRTSourceTest, seekTimeIsEarlierThanFirst) {
+    MediaSource::ReadOptions options;
+    options.setSeekTo(500, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
+    err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
+    EXPECT_EQ(OK, err);
+    EXPECT_EQ(1 * kSecToUsec, startTimeUs);
+    CheckStartTimeMs(parcel, 1 * kSecToMsec);
+}
+
+TEST_F(TimedTextSRTSourceTest, seekTimeIsLaterThanLast) {
+    MediaSource::ReadOptions options;
+    options.setSeekTo(7 * kSecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
+    err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
+    EXPECT_EQ(ERROR_END_OF_STREAM, err);
+
+    options.setSeekTo(8 * kSecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
+    err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
+    EXPECT_EQ(ERROR_END_OF_STREAM, err);
+}
+
+TEST_F(TimedTextSRTSourceTest, seekTimeIsMatched) {
+    for (int i = 1; i <= 5; i++) {
+        MediaSource::ReadOptions options;
+        options.setSeekTo(i * kSecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
+        err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
+        EXPECT_EQ(OK, err);
+        EXPECT_EQ(i * kSecToUsec, startTimeUs);
+
+        options.setSeekTo(i * kSecToUsec + 100, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
+        err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
+        EXPECT_EQ(OK, err);
+        EXPECT_EQ(i * kSecToUsec, startTimeUs);
+    }
+}
+
+TEST_F(TimedTextSRTSourceTest, seekTimeInBetweenTwo) {
+    for (int i = 1; i <= 4; i++) {
+        MediaSource::ReadOptions options;
+        options.setSeekTo(i * kSecToUsec + 500000, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
+        err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
+        EXPECT_EQ(OK, err);
+        EXPECT_EQ((i + 1) * kSecToUsec, startTimeUs);
+
+        options.setSeekTo(i * kSecToUsec + 600000, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
+        err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
+        EXPECT_EQ(OK, err);
+        EXPECT_EQ((i + 1) * kSecToUsec, startTimeUs);
+    }
+}
+
+TEST_F(TimedTextSRTSourceTest, checkEdgeCase) {
+    MediaSource::ReadOptions options;
+    options.setSeekTo(5500 * kMsecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
+    err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
+    EXPECT_EQ(OK, err);
+    EXPECT_EQ(5500 * kMsecToUsec, startTimeUs);
+    subtitle = StringPrintf("6\n\n");
+    CheckDataEquals(parcel, subtitle.c_str());
+
+    options.setSeekTo(5800 * kMsecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
+    err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
+    EXPECT_EQ(OK, err);
+    EXPECT_EQ(5800 * kMsecToUsec, startTimeUs);
+    subtitle = StringPrintf("7\n\n");
+    CheckDataEquals(parcel, subtitle.c_str());
+
+    options.setSeekTo(6000 * kMsecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
+    err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
+    EXPECT_EQ(OK, err);
+    EXPECT_EQ(6000 * kMsecToUsec, startTimeUs);
+    subtitle = StringPrintf("8\n\n");
+    CheckDataEquals(parcel, subtitle.c_str());
+}
+
+}  // namespace test
+}  // namespace android
diff --git a/media/mtp/MtpDevice.cpp b/media/mtp/MtpDevice.cpp
index bf7795c..d672dff 100644
--- a/media/mtp/MtpDevice.cpp
+++ b/media/mtp/MtpDevice.cpp
@@ -667,7 +667,7 @@
 // reads the object's data and writes it to the specified file path
 bool MtpDevice::readObject(MtpObjectHandle handle, const char* destPath, int group, int perm) {
     ALOGD("readObject: %s", destPath);
-    int fd = ::open(destPath, O_RDWR | O_CREAT | O_TRUNC);
+    int fd = ::open(destPath, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
     if (fd < 0) {
         ALOGE("open failed for %s", destPath);
         return false;
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index 5606187..662a93d 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -931,7 +931,7 @@
     initialData = ret - MTP_CONTAINER_HEADER_SIZE;
 
     mtp_file_range  mfr;
-    mfr.fd = open(mSendObjectFilePath, O_RDWR | O_CREAT | O_TRUNC);
+    mfr.fd = open(mSendObjectFilePath, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
     if (mfr.fd < 0) {
         result = MTP_RESPONSE_GENERAL_ERROR;
         goto done;
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 8473fab..c2d2790 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -89,7 +89,7 @@
 
 LOCAL_CFLAGS += -DSTATE_QUEUE_INSTANTIATIONS='"StateQueueInstantiations.cpp"'
 
-LOCAL_CFLAGS += -DHAVE_REQUEST_PRIORITY -UFAST_TRACKS_AT_NON_NATIVE_SAMPLE_RATE -USOAKER
+LOCAL_CFLAGS += -UFAST_TRACKS_AT_NON_NATIVE_SAMPLE_RATE
 
 # uncomment for systrace
 # LOCAL_CFLAGS += -DATRACE_TAG=ATRACE_TAG_AUDIO
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index aab9984..d65a2b6 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -83,13 +83,7 @@
 #include "PipeReader.h"
 #include "SourceAudioBufferProvider.h"
 
-#ifdef HAVE_REQUEST_PRIORITY
 #include "SchedulingPolicyService.h"
-#endif
-
-#ifdef SOAKER
-#include "Soaker.h"
-#endif
 
 // ----------------------------------------------------------------------------
 
@@ -167,6 +161,10 @@
 static uint32_t gScreenState; // incremented by 2 when screen state changes, bit 0 == 1 means "off"
                               // AudioFlinger::setParameters() updates, other threads read w/o lock
 
+// Priorities for requestPriority
+static const int kPriorityAudioApp = 2;
+static const int kPriorityFastMixer = 3;
+
 // ----------------------------------------------------------------------------
 
 #ifdef ADD_BATTERY_DATA
@@ -216,8 +214,9 @@
 AudioFlinger::AudioFlinger()
     : BnAudioFlinger(),
       mPrimaryHardwareDev(NULL),
-      mHardwareStatus(AUDIO_HW_IDLE), // see also onFirstRef()
+      mHardwareStatus(AUDIO_HW_IDLE),
       mMasterVolume(1.0f),
+      mMasterVolumeSW(1.0f),
       mMasterVolumeSupportLvl(MVS_NONE),
       mMasterMute(false),
       mNextUniqueId(1),
@@ -247,21 +246,17 @@
     }
 
     mMode = AUDIO_MODE_NORMAL;
-    mMasterVolumeSW = 1.0;
-    mMasterVolume   = 1.0;
-    mHardwareStatus = AUDIO_HW_IDLE;
 }
 
 AudioFlinger::~AudioFlinger()
 {
-
     while (!mRecordThreads.isEmpty()) {
         // closeInput() will remove first entry from mRecordThreads
-        closeInput(mRecordThreads.keyAt(0));
+        closeInput_nonvirtual(mRecordThreads.keyAt(0));
     }
     while (!mPlaybackThreads.isEmpty()) {
         // closeOutput() will remove first entry from mPlaybackThreads
-        closeOutput(mPlaybackThreads.keyAt(0));
+        closeOutput_nonvirtual(mPlaybackThreads.keyAt(0));
     }
 
     for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
@@ -278,7 +273,7 @@
 };
 #define ARRAY_SIZE(x) (sizeof((x))/sizeof(((x)[0])))
 
-audio_hw_device_t* AudioFlinger::findSuitableHwDev_l(audio_module_handle_t module, uint32_t devices)
+audio_hw_device_t* AudioFlinger::findSuitableHwDev_l(audio_module_handle_t module, audio_devices_t devices)
 {
     // if module is 0, the request comes from an old policy manager and we should load
     // well known modules
@@ -304,7 +299,7 @@
     return NULL;
 }
 
-status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args)
+void AudioFlinger::dumpClients(int fd, const Vector<String16>& args)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
@@ -327,11 +322,10 @@
         result.append(buffer);
     }
     write(fd, result.string(), result.size());
-    return NO_ERROR;
 }
 
 
-status_t AudioFlinger::dumpInternals(int fd, const Vector<String16>& args)
+void AudioFlinger::dumpInternals(int fd, const Vector<String16>& args)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
@@ -344,10 +338,9 @@
                             (uint32_t)(mStandbyTimeInNsecs / 1000000));
     result.append(buffer);
     write(fd, result.string(), result.size());
-    return NO_ERROR;
 }
 
-status_t AudioFlinger::dumpPermissionDenial(int fd, const Vector<String16>& args)
+void AudioFlinger::dumpPermissionDenial(int fd, const Vector<String16>& args)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
@@ -358,7 +351,6 @@
             IPCThreadState::self()->getCallingUid());
     result.append(buffer);
     write(fd, result.string(), result.size());
-    return NO_ERROR;
 }
 
 static bool tryLock(Mutex& mutex)
@@ -440,7 +432,7 @@
         audio_stream_type_t streamType,
         uint32_t sampleRate,
         audio_format_t format,
-        uint32_t channelMask,
+        audio_channel_mask_t channelMask,
         int frameCount,
         IAudioFlinger::track_flags_t flags,
         const sp<IMemory>& sharedBuffer,
@@ -876,17 +868,19 @@
             if (mBtNrecIsOff != btNrecIsOff) {
                 for (size_t i = 0; i < mRecordThreads.size(); i++) {
                     sp<RecordThread> thread = mRecordThreads.valueAt(i);
-                    RecordThread::RecordTrack *track = thread->track();
-                    if (track != NULL) {
-                        audio_devices_t device = (audio_devices_t)(
-                                thread->device() & AUDIO_DEVICE_IN_ALL);
-                        bool suspend = audio_is_bluetooth_sco_device(device) && btNrecIsOff;
+                    audio_devices_t device = thread->device() & AUDIO_DEVICE_IN_ALL;
+                    bool suspend = audio_is_bluetooth_sco_device(device) && btNrecIsOff;
+                    // collect all of the thread's session IDs
+                    KeyedVector<int, bool> ids = thread->sessionIds();
+                    // suspend effects associated with those session IDs
+                    for (size_t j = 0; j < ids.size(); ++j) {
+                        int sessionId = ids.keyAt(j);
                         thread->setEffectSuspended(FX_IID_AEC,
                                                    suspend,
-                                                   track->sessionId());
+                                                   sessionId);
                         thread->setEffectSuspended(FX_IID_NS,
                                                    suspend,
-                                                   track->sessionId());
+                                                   sessionId);
                     }
                 }
                 mBtNrecIsOff = btNrecIsOff;
@@ -908,7 +902,7 @@
     {
         Mutex::Autolock _l(mLock);
         thread = checkPlaybackThread_l(ioHandle);
-        if (thread == NULL) {
+        if (thread == 0) {
             thread = checkRecordThread_l(ioHandle);
         } else if (thread == primaryPlaybackThread_l()) {
             // indicate output device change to all input threads for pre processing
@@ -964,7 +958,8 @@
     return String8("");
 }
 
-size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, audio_format_t format, int channelCount) const
+size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, audio_format_t format,
+        audio_channel_mask_t channelMask) const
 {
     status_t ret = initCheck();
     if (ret != NO_ERROR) {
@@ -975,7 +970,7 @@
     mHardwareStatus = AUDIO_HW_GET_INPUT_BUFFER_SIZE;
     struct audio_config config = {
         sample_rate: sampleRate,
-        channel_mask: audio_channel_in_mask_from_count(channelCount),
+        channel_mask: channelMask,
         format: format,
     };
     size_t size = mPrimaryHardwareDev->get_input_buffer_size(mPrimaryHardwareDev, &config);
@@ -985,10 +980,6 @@
 
 unsigned int AudioFlinger::getInputFramesLost(audio_io_handle_t ioHandle) const
 {
-    if (ioHandle == 0) {
-        return 0;
-    }
-
     Mutex::Autolock _l(mLock);
 
     RecordThread *recordThread = checkRecordThread_l(ioHandle);
@@ -1124,7 +1115,7 @@
 // ----------------------------------------------------------------------------
 
 AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
-        uint32_t device, type_t type)
+        audio_devices_t device, type_t type)
     :   Thread(false),
         mType(type),
         mAudioFlinger(audioFlinger), mSampleRate(0), mFrameCount(0), mNormalFrameCount(0),
@@ -1132,8 +1123,7 @@
         mChannelCount(0),
         mFrameSize(1), mFormat(AUDIO_FORMAT_INVALID),
         mParamStatus(NO_ERROR),
-        mStandby(false), mId(id),
-        mDevice(device),
+        mStandby(false), mDevice(device), mId(id),
         mDeathRecipient(new PMDeathRecipient(this))
 {
 }
@@ -1226,7 +1216,7 @@
     mLock.unlock();
 }
 
-status_t AudioFlinger::ThreadBase::dumpBase(int fd, const Vector<String16>& args)
+void AudioFlinger::ThreadBase::dumpBase(int fd, const Vector<String16>& args)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
@@ -1283,10 +1273,9 @@
     if (locked) {
         mLock.unlock();
     }
-    return NO_ERROR;
 }
 
-status_t AudioFlinger::ThreadBase::dumpEffectChains(int fd, const Vector<String16>& args)
+void AudioFlinger::ThreadBase::dumpEffectChains(int fd, const Vector<String16>& args)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
@@ -1301,7 +1290,6 @@
             chain->dump(fd, args);
         }
     }
-    return NO_ERROR;
 }
 
 void AudioFlinger::ThreadBase::acquireWakeLock()
@@ -1397,8 +1385,8 @@
         return;
     }
 
-    KeyedVector <int, sp<SuspendedSessionDesc> > sessionEffects =
-            mSuspendedSessions.editValueAt(index);
+    const KeyedVector <int, sp<SuspendedSessionDesc> >& sessionEffects =
+            mSuspendedSessions.valueAt(index);
 
     for (size_t i = 0; i < sessionEffects.size(); i++) {
         sp<SuspendedSessionDesc> desc = sessionEffects.valueAt(i);
@@ -1424,7 +1412,7 @@
 
     if (suspend) {
         if (index >= 0) {
-            sessionEffects = mSuspendedSessions.editValueAt(index);
+            sessionEffects = mSuspendedSessions.valueAt(index);
         } else {
             mSuspendedSessions.add(sessionId, sessionEffects);
         }
@@ -1432,7 +1420,7 @@
         if (index < 0) {
             return;
         }
-        sessionEffects = mSuspendedSessions.editValueAt(index);
+        sessionEffects = mSuspendedSessions.valueAt(index);
     }
 
 
@@ -1449,7 +1437,7 @@
         } else {
             desc = new SuspendedSessionDesc();
             if (type != NULL) {
-                memcpy(&desc->mType, type, sizeof(effect_uuid_t));
+                desc->mType = *type;
             }
             sessionEffects.add(key, desc);
             ALOGV("updateSuspendedSessions_l() suspend adding effect %08x", key);
@@ -1509,7 +1497,7 @@
 AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger,
                                              AudioStreamOut* output,
                                              audio_io_handle_t id,
-                                             uint32_t device,
+                                             audio_devices_t device,
                                              type_t type)
     :   ThreadBase(audioFlinger, id, device, type),
         mMixBuffer(NULL), mSuspended(0), mBytesWritten(0),
@@ -1549,15 +1537,14 @@
     delete [] mMixBuffer;
 }
 
-status_t AudioFlinger::PlaybackThread::dump(int fd, const Vector<String16>& args)
+void AudioFlinger::PlaybackThread::dump(int fd, const Vector<String16>& args)
 {
     dumpInternals(fd, args);
     dumpTracks(fd, args);
     dumpEffectChains(fd, args);
-    return NO_ERROR;
 }
 
-status_t AudioFlinger::PlaybackThread::dumpTracks(int fd, const Vector<String16>& args)
+void AudioFlinger::PlaybackThread::dumpTracks(int fd, const Vector<String16>& args)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
@@ -1605,11 +1592,9 @@
     FastTrackUnderruns underruns = getFastTrackUnderruns(0);
     fdprintf(fd, "Normal mixer raw underrun counters: partial=%u empty=%u\n",
             underruns.mBitFields.mPartial, underruns.mBitFields.mEmpty);
-
-    return NO_ERROR;
 }
 
-status_t AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String16>& args)
+void AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String16>& args)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
@@ -1633,8 +1618,6 @@
     fdprintf(fd, "Fast track availMask=%#x\n", mFastTrackAvailMask);
 
     dumpBase(fd, args);
-
-    return NO_ERROR;
 }
 
 // Thread virtuals
@@ -1660,7 +1643,7 @@
         audio_stream_type_t streamType,
         uint32_t sampleRate,
         audio_format_t format,
-        uint32_t channelMask,
+        audio_channel_mask_t channelMask,
         int frameCount,
         const sp<IMemory>& sharedBuffer,
         int sessionId,
@@ -1715,7 +1698,7 @@
                 frameCount, mFrameCount);
       } else {
         ALOGV("AUDIO_OUTPUT_FLAG_FAST denied: isTimed=%d sharedBuffer=%p frameCount=%d "
-                "mFrameCount=%d format=%d isLinear=%d channelMask=%d sampleRate=%d mSampleRate=%d "
+                "mFrameCount=%d format=%d isLinear=%d channelMask=%#x sampleRate=%d mSampleRate=%d "
                 "hasFastMixer=%d tid=%d fastTrackAvailMask=%#x",
                 isTimed, sharedBuffer.get(), frameCount, mFrameCount, format,
                 audio_is_linear_pcm(format),
@@ -1789,7 +1772,7 @@
             track = TimedTrack::create(this, client, streamType, sampleRate, format,
                     channelMask, frameCount, sharedBuffer, sessionId);
         }
-        if (track == NULL || track->getCblk() == NULL || track->name() < 0) {
+        if (track == 0 || track->getCblk() == NULL || track->name() < 0) {
             lStatus = NO_MEMORY;
             goto Exit;
         }
@@ -1804,18 +1787,16 @@
         }
     }
 
-#ifdef HAVE_REQUEST_PRIORITY
     if ((flags & IAudioFlinger::TRACK_FAST) && (tid != -1)) {
         pid_t callingPid = IPCThreadState::self()->getCallingPid();
         // we don't have CAP_SYS_NICE, nor do we want to have it as it's too powerful,
         // so ask activity manager to do this on our behalf
-        int err = requestPriority(callingPid, tid, 1);
+        int err = requestPriority(callingPid, tid, kPriorityAudioApp);
         if (err != 0) {
             ALOGW("Policy SCHED_FIFO priority %d is unavailable for pid %d tid %d; error %d",
-                    1, callingPid, tid, err);
+                    kPriorityAudioApp, callingPid, tid, err);
         }
     }
-#endif
 
     lStatus = NO_ERROR;
 
@@ -2192,28 +2173,25 @@
 // ----------------------------------------------------------------------------
 
 AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
-        audio_io_handle_t id, uint32_t device, type_t type)
+        audio_io_handle_t id, audio_devices_t device, type_t type)
     :   PlaybackThread(audioFlinger, output, id, device, type),
         // mAudioMixer below
-#ifdef SOAKER
-        mSoaker(NULL),
-#endif
         // mFastMixer below
         mFastMixerFutex(0)
         // mOutputSink below
         // mPipeSink below
         // mNormalSink below
 {
-    ALOGV("MixerThread() id=%d device=%d type=%d", id, device, type);
-    ALOGV("mSampleRate=%d, mChannelMask=%d, mChannelCount=%d, mFormat=%d, mFrameSize=%d, "
+    ALOGV("MixerThread() id=%d device=%#x type=%d", id, device, type);
+    ALOGV("mSampleRate=%d, mChannelMask=%#x, mChannelCount=%d, mFormat=%d, mFrameSize=%d, "
             "mFrameCount=%d, mNormalFrameCount=%d",
             mSampleRate, mChannelMask, mChannelCount, mFormat, mFrameSize, mFrameCount,
             mNormalFrameCount);
     mAudioMixer = new AudioMixer(mNormalFrameCount, mSampleRate);
 
     // FIXME - Current mixer implementation only supports stereo output
-    if (mChannelCount == 1) {
-        ALOGE("Invalid audio hardware channel count");
+    if (mChannelCount != FCC_2) {
+        ALOGE("Invalid audio hardware channel count %d", mChannelCount);
     }
 
     // create an NBAIO sink for the HAL output stream, and negotiate
@@ -2267,13 +2245,6 @@
         mTeeSource = teeSource;
 #endif
 
-#ifdef SOAKER
-        // create a soaker as workaround for governor issues
-        mSoaker = new Soaker();
-        // FIXME Soaker should only run when needed, i.e. when FastMixer is not in COLD_IDLE
-        mSoaker->run("Soaker", PRIORITY_LOWEST);
-#endif
-
         // create fast mixer and configure it initially with just one fast track for our submix
         mFastMixer = new FastMixer();
         FastMixerStateQueue *sq = mFastMixer->sq();
@@ -2305,14 +2276,12 @@
 
         // start the fast mixer
         mFastMixer->run("FastMixer", PRIORITY_URGENT_AUDIO);
-#ifdef HAVE_REQUEST_PRIORITY
         pid_t tid = mFastMixer->getTid();
-        int err = requestPriority(getpid_cached, tid, 2);
+        int err = requestPriority(getpid_cached, tid, kPriorityFastMixer);
         if (err != 0) {
             ALOGW("Policy SCHED_FIFO priority %d is unavailable for pid %d tid %d; error %d",
-                    2, getpid_cached, tid, err);
+                    kPriorityFastMixer, getpid_cached, tid, err);
         }
-#endif
 
 #ifdef AUDIO_WATCHDOG
         // create and start the watchdog
@@ -2320,10 +2289,10 @@
         mAudioWatchdog->setDump(&mAudioWatchdogDump);
         mAudioWatchdog->run("AudioWatchdog", PRIORITY_URGENT_AUDIO);
         tid = mAudioWatchdog->getTid();
-        err = requestPriority(getpid_cached, tid, 1);
+        err = requestPriority(getpid_cached, tid, kPriorityFastMixer);
         if (err != 0) {
             ALOGW("Policy SCHED_FIFO priority %d is unavailable for pid %d tid %d; error %d",
-                    1, getpid_cached, tid, err);
+                    kPriorityFastMixer, getpid_cached, tid, err);
         }
 #endif
 
@@ -2370,12 +2339,6 @@
         delete fastTrack->mBufferProvider;
         sq->end(false /*didModify*/);
         delete mFastMixer;
-#ifdef SOAKER
-        if (mSoaker != NULL) {
-            mSoaker->requestExitAndWait();
-        }
-        delete mSoaker;
-#endif
         if (mAudioWatchdog != 0) {
             mAudioWatchdog->requestExit();
             mAudioWatchdog->requestExitAndWait();
@@ -2508,9 +2471,6 @@
 
     // MIXER
     nsecs_t lastWarning = 0;
-if (mType == MIXER) {
-    longStandbyExit = false;
-}
 
     // DUPLICATING
     // FIXME could this be made local to while loop?
@@ -2519,9 +2479,9 @@
     cacheParameters_l();
     sleepTime = idleSleepTime;
 
-if (mType == MIXER) {
-    sleepTimeShift = 0;
-}
+    if (mType == MIXER) {
+        sleepTimeShift = 0;
+    }
 
     CpuStats cpuStats;
     const String8 myName(String8::format("thread %p type %d TID %d", this, mType, gettid()));
@@ -2548,7 +2508,7 @@
 
             // put audio hardware into standby after short delay
             if (CC_UNLIKELY((!mActiveTracks.size() && systemTime() > standbyTime) ||
-                        mSuspended > 0)) {
+                        isSuspended())) {
                 if (!mStandby) {
 
                     threadLoop_standby();
@@ -2602,7 +2562,7 @@
             threadLoop_sleepTime();
         }
 
-        if (mSuspended > 0) {
+        if (isSuspended()) {
             sleepTime = suspendSleepTimeUs();
         }
 
@@ -2635,11 +2595,6 @@
                             ns2ms(delta), mNumDelayedWrites, this);
                     lastWarning = now;
                 }
-                // FIXME this is broken: longStandbyExit should be handled out of the if() and with
-                // a different threshold. Or completely removed for what it is worth anyway...
-                if (mStandby) {
-                    longStandbyExit = true;
-                }
             }
 }
 
@@ -2667,15 +2622,13 @@
         // is now local to this block, but will keep it for now (at least until merge done).
     }
 
-if (mType == MIXER || mType == DIRECT) {
-    // put output stream into standby mode
-    if (!mStandby) {
-        mOutput->stream->common.standby(&mOutput->stream->common);
+    // for DuplicatingThread, standby mode is handled by the outputTracks, otherwise ...
+    if (mType == MIXER || mType == DIRECT) {
+        // put output stream into standby mode
+        if (!mStandby) {
+            mOutput->stream->common.standby(&mOutput->stream->common);
+        }
     }
-}
-if (mType == DUPLICATING) {
-    // for DuplicatingThread, standby mode is handled by the outputTracks
-}
 
     releaseWakeLock();
 
@@ -2794,7 +2747,7 @@
 // shared by MIXER and DIRECT, overridden by DUPLICATING
 void AudioFlinger::PlaybackThread::threadLoop_standby()
 {
-    ALOGV("Audio hardware entering standby, mixer %p, suspend count %u", this, mSuspended);
+    ALOGV("Audio hardware entering standby, mixer %p, suspend count %d", this, mSuspended);
     mOutput->stream->common.standby(&mOutput->stream->common);
 }
 
@@ -2847,11 +2800,10 @@
         } else {
             sleepTime = idleSleepTime;
         }
-    } else if (mBytesWritten != 0 ||
-               (mMixerStatus == MIXER_TRACKS_ENABLED && longStandbyExit)) {
+    } else if (mBytesWritten != 0 || (mMixerStatus == MIXER_TRACKS_ENABLED)) {
         memset (mMixBuffer, 0, mixBufferSize);
         sleepTime = 0;
-        ALOGV_IF((mBytesWritten == 0 && (mMixerStatus == MIXER_TRACKS_ENABLED && longStandbyExit)), "anticipated start");
+        ALOGV_IF((mBytesWritten == 0 && (mMixerStatus == MIXER_TRACKS_ENABLED)), "anticipated start");
     }
     // TODO add standby time extension fct of effect tail
 }
@@ -3229,7 +3181,7 @@
             }
 
             //ALOGV("track %d u=%08x, s=%08x [NOT READY] on thread %p", name, cblk->user, cblk->server, this);
-            if ((track->sharedBuffer() != 0) || track->isTerminated() ||
+            if ((track->sharedBuffer() != 0) ||
                     track->isStopped() || track->isPaused()) {
                 // We have consumed all the buffers of this track.
                 // Remove it from the list of active tracks.
@@ -3249,8 +3201,8 @@
                 track->mUnderrunCount++;
                 // No buffers for this track. Give it a few chances to
                 // fill a buffer, then remove it from active list.
-                if (--(track->mRetryCount) <= 0) {
-                    ALOGV("BUFFER TIMEOUT: remove(%d) from active list on thread %p", name, this);
+                if (--(track->mRetryCount) <= 0 || track->isTerminated()) {
+                    ALOGV_IF(track->mRetryCount <= 0, "BUFFER TIMEOUT: remove(%d) from active list on thread %p", name, this);
                     tracksToRemove->add(track);
                     // indicate to client process that the track was disabled because of underrun;
                     // it will then automatically call start() when data is available
@@ -3373,7 +3325,7 @@
     idleSleepTime = idleSleepTimeUs();
 }
 
-void AudioFlinger::MixerThread::invalidateTracks(audio_stream_type_t streamType)
+void AudioFlinger::PlaybackThread::invalidateTracks(audio_stream_type_t streamType)
 {
     ALOGV ("MixerThread::invalidateTracks() mixer %p, streamType %d, mTracks.size %d",
             this,  streamType, mTracks.size());
@@ -3460,14 +3412,14 @@
 #ifdef ADD_BATTERY_DATA
             // when changing the audio output device, call addBatteryData to notify
             // the change
-            if ((int)mDevice != value) {
+            if (mDevice != value) {
                 uint32_t params = 0;
                 // check whether speaker is on
                 if (value & AUDIO_DEVICE_OUT_SPEAKER) {
                     params |= IMediaPlayerService::kBatteryDataSpeakerOn;
                 }
 
-                int deviceWithoutSpeaker
+                audio_devices_t deviceWithoutSpeaker
                     = AUDIO_DEVICE_OUT_ALL & ~AUDIO_DEVICE_OUT_SPEAKER;
                 // check if any other device (except speaker) is on
                 if (value & deviceWithoutSpeaker ) {
@@ -3482,7 +3434,7 @@
 
             // forward device change to effects that have requested to be
             // aware of attached audio device.
-            mDevice = (uint32_t)value;
+            mDevice = value;
             for (size_t i = 0; i < mEffectChains.size(); i++) {
                 mEffectChains[i]->setDevice_l(mDevice);
             }
@@ -3505,7 +3457,7 @@
                 readOutputParameters();
                 mAudioMixer = new AudioMixer(mNormalFrameCount, mSampleRate);
                 for (size_t i = 0; i < mTracks.size() ; i++) {
-                    int name = getTrackName_l((audio_channel_mask_t)mTracks[i]->mChannelMask);
+                    int name = getTrackName_l(mTracks[i]->mChannelMask);
                     if (name < 0) break;
                     mTracks[i]->mName = name;
                     // limit track sample rate to 2 x new output sample rate
@@ -3539,7 +3491,7 @@
     return reconfig;
 }
 
-status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>& args)
+void AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>& args)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
@@ -3602,7 +3554,7 @@
                     }
                     break;
                 }
-                ALOG_ASSERT(actual <= count);
+                ALOG_ASSERT(actual <= (ssize_t)count);
                 write(teeFd, buffer, actual * channelCount * sizeof(short));
                 total += actual;
             }
@@ -3624,8 +3576,6 @@
         AudioWatchdogDump wdCopy = mAudioWatchdogDump;
         wdCopy.dump(fd);
     }
-
-    return NO_ERROR;
 }
 
 uint32_t AudioFlinger::MixerThread::idleSleepTimeUs() const
@@ -3651,7 +3601,7 @@
 
 // ----------------------------------------------------------------------------
 AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger,
-        AudioStreamOut* output, audio_io_handle_t id, uint32_t device)
+        AudioStreamOut* output, audio_io_handle_t id, audio_devices_t device)
     :   PlaybackThread(audioFlinger, output, id, device, DIRECT)
         // mLeftVolFloat, mRightVolFloat
 {
@@ -3751,7 +3701,7 @@
             }
 
             //ALOGV("track %d u=%08x, s=%08x [NOT READY]", track->name(), cblk->user, cblk->server);
-            if ((track->sharedBuffer() != 0) || track->isTerminated() ||
+            if ((track->sharedBuffer() != 0) ||
                     track->isStopped() || track->isPaused()) {
                 // We have consumed all the buffers of this track.
                 // Remove it from the list of active tracks.
@@ -3769,8 +3719,8 @@
             } else {
                 // No buffers for this track. Give it a few chances to
                 // fill a buffer, then remove it from active list.
-                if (--(track->mRetryCount) <= 0) {
-                    ALOGV("BUFFER TIMEOUT: remove(%d) from active list", track->name());
+                if (--(track->mRetryCount) <= 0 || track->isTerminated()) {
+                    ALOGV_IF(track->mRetryCount <= 0, "BUFFER TIMEOUT: remove(%d) from active list", track->name());
                     trackToRemove = track;
                 } else {
                     mixerStatus = MIXER_TRACKS_ENABLED;
@@ -4070,6 +4020,7 @@
             return false;
         }
         PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
+        // see note at standby() declaration
         if (playbackThread->standby() && !playbackThread->isSuspended()) {
             ALOGV("DuplicatingThread output track %p on thread %p Not Ready", outputTracks[i].get(), thread.get());
             return false;
@@ -4099,7 +4050,7 @@
             const sp<Client>& client,
             uint32_t sampleRate,
             audio_format_t format,
-            uint32_t channelMask,
+            audio_channel_mask_t channelMask,
             int frameCount,
             const sp<IMemory>& sharedBuffer,
             int sessionId)
@@ -4274,7 +4225,7 @@
             audio_stream_type_t streamType,
             uint32_t sampleRate,
             audio_format_t format,
-            uint32_t channelMask,
+            audio_channel_mask_t channelMask,
             int frameCount,
             const sp<IMemory>& sharedBuffer,
             int sessionId,
@@ -4300,7 +4251,7 @@
         // 16 bit because data is converted to 16 bit before being stored in buffer by AudioTrack
         mCblk->frameSize = audio_is_linear_pcm(format) ? mChannelCount * sizeof(int16_t) : sizeof(uint8_t);
         // to avoid leaking a track name, do not allocate one unless there is an mCblk
-        mName = thread->getTrackName_l((audio_channel_mask_t)channelMask);
+        mName = thread->getTrackName_l(channelMask);
         mCblk->mName = mName;
         if (mName < 0) {
             ALOGE("no more track names available");
@@ -4329,11 +4280,6 @@
 AudioFlinger::PlaybackThread::Track::~Track()
 {
     ALOGV("PlaybackThread::Track destructor");
-    sp<ThreadBase> thread = mThread.promote();
-    if (thread != 0) {
-        Mutex::Autolock _l(thread->mLock);
-        mState = TERMINATED;
-    }
 }
 
 void AudioFlinger::PlaybackThread::Track::destroy()
@@ -4496,8 +4442,6 @@
         }
 
         buffer->raw = getBuffer(s, framesReq);
-        if (buffer->raw == NULL) goto getNextBuffer_exit;
-
         buffer->frameCount = framesReq;
         return NO_ERROR;
     }
@@ -4821,12 +4765,12 @@
             audio_stream_type_t streamType,
             uint32_t sampleRate,
             audio_format_t format,
-            uint32_t channelMask,
+            audio_channel_mask_t channelMask,
             int frameCount,
             const sp<IMemory>& sharedBuffer,
             int sessionId) {
     if (!client->reserveTimedTrack())
-        return NULL;
+        return 0;
 
     return new TimedTrack(
         thread, client, streamType, sampleRate, format, channelMask, frameCount,
@@ -4839,7 +4783,7 @@
             audio_stream_type_t streamType,
             uint32_t sampleRate,
             audio_format_t format,
-            uint32_t channelMask,
+            audio_channel_mask_t channelMask,
             int frameCount,
             const sp<IMemory>& sharedBuffer,
             int sessionId)
@@ -5061,7 +5005,7 @@
     AudioBufferProvider::Buffer* buffer, int64_t pts)
 {
     if (pts == AudioBufferProvider::kInvalidPTS) {
-        buffer->raw = 0;
+        buffer->raw = NULL;
         buffer->frameCount = 0;
         mTimedAudioOutputOnTime = false;
         return INVALID_OPERATION;
@@ -5076,7 +5020,7 @@
 
         // if we have no timed buffers, then fail
         if (mTimedBufferQueue.isEmpty()) {
-            buffer->raw = 0;
+            buffer->raw = NULL;
             buffer->frameCount = 0;
             return NOT_ENOUGH_DATA;
         }
@@ -5103,7 +5047,7 @@
                 // the transform failed.  this shouldn't happen, but if it does
                 // then just drop this buffer
                 ALOGW("timedGetNextBuffer transform failed");
-                buffer->raw = 0;
+                buffer->raw = NULL;
                 buffer->frameCount = 0;
                 trimTimedBufferQueueHead_l("getNextBuffer; no transform");
                 return NO_ERROR;
@@ -5112,7 +5056,7 @@
             if (mMediaTimeTransformTarget == TimedAudioTrack::COMMON_TIME) {
                 if (OK != mCCHelper.commonTimeToLocalTime(transformedPTS,
                                                           &headLocalPTS)) {
-                    buffer->raw = 0;
+                    buffer->raw = NULL;
                     buffer->frameCount = 0;
                     return INVALID_OPERATION;
                 }
@@ -5334,7 +5278,7 @@
             const sp<Client>& client,
             uint32_t sampleRate,
             audio_format_t format,
-            uint32_t channelMask,
+            audio_channel_mask_t channelMask,
             int frameCount,
             int sessionId)
     :   TrackBase(thread, client, sampleRate, format,
@@ -5355,10 +5299,7 @@
 
 AudioFlinger::RecordThread::RecordTrack::~RecordTrack()
 {
-    sp<ThreadBase> thread = mThread.promote();
-    if (thread != 0) {
-        AudioSystem::releaseInput(thread->id());
-    }
+    ALOGV("%s", __func__);
 }
 
 // AudioBufferProvider interface
@@ -5389,8 +5330,6 @@
         }
 
         buffer->raw = getBuffer(s, framesReq);
-        if (buffer->raw == NULL) goto getNextBuffer_exit;
-
         buffer->frameCount = framesReq;
         return NO_ERROR;
     }
@@ -5418,14 +5357,26 @@
     sp<ThreadBase> thread = mThread.promote();
     if (thread != 0) {
         RecordThread *recordThread = (RecordThread *)thread.get();
-        recordThread->stop(this);
-        TrackBase::reset();
-        // Force overrun condition to avoid false overrun callback until first data is
-        // read from buffer
-        android_atomic_or(CBLK_UNDERRUN_ON, &mCblk->flags);
+        recordThread->mLock.lock();
+        bool doStop = recordThread->stop_l(this);
+        if (doStop) {
+            TrackBase::reset();
+            // Force overrun condition to avoid false overrun callback until first data is
+            // read from buffer
+            android_atomic_or(CBLK_UNDERRUN_ON, &mCblk->flags);
+        }
+        recordThread->mLock.unlock();
+        if (doStop) {
+            AudioSystem::stopInput(recordThread->id());
+        }
     }
 }
 
+/*static*/ void AudioFlinger::RecordThread::RecordTrack::appendDumpHeader(String8& result)
+{
+    result.append("   Clien Fmt Chn mask   Session Buf  S SRate  Serv     User\n");
+}
+
 void AudioFlinger::RecordThread::RecordTrack::dump(char* buffer, size_t size)
 {
     snprintf(buffer, size, "   %05d %03u 0x%08x %05d   %04u %01d %05u  %08x %08x\n",
@@ -5448,7 +5399,7 @@
             DuplicatingThread *sourceThread,
             uint32_t sampleRate,
             audio_format_t format,
-            uint32_t channelMask,
+            audio_channel_mask_t channelMask,
             int frameCount)
     :   Track(playbackThread, NULL, AUDIO_STREAM_CNT, sampleRate, format, channelMask, frameCount,
                 NULL, 0, IAudioFlinger::TRACK_DEFAULT),
@@ -5836,9 +5787,10 @@
         audio_io_handle_t input,
         uint32_t sampleRate,
         audio_format_t format,
-        uint32_t channelMask,
+        audio_channel_mask_t channelMask,
         int frameCount,
         IAudioFlinger::track_flags_t flags,
+        pid_t tid,
         int *sessionId,
         status_t *status)
 {
@@ -5877,13 +5829,8 @@
             }
         }
         // create new record track. The record track uses one track in mHardwareMixerThread by convention.
-        recordTrack = thread->createRecordTrack_l(client,
-                                                sampleRate,
-                                                format,
-                                                channelMask,
-                                                frameCount,
-                                                lSessionId,
-                                                &lStatus);
+        recordTrack = thread->createRecordTrack_l(client, sampleRate, format, channelMask,
+                                                  frameCount, lSessionId, flags, tid, &lStatus);
     }
     if (lStatus != NO_ERROR) {
         // remove local strong reference to Client before deleting the RecordTrack so that the Client
@@ -5913,19 +5860,24 @@
 }
 
 AudioFlinger::RecordHandle::~RecordHandle() {
-    stop();
+    stop_nonvirtual();
+    mRecordTrack->destroy();
 }
 
 sp<IMemory> AudioFlinger::RecordHandle::getCblk() const {
     return mRecordTrack->getCblk();
 }
 
-status_t AudioFlinger::RecordHandle::start(int event, int triggerSession) {
+status_t AudioFlinger::RecordHandle::start(int /*AudioSystem::sync_event_t*/ event, int triggerSession) {
     ALOGV("RecordHandle::start()");
     return mRecordTrack->start((AudioSystem::sync_event_t)event, triggerSession);
 }
 
 void AudioFlinger::RecordHandle::stop() {
+    stop_nonvirtual();
+}
+
+void AudioFlinger::RecordHandle::stop_nonvirtual() {
     ALOGV("RecordHandle::stop()");
     mRecordTrack->stop();
 }
@@ -5941,13 +5893,13 @@
 AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger,
                                          AudioStreamIn *input,
                                          uint32_t sampleRate,
-                                         uint32_t channels,
+                                         audio_channel_mask_t channelMask,
                                          audio_io_handle_t id,
-                                         uint32_t device) :
+                                         audio_devices_t device) :
     ThreadBase(audioFlinger, id, device, RECORD),
-    mInput(input), mTrack(NULL), mResampler(NULL), mRsmpOutBuffer(NULL), mRsmpInBuffer(NULL),
+    mInput(input), mResampler(NULL), mRsmpOutBuffer(NULL), mRsmpInBuffer(NULL),
     // mRsmpInIndex and mInputBytes set by readInputParameters()
-    mReqChannelCount(popcount(channels)),
+    mReqChannelCount(popcount(channelMask)),
     mReqSampleRate(sampleRate)
     // mBytesRead is only meaningful while active, and so is cleared in start()
     // (but might be better to also clear here for dump?)
@@ -5985,6 +5937,7 @@
 
     nsecs_t lastWarning = 0;
 
+    inputStandBy();
     acquireWakeLock();
 
     // start recording
@@ -5996,10 +5949,7 @@
             Mutex::Autolock _l(mLock);
             checkForNewParameters_l();
             if (mActiveTrack == 0 && mConfigEvents.isEmpty()) {
-                if (!mStandby) {
-                    mInput->stream->common.standby(&mInput->stream->common);
-                    mStandby = true;
-                }
+                standby();
 
                 if (exitPending()) break;
 
@@ -6013,10 +5963,7 @@
             }
             if (mActiveTrack != 0) {
                 if (mActiveTrack->mState == TrackBase::PAUSING) {
-                    if (!mStandby) {
-                        mInput->stream->common.standby(&mInput->stream->common);
-                        mStandby = true;
-                    }
+                    standby();
                     mActiveTrack.clear();
                     mStartStopCond.broadcast();
                 } else if (mActiveTrack->mState == TrackBase::RESUMING) {
@@ -6034,6 +5981,9 @@
                         mStartStopCond.broadcast();
                     }
                     mStandby = false;
+                } else if (mActiveTrack->mState == TrackBase::TERMINATED) {
+                    removeTrack_l(mActiveTrack);
+                    mActiveTrack.clear();
                 }
             }
             lockEffectChains_l(effectChains);
@@ -6068,18 +6018,12 @@
                                 mFormat != AUDIO_FORMAT_PCM_16_BIT) {
                                 memcpy(dst, src, framesIn * mFrameSize);
                             } else {
-                                int16_t *src16 = (int16_t *)src;
-                                int16_t *dst16 = (int16_t *)dst;
                                 if (mChannelCount == 1) {
-                                    while (framesIn--) {
-                                        *dst16++ = *src16;
-                                        *dst16++ = *src16++;
-                                    }
+                                    upmix_to_stereo_i16_from_mono_i16((int16_t *)dst,
+                                            (int16_t *)src, framesIn);
                                 } else {
-                                    while (framesIn--) {
-                                        *dst16++ = (int16_t)(((int32_t)*src16 + (int32_t)*(src16 + 1)) >> 1);
-                                        src16 += 2;
-                                    }
+                                    downmix_to_mono_i16_from_stereo_i16((int16_t *)dst,
+                                            (int16_t *)src, framesIn);
                                 }
                             }
                         }
@@ -6097,7 +6041,7 @@
                                 if (mActiveTrack->mState == TrackBase::ACTIVE) {
                                     // Force input into standby so that it tries to
                                     // recover at next read attempt
-                                    mInput->stream->common.standby(&mInput->stream->common);
+                                    inputStandBy();
                                     usleep(kRecordThreadSleepUs);
                                 }
                                 mRsmpInIndex = mFrameCount;
@@ -6120,12 +6064,8 @@
                     if (mChannelCount == 2 && mReqChannelCount == 1) {
                         ditherAndClamp(mRsmpOutBuffer, mRsmpOutBuffer, framesOut);
                         // the resampler always outputs stereo samples: do post stereo to mono conversion
-                        int16_t *src = (int16_t *)mRsmpOutBuffer;
-                        int16_t *dst = buffer.i16;
-                        while (framesOut--) {
-                            *dst++ = (int16_t)(((int32_t)*src + (int32_t)*(src + 1)) >> 1);
-                            src += 2;
-                        }
+                        downmix_to_mono_i16_from_stereo_i16(buffer.i16, (int16_t *)mRsmpOutBuffer,
+                                framesOut);
                     } else {
                         ditherAndClamp((int32_t *)buffer.raw, mRsmpOutBuffer, framesOut);
                     }
@@ -6151,7 +6091,7 @@
                         }
                     }
                 }
-                mActiveTrack->overflow();
+                mActiveTrack->clearOverflow();
             }
             // client isn't retrieving buffers fast enough
             else {
@@ -6173,12 +6113,13 @@
         effectChains.clear();
     }
 
-    if (!mStandby) {
-        mInput->stream->common.standby(&mInput->stream->common);
-    }
-    mActiveTrack.clear();
+    standby();
 
-    mStartStopCond.broadcast();
+    {
+        Mutex::Autolock _l(mLock);
+        mActiveTrack.clear();
+        mStartStopCond.broadcast();
+    }
 
     releaseWakeLock();
 
@@ -6186,14 +6127,28 @@
     return false;
 }
 
+void AudioFlinger::RecordThread::standby()
+{
+    if (!mStandby) {
+        inputStandBy();
+        mStandby = true;
+    }
+}
+
+void AudioFlinger::RecordThread::inputStandBy()
+{
+    mInput->stream->common.standby(&mInput->stream->common);
+}
 
 sp<AudioFlinger::RecordThread::RecordTrack>  AudioFlinger::RecordThread::createRecordTrack_l(
         const sp<AudioFlinger::Client>& client,
         uint32_t sampleRate,
         audio_format_t format,
-        int channelMask,
+        audio_channel_mask_t channelMask,
         int frameCount,
         int sessionId,
+        IAudioFlinger::track_flags_t flags,
+        pid_t tid,
         status_t *status)
 {
     sp<RecordTrack> track;
@@ -6205,6 +6160,8 @@
         goto Exit;
     }
 
+    // FIXME use flags and tid similar to createTrack_l()
+
     { // scope for mLock
         Mutex::Autolock _l(mLock);
 
@@ -6215,11 +6172,11 @@
             lStatus = NO_MEMORY;
             goto Exit;
         }
+        mTracks.add(track);
 
-        mTrack = track.get();
         // disable AEC and NS if the device is a BT SCO headset supporting those pre processings
-        bool suspend = audio_is_bluetooth_sco_device(
-                (audio_devices_t)(mDevice & AUDIO_DEVICE_IN_ALL)) && mAudioFlinger->btNrecIsOff();
+        bool suspend = audio_is_bluetooth_sco_device(mDevice & AUDIO_DEVICE_IN_ALL) &&
+                        mAudioFlinger->btNrecIsOff();
         setEffectSuspended_l(FX_IID_AEC, suspend, sessionId);
         setEffectSuspended_l(FX_IID_NS, suspend, sessionId);
     }
@@ -6337,27 +6294,23 @@
     }
 }
 
-void AudioFlinger::RecordThread::stop(RecordThread::RecordTrack* recordTrack) {
+bool AudioFlinger::RecordThread::stop_l(RecordThread::RecordTrack* recordTrack) {
     ALOGV("RecordThread::stop");
-    sp<ThreadBase> strongMe = this;
-    {
-        AutoMutex lock(mLock);
-        if (mActiveTrack != 0 && recordTrack == mActiveTrack.get()) {
-            mActiveTrack->mState = TrackBase::PAUSING;
-            // do not wait for mStartStopCond if exiting
-            if (exitPending()) {
-                return;
-            }
-            mStartStopCond.wait(mLock);
-            // if we have been restarted, recordTrack == mActiveTrack.get() here
-            if (mActiveTrack == 0 || recordTrack != mActiveTrack.get()) {
-                mLock.unlock();
-                AudioSystem::stopInput(mId);
-                mLock.lock();
-                ALOGV("Record stopped OK");
-            }
-        }
+    if (recordTrack != mActiveTrack.get() || recordTrack->mState == TrackBase::PAUSING) {
+        return false;
     }
+    recordTrack->mState = TrackBase::PAUSING;
+    // do not wait for mStartStopCond if exiting
+    if (exitPending()) {
+        return true;
+    }
+    mStartStopCond.wait(mLock);
+    // if we have been restarted, recordTrack == mActiveTrack.get() here
+    if (exitPending() || recordTrack != mActiveTrack.get()) {
+        ALOGV("Record stopped OK");
+        return true;
+    }
+    return false;
 }
 
 bool AudioFlinger::RecordThread::isValidSyncEvent(const sp<SyncEvent>& event)
@@ -6371,16 +6324,63 @@
         return BAD_VALUE;
     }
 
+    int eventSession = event->triggerSession();
+    status_t ret = NAME_NOT_FOUND;
+
     Mutex::Autolock _l(mLock);
 
-    if (mTrack != NULL && event->triggerSession() == mTrack->sessionId()) {
-        mTrack->setSyncEvent(event);
-        return NO_ERROR;
+    for (size_t i = 0; i < mTracks.size(); i++) {
+        sp<RecordTrack> track = mTracks[i];
+        if (eventSession == track->sessionId()) {
+            track->setSyncEvent(event);
+            ret = NO_ERROR;
+        }
     }
-    return NAME_NOT_FOUND;
+    return ret;
 }
 
-status_t AudioFlinger::RecordThread::dump(int fd, const Vector<String16>& args)
+void AudioFlinger::RecordThread::RecordTrack::destroy()
+{
+    // see comments at AudioFlinger::PlaybackThread::Track::destroy()
+    sp<RecordTrack> keep(this);
+    {
+        sp<ThreadBase> thread = mThread.promote();
+        if (thread != 0) {
+            if (mState == ACTIVE || mState == RESUMING) {
+                AudioSystem::stopInput(thread->id());
+            }
+            AudioSystem::releaseInput(thread->id());
+            Mutex::Autolock _l(thread->mLock);
+            RecordThread *recordThread = (RecordThread *) thread.get();
+            recordThread->destroyTrack_l(this);
+        }
+    }
+}
+
+// destroyTrack_l() must be called with ThreadBase::mLock held
+void AudioFlinger::RecordThread::destroyTrack_l(const sp<RecordTrack>& track)
+{
+    track->mState = TrackBase::TERMINATED;
+    // active tracks are removed by threadLoop()
+    if (mActiveTrack != track) {
+        removeTrack_l(track);
+    }
+}
+
+void AudioFlinger::RecordThread::removeTrack_l(const sp<RecordTrack>& track)
+{
+    mTracks.remove(track);
+    // need anything related to effects here?
+}
+
+void AudioFlinger::RecordThread::dump(int fd, const Vector<String16>& args)
+{
+    dumpInternals(fd, args);
+    dumpTracks(fd, args);
+    dumpEffectChains(fd, args);
+}
+
+void AudioFlinger::RecordThread::dumpInternals(int fd, const Vector<String16>& args)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
@@ -6390,11 +6390,6 @@
     result.append(buffer);
 
     if (mActiveTrack != 0) {
-        result.append("Active Track:\n");
-        result.append("   Clien Fmt Chn mask   Session Buf  S SRate  Serv     User\n");
-        mActiveTrack->dump(buffer, SIZE);
-        result.append(buffer);
-
         snprintf(buffer, SIZE, "In index: %d\n", mRsmpInIndex);
         result.append(buffer);
         snprintf(buffer, SIZE, "In size: %d\n", mInputBytes);
@@ -6405,17 +6400,41 @@
         result.append(buffer);
         snprintf(buffer, SIZE, "Out sample rate: %d\n", mReqSampleRate);
         result.append(buffer);
-
-
     } else {
-        result.append("No record client\n");
+        result.append("No active record client\n");
     }
+
     write(fd, result.string(), result.size());
 
     dumpBase(fd, args);
-    dumpEffectChains(fd, args);
+}
 
-    return NO_ERROR;
+void AudioFlinger::RecordThread::dumpTracks(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, "Input thread %p tracks\n", this);
+    result.append(buffer);
+    RecordTrack::appendDumpHeader(result);
+    for (size_t i = 0; i < mTracks.size(); ++i) {
+        sp<RecordTrack> track = mTracks[i];
+        if (track != 0) {
+            track->dump(buffer, SIZE);
+            result.append(buffer);
+        }
+    }
+
+    if (mActiveTrack != 0) {
+        snprintf(buffer, SIZE, "\nInput thread %p active tracks\n", this);
+        result.append(buffer);
+        RecordTrack::appendDumpHeader(result);
+        mActiveTrack->dump(buffer, SIZE);
+        result.append(buffer);
+
+    }
+    write(fd, result.string(), result.size());
 }
 
 // AudioBufferProvider interface
@@ -6432,7 +6451,7 @@
             if (mActiveTrack->mState == TrackBase::ACTIVE) {
                 // Force input into standby so that it tries to
                 // recover at next read attempt
-                mInput->stream->common.standby(&mInput->stream->common);
+                inputStandBy();
                 usleep(kRecordThreadSleepUs);
             }
             buffer->raw = NULL;
@@ -6508,25 +6527,30 @@
             // store input device and output device but do not forward output device to audio HAL.
             // Note that status is ignored by the caller for output device
             // (see AudioFlinger::setParameters()
+            audio_devices_t newDevice = mDevice;
             if (value & AUDIO_DEVICE_OUT_ALL) {
-                mDevice &= (uint32_t)~(value & AUDIO_DEVICE_OUT_ALL);
+                newDevice &= ~(value & AUDIO_DEVICE_OUT_ALL);
                 status = BAD_VALUE;
             } else {
-                mDevice &= (uint32_t)~(value & AUDIO_DEVICE_IN_ALL);
+                newDevice &= ~(value & AUDIO_DEVICE_IN_ALL);
                 // disable AEC and NS if the device is a BT SCO headset supporting those pre processings
-                if (mTrack != NULL) {
+                if (mTracks.size() > 0) {
                     bool suspend = audio_is_bluetooth_sco_device(
                             (audio_devices_t)value) && mAudioFlinger->btNrecIsOff();
-                    setEffectSuspended_l(FX_IID_AEC, suspend, mTrack->sessionId());
-                    setEffectSuspended_l(FX_IID_NS, suspend, mTrack->sessionId());
+                    for (size_t i = 0; i < mTracks.size(); i++) {
+                        sp<RecordTrack> track = mTracks[i];
+                        setEffectSuspended_l(FX_IID_AEC, suspend, track->sessionId());
+                        setEffectSuspended_l(FX_IID_NS, suspend, track->sessionId());
+                    }
                 }
             }
-            mDevice |= (uint32_t)value;
+            newDevice |= value;
+            mDevice = newDevice;    // since mDevice is read by other threads, only write to it once
         }
         if (status == NO_ERROR) {
             status = mInput->stream->common.set_parameters(&mInput->stream->common, keyValuePair.string());
             if (status == INVALID_OPERATION) {
-                mInput->stream->common.standby(&mInput->stream->common);
+                inputStandBy();
                 status = mInput->stream->common.set_parameters(&mInput->stream->common,
                         keyValuePair.string());
             }
@@ -6656,23 +6680,28 @@
         result = EFFECT_SESSION;
     }
 
-    if (mTrack != NULL && sessionId == mTrack->sessionId()) {
-        result |= TRACK_SESSION;
+    for (size_t i = 0; i < mTracks.size(); ++i) {
+        if (sessionId == mTracks[i]->sessionId()) {
+            result |= TRACK_SESSION;
+            break;
+        }
     }
 
     return result;
 }
 
-AudioFlinger::RecordThread::RecordTrack* AudioFlinger::RecordThread::track()
+KeyedVector<int, bool> AudioFlinger::RecordThread::sessionIds()
 {
+    KeyedVector<int, bool> ids;
     Mutex::Autolock _l(mLock);
-    return mTrack;
-}
-
-AudioFlinger::AudioStreamIn* AudioFlinger::RecordThread::getInput() const
-{
-    Mutex::Autolock _l(mLock);
-    return mInput;
+    for (size_t j = 0; j < mTracks.size(); ++j) {
+        sp<RecordThread::RecordTrack> track = mTracks[j];
+        int sessionId = track->sessionId();
+        if (ids.indexOfKey(sessionId) < 0) {
+            ids.add(sessionId, true);
+        }
+    }
+    return ids;
 }
 
 AudioFlinger::AudioStreamIn* AudioFlinger::RecordThread::clearInput()
@@ -6768,7 +6797,7 @@
 
     ALOGV("openOutput(), module %d Device %x, SamplingRate %d, Format %d, Channels %x, flags %x",
               module,
-              (pDevices != NULL) ? (int)*pDevices : 0,
+              (pDevices != NULL) ? *pDevices : 0,
               config.sample_rate,
               config.format,
               config.channel_mask,
@@ -6897,6 +6926,11 @@
 
 status_t AudioFlinger::closeOutput(audio_io_handle_t output)
 {
+    return closeOutput_nonvirtual(output);
+}
+
+status_t AudioFlinger::closeOutput_nonvirtual(audio_io_handle_t output)
+{
     // keep strong reference on the playback thread so that
     // it is not destroyed while exit() is executed
     sp<PlaybackThread> thread;
@@ -6969,7 +7003,7 @@
                                           audio_devices_t *pDevices,
                                           uint32_t *pSamplingRate,
                                           audio_format_t *pFormat,
-                                          uint32_t *pChannelMask)
+                                          audio_channel_mask_t *pChannelMask)
 {
     status_t status;
     RecordThread *thread = NULL;
@@ -7012,7 +7046,7 @@
         reqFormat == config.format && config.format == AUDIO_FORMAT_PCM_16_BIT &&
         (config.sample_rate <= 2 * reqSamplingRate) &&
         (popcount(config.channel_mask) <= FCC_2) && (popcount(reqChannels) <= FCC_2)) {
-        ALOGV("openInput() reopening with proposed sampling rate and channels");
+        ALOGV("openInput() reopening with proposed sampling rate and channel mask");
         inStream = NULL;
         status = inHwDev->open_input_stream(inHwDev, id, *pDevices, &config, &inStream);
     }
@@ -7023,7 +7057,7 @@
         // Start record thread
         // RecorThread require both input and output device indication to forward to audio
         // pre processing modules
-        uint32_t device = (*pDevices) | primaryOutputDevice_l();
+        audio_devices_t device = (*pDevices) | primaryOutputDevice_l();
         thread = new RecordThread(this,
                                   input,
                                   reqSamplingRate,
@@ -7036,8 +7070,6 @@
         if (pFormat != NULL) *pFormat = config.format;
         if (pChannelMask != NULL) *pChannelMask = reqChannels;
 
-        input->stream->common.standby(&input->stream->common);
-
         // notify client processes of the new input creation
         thread->audioConfigChanged_l(AudioSystem::INPUT_OPENED);
         return id;
@@ -7048,13 +7080,18 @@
 
 status_t AudioFlinger::closeInput(audio_io_handle_t input)
 {
+    return closeInput_nonvirtual(input);
+}
+
+status_t AudioFlinger::closeInput_nonvirtual(audio_io_handle_t input)
+{
     // keep strong reference on the record thread so that
     // it is not destroyed while exit() is executed
     sp<RecordThread> thread;
     {
         Mutex::Autolock _l(mLock);
         thread = checkRecordThread_l(input);
-        if (thread == NULL) {
+        if (thread == 0) {
             return BAD_VALUE;
         }
 
@@ -7078,21 +7115,11 @@
 status_t AudioFlinger::setStreamOutput(audio_stream_type_t stream, audio_io_handle_t output)
 {
     Mutex::Autolock _l(mLock);
-    MixerThread *dstThread = checkMixerThread_l(output);
-    if (dstThread == NULL) {
-        ALOGW("setStreamOutput() bad output id %d", output);
-        return BAD_VALUE;
-    }
-
     ALOGV("setStreamOutput() stream %d to output %d", stream, output);
-    audioConfigChanged_l(AudioSystem::STREAM_CONFIG_CHANGED, output, &stream);
 
     for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
         PlaybackThread *thread = mPlaybackThreads.valueAt(i).get();
-        if (thread != dstThread && thread->type() != ThreadBase::DIRECT) {
-            MixerThread *srcThread = (MixerThread *)thread;
-            srcThread->invalidateTracks(stream);
-        }
+        thread->invalidateTracks(stream);
     }
 
     return NO_ERROR;
@@ -7186,20 +7213,14 @@
             }
         }
         if (!found) {
+            Mutex::Autolock _l (t->mLock);
             // remove all effects from the chain
             while (ec->mEffects.size()) {
                 sp<EffectModule> effect = ec->mEffects[0];
                 effect->unPin();
-                Mutex::Autolock _l (t->mLock);
                 t->removeEffect_l(effect);
-                for (size_t j = 0; j < effect->mHandles.size(); j++) {
-                    sp<EffectHandle> handle = effect->mHandles[j].promote();
-                    if (handle != 0) {
-                        handle->mEffect.clear();
-                        if (handle->mHasControl && handle->mEnabled) {
-                            t->checkSuspendOnEffectEnabled_l(effect, false, effect->sessionId());
-                        }
-                    }
+                if (effect->purgeHandles()) {
+                    t->checkSuspendOnEffectEnabled_l(effect, false, effect->sessionId());
                 }
                 AudioSystem::unregisterEffect(effect->id());
             }
@@ -7244,7 +7265,7 @@
     return NULL;
 }
 
-uint32_t AudioFlinger::primaryOutputDevice_l() const
+audio_devices_t AudioFlinger::primaryOutputDevice_l() const
 {
     PlaybackThread *thread = primaryPlaybackThread_l();
 
@@ -7401,7 +7422,7 @@
                     // 0 and the effect is not auxiliary, continue enumeration in case
                     // an auxiliary version of this effect type is available
                     found = true;
-                    memcpy(&d, &desc, sizeof(effect_descriptor_t));
+                    d = desc;
                     if (sessionId != AUDIO_SESSION_OUTPUT_MIX ||
                             (desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
                         break;
@@ -7417,7 +7438,7 @@
             // connect to output mix (Compliance to OpenSL ES)
             if (sessionId == AUDIO_SESSION_OUTPUT_MIX &&
                     (d.flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_AUXILIARY) {
-                memcpy(&desc, &d, sizeof(effect_descriptor_t));
+                desc = d;
             }
         }
 
@@ -7436,7 +7457,7 @@
         }
 
         // return effect descriptor
-        memcpy(pDesc, &desc, sizeof(effect_descriptor_t));
+        *pDesc = desc;
 
         // If output is not specified try to find a matching audio session ID in one of the
         // output threads.
@@ -7670,7 +7691,7 @@
         }
         // create effect handle and connect it to effect module
         handle = new EffectHandle(effect, client, effectClient, priority);
-        lStatus = effect->addHandle(handle);
+        lStatus = effect->addHandle(handle.get());
         if (enabled != NULL) {
             *enabled = (int)effect->isEnabled();
         }
@@ -7810,7 +7831,7 @@
 }
 
 void AudioFlinger::ThreadBase::disconnectEffect(const sp<EffectModule>& effect,
-                                                    const wp<EffectHandle>& handle,
+                                                    EffectHandle *handle,
                                                     bool unpinIfLast) {
 
     Mutex::Autolock _l(mLock);
@@ -8002,16 +8023,18 @@
                                         effect_descriptor_t *desc,
                                         int id,
                                         int sessionId)
-    : mThread(thread), mChain(chain), mId(id), mSessionId(sessionId), mEffectInterface(NULL),
-      mStatus(NO_INIT), mState(IDLE), mSuspended(false)
+    : mPinned(sessionId > AUDIO_SESSION_OUTPUT_MIX),
+      mThread(thread), mChain(chain), mId(id), mSessionId(sessionId),
+      mDescriptor(*desc),
+      // mConfig is set by configure() and not used before then
+      mEffectInterface(NULL),
+      mStatus(NO_INIT), mState(IDLE),
+      // mMaxDisableWaitCnt is set by configure() and not used before then
+      // mDisableWaitCnt is set by process() and updateState() and not used before then
+      mSuspended(false)
 {
     ALOGV("Constructor %p", this);
     int lStatus;
-    if (thread == NULL) {
-        return;
-    }
-
-    memcpy(&mDescriptor, desc, sizeof(effect_descriptor_t));
 
     // create effect engine from effect factory
     mStatus = EffectCreate(&desc->uuid, sessionId, thread->id(), &mEffectInterface);
@@ -8025,9 +8048,6 @@
         goto Error;
     }
 
-    if (mSessionId > AUDIO_SESSION_OUTPUT_MIX) {
-        mPinned = true;
-    }
     ALOGV("Constructor success name %s, Interface %p", mDescriptor.name, mEffectInterface);
     return;
 Error:
@@ -8055,38 +8075,41 @@
     }
 }
 
-status_t AudioFlinger::EffectModule::addHandle(const sp<EffectHandle>& handle)
+status_t AudioFlinger::EffectModule::addHandle(EffectHandle *handle)
 {
     status_t status;
 
     Mutex::Autolock _l(mLock);
     int priority = handle->priority();
     size_t size = mHandles.size();
-    sp<EffectHandle> h;
+    EffectHandle *controlHandle = NULL;
     size_t i;
     for (i = 0; i < size; i++) {
-        h = mHandles[i].promote();
-        if (h == 0) continue;
+        EffectHandle *h = mHandles[i];
+        if (h == NULL || h->destroyed_l()) continue;
+        // first non destroyed handle is considered in control
+        if (controlHandle == NULL)
+            controlHandle = h;
         if (h->priority() <= priority) break;
     }
     // if inserted in first place, move effect control from previous owner to this handle
     if (i == 0) {
         bool enabled = false;
-        if (h != 0) {
-            enabled = h->enabled();
-            h->setControl(false/*hasControl*/, true /*signal*/, enabled /*enabled*/);
+        if (controlHandle != NULL) {
+            enabled = controlHandle->enabled();
+            controlHandle->setControl(false/*hasControl*/, true /*signal*/, enabled /*enabled*/);
         }
         handle->setControl(true /*hasControl*/, false /*signal*/, enabled /*enabled*/);
         status = NO_ERROR;
     } else {
         status = ALREADY_EXISTS;
     }
-    ALOGV("addHandle() %p added handle %p in position %d", this, handle.get(), i);
+    ALOGV("addHandle() %p added handle %p in position %d", this, handle, i);
     mHandles.insertAt(handle, i);
     return status;
 }
 
-size_t AudioFlinger::EffectModule::removeHandle(const wp<EffectHandle>& handle)
+size_t AudioFlinger::EffectModule::removeHandle(EffectHandle *handle)
 {
     Mutex::Autolock _l(mLock);
     size_t size = mHandles.size();
@@ -8097,43 +8120,44 @@
     if (i == size) {
         return size;
     }
-    ALOGV("removeHandle() %p removed handle %p in position %d", this, handle.unsafe_get(), i);
+    ALOGV("removeHandle() %p removed handle %p in position %d", this, handle, i);
 
-    bool enabled = false;
-    EffectHandle *hdl = handle.unsafe_get();
-    if (hdl != NULL) {
-        ALOGV("removeHandle() unsafe_get OK");
-        enabled = hdl->enabled();
-    }
     mHandles.removeAt(i);
-    size = mHandles.size();
     // if removed from first place, move effect control from this handle to next in line
-    if (i == 0 && size != 0) {
-        sp<EffectHandle> h = mHandles[0].promote();
-        if (h != 0) {
-            h->setControl(true /*hasControl*/, true /*signal*/ , enabled /*enabled*/);
+    if (i == 0) {
+        EffectHandle *h = controlHandle_l();
+        if (h != NULL) {
+            h->setControl(true /*hasControl*/, true /*signal*/ , handle->enabled() /*enabled*/);
         }
     }
 
     // Prevent calls to process() and other functions on effect interface from now on.
     // The effect engine will be released by the destructor when the last strong reference on
     // this object is released which can happen after next process is called.
-    if (size == 0 && !mPinned) {
+    if (mHandles.size() == 0 && !mPinned) {
         mState = DESTROYED;
     }
 
-    return size;
+    return mHandles.size();
 }
 
-sp<AudioFlinger::EffectHandle> AudioFlinger::EffectModule::controlHandle()
+// must be called with EffectModule::mLock held
+AudioFlinger::EffectHandle *AudioFlinger::EffectModule::controlHandle_l()
 {
-    Mutex::Autolock _l(mLock);
-    return mHandles.size() != 0 ? mHandles[0].promote() : 0;
+    // the first valid handle in the list has control over the module
+    for (size_t i = 0; i < mHandles.size(); i++) {
+        EffectHandle *h = mHandles[i];
+        if (h != NULL && !h->destroyed_l()) {
+            return h;
+        }
+    }
+
+    return NULL;
 }
 
-void AudioFlinger::EffectModule::disconnect(const wp<EffectHandle>& handle, bool unpinIfLast)
+size_t AudioFlinger::EffectModule::disconnect(EffectHandle *handle, bool unpinIfLast)
 {
-    ALOGV("disconnect() %p handle %p", this, handle.unsafe_get());
+    ALOGV("disconnect() %p handle %p", this, handle);
     // keep a strong reference on this EffectModule to avoid calling the
     // destructor before we exit
     sp<EffectModule> keep(this);
@@ -8143,6 +8167,7 @@
             thread->disconnectEffect(keep, handle, unpinIfLast);
         }
     }
+    return mHandles.size();
 }
 
 void AudioFlinger::EffectModule::updateState() {
@@ -8240,7 +8265,6 @@
 
 status_t AudioFlinger::EffectModule::configure()
 {
-    uint32_t channels;
     if (mEffectInterface == NULL) {
         return NO_INIT;
     }
@@ -8251,18 +8275,14 @@
     }
 
     // TODO: handle configuration of effects replacing track process
-    if (thread->channelCount() == 1) {
-        channels = AUDIO_CHANNEL_OUT_MONO;
-    } else {
-        channels = AUDIO_CHANNEL_OUT_STEREO;
-    }
+    audio_channel_mask_t channelMask = thread->channelMask();
 
     if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
         mConfig.inputCfg.channels = AUDIO_CHANNEL_OUT_MONO;
     } else {
-        mConfig.inputCfg.channels = channels;
+        mConfig.inputCfg.channels = channelMask;
     }
-    mConfig.outputCfg.channels = channels;
+    mConfig.outputCfg.channels = channelMask;
     mConfig.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
     mConfig.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
     mConfig.inputCfg.samplingRate = thread->sampleRate();
@@ -8452,8 +8472,8 @@
     if (cmdCode != EFFECT_CMD_GET_PARAM && status == NO_ERROR) {
         uint32_t size = (replySize == NULL) ? 0 : *replySize;
         for (size_t i = 1; i < mHandles.size(); i++) {
-            sp<EffectHandle> h = mHandles[i].promote();
-            if (h != 0) {
+            EffectHandle *h = mHandles[i];
+            if (h != NULL && !h->destroyed_l()) {
                 h->commandExecuted(cmdCode, cmdSize, pCmdData, size, pReplyData);
             }
         }
@@ -8463,8 +8483,14 @@
 
 status_t AudioFlinger::EffectModule::setEnabled(bool enabled)
 {
-
     Mutex::Autolock _l(mLock);
+    return setEnabled_l(enabled);
+}
+
+// must be called with EffectModule::mLock held
+status_t AudioFlinger::EffectModule::setEnabled_l(bool enabled)
+{
+
     ALOGV("setEnabled %p enabled %d", this, enabled);
 
     if (enabled != isEnabled()) {
@@ -8499,8 +8525,8 @@
             return NO_ERROR; // simply ignore as we are being destroyed
         }
         for (size_t i = 1; i < mHandles.size(); i++) {
-            sp<EffectHandle> h = mHandles[i].promote();
-            if (h != 0) {
+            EffectHandle *h = mHandles[i];
+            if (h != NULL && !h->destroyed_l()) {
                 h->setEnabled(enabled);
             }
         }
@@ -8573,14 +8599,14 @@
     return status;
 }
 
-status_t AudioFlinger::EffectModule::setDevice(uint32_t device)
+status_t AudioFlinger::EffectModule::setDevice(audio_devices_t device)
 {
     Mutex::Autolock _l(mLock);
     status_t status = NO_ERROR;
     if (device && (mDescriptor.flags & EFFECT_FLAG_DEVICE_MASK) == EFFECT_FLAG_DEVICE_IND) {
         // audio pre processing modules on RecordThread can receive both output and
         // input device indication in the same call
-        uint32_t dev = device & AUDIO_DEVICE_OUT_ALL;
+        audio_devices_t dev = device & AUDIO_DEVICE_OUT_ALL;
         if (dev) {
             status_t cmdStatus;
             uint32_t size = sizeof(status_t);
@@ -8649,7 +8675,23 @@
     return mSuspended;
 }
 
-status_t AudioFlinger::EffectModule::dump(int fd, const Vector<String16>& args)
+bool AudioFlinger::EffectModule::purgeHandles()
+{
+    bool enabled = false;
+    Mutex::Autolock _l(mLock);
+    for (size_t i = 0; i < mHandles.size(); i++) {
+        EffectHandle *handle = mHandles[i];
+        if (handle != NULL && !handle->destroyed_l()) {
+            handle->effect().clear();
+            if (handle->hasControl()) {
+                enabled = handle->enabled();
+            }
+        }
+    }
+    return enabled;
+}
+
+void AudioFlinger::EffectModule::dump(int fd, const Vector<String16>& args)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
@@ -8715,8 +8757,8 @@
     result.append(buffer);
     result.append("\t\t\tPid   Priority Ctrl Locked client server\n");
     for (size_t i = 0; i < mHandles.size(); ++i) {
-        sp<EffectHandle> handle = mHandles[i].promote();
-        if (handle != 0) {
+        EffectHandle *handle = mHandles[i];
+        if (handle != NULL && !handle->destroyed_l()) {
             handle->dump(buffer, SIZE);
             result.append(buffer);
         }
@@ -8729,8 +8771,6 @@
     if (locked) {
         mLock.unlock();
     }
-
-    return NO_ERROR;
 }
 
 // ----------------------------------------------------------------------------
@@ -8746,7 +8786,7 @@
                                         int32_t priority)
     : BnEffect(),
     mEffect(effect), mEffectClient(effectClient), mClient(client), mCblk(NULL),
-    mPriority(priority), mHasControl(false), mEnabled(false)
+    mPriority(priority), mHasControl(false), mEnabled(false), mDestroyed(false)
 {
     ALOGV("constructor %p", this);
 
@@ -8771,8 +8811,15 @@
 AudioFlinger::EffectHandle::~EffectHandle()
 {
     ALOGV("Destructor %p", this);
+
+    if (mEffect == 0) {
+        mDestroyed = true;
+        return;
+    }
+    mEffect->lock();
+    mDestroyed = true;
+    mEffect->unlock();
     disconnect(false);
-    ALOGV("Destructor DONE %p", this);
 }
 
 status_t AudioFlinger::EffectHandle::enable()
@@ -8843,9 +8890,8 @@
     if (mEffect == 0) {
         return;
     }
-    mEffect->disconnect(this, unpinIfLast);
-
-    if (mHasControl && mEnabled) {
+    // restore suspended effects if the disconnected handle was enabled and the last one.
+    if ((mEffect->disconnect(this, unpinIfLast) == 0) && mEnabled) {
         sp<ThreadBase> thread = mEffect->thread().promote();
         if (thread != 0) {
             thread->checkSuspendOnEffectEnabled(mEffect, false, mEffect->sessionId());
@@ -9275,7 +9321,7 @@
 }
 
 // setDevice_l() must be called with PlaybackThread::mLock held
-void AudioFlinger::EffectChain::setDevice_l(uint32_t device)
+void AudioFlinger::EffectChain::setDevice_l(audio_devices_t device)
 {
     size_t size = mEffects.size();
     for (size_t i = 0; i < size; i++) {
@@ -9350,7 +9396,7 @@
     return hasControl;
 }
 
-status_t AudioFlinger::EffectChain::dump(int fd, const Vector<String16>& args)
+void AudioFlinger::EffectChain::dump(int fd, const Vector<String16>& args)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
@@ -9384,8 +9430,6 @@
     if (locked) {
         mLock.unlock();
     }
-
-    return NO_ERROR;
 }
 
 // must be called with ThreadBase::mLock held
@@ -9401,7 +9445,7 @@
             desc = mSuspendedEffects.valueAt(index);
         } else {
             desc = new SuspendedEffectDesc();
-            memcpy(&desc->mType, type, sizeof(effect_uuid_t));
+            desc->mType = *type;
             mSuspendedEffects.add(type->timeLow, desc);
             ALOGV("setEffectSuspended_l() add entry for %08x", type->timeLow);
         }
@@ -9428,10 +9472,12 @@
                 sp<EffectModule> effect = desc->mEffect.promote();
                 if (effect != 0) {
                     effect->setSuspended(false);
-                    sp<EffectHandle> handle = effect->controlHandle();
-                    if (handle != 0) {
-                        effect->setEnabled(handle->enabled());
+                    effect->lock();
+                    EffectHandle *handle = effect->controlHandle_l();
+                    if (handle != NULL && !handle->destroyed_l()) {
+                        effect->setEnabled_l(handle->enabled());
                     }
+                    effect->unlock();
                 }
                 desc->mEffect.clear();
             }
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index cfd718f..2b6d00f 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -91,7 +91,7 @@
                                 audio_stream_type_t streamType,
                                 uint32_t sampleRate,
                                 audio_format_t format,
-                                uint32_t channelMask,
+                                audio_channel_mask_t channelMask,
                                 int frameCount,
                                 IAudioFlinger::track_flags_t flags,
                                 const sp<IMemory>& sharedBuffer,
@@ -105,9 +105,10 @@
                                 audio_io_handle_t input,
                                 uint32_t sampleRate,
                                 audio_format_t format,
-                                uint32_t channelMask,
+                                audio_channel_mask_t channelMask,
                                 int frameCount,
                                 IAudioFlinger::track_flags_t flags,
+                                pid_t tid,
                                 int *sessionId,
                                 status_t *status);
 
@@ -142,7 +143,8 @@
 
     virtual     void        registerClient(const sp<IAudioFlingerClient>& client);
 
-    virtual     size_t      getInputBufferSize(uint32_t sampleRate, audio_format_t format, int channelCount) const;
+    virtual     size_t      getInputBufferSize(uint32_t sampleRate, audio_format_t format,
+                                               audio_channel_mask_t channelMask) const;
 
     virtual audio_io_handle_t openOutput(audio_module_handle_t module,
                                          audio_devices_t *pDevices,
@@ -268,17 +270,17 @@
     // RefBase
     virtual     void        onFirstRef();
 
-    audio_hw_device_t*      findSuitableHwDev_l(audio_module_handle_t module, uint32_t devices);
+    audio_hw_device_t*      findSuitableHwDev_l(audio_module_handle_t module, audio_devices_t devices);
     void                    purgeStaleEffects_l();
 
     // standby delay for MIXER and DUPLICATING playback threads is read from property
     // ro.audio.flinger_standbytime_ms or defaults to kDefaultStandbyTimeInNsecs
     static nsecs_t          mStandbyTimeInNsecs;
 
-    // Internal dump utilites.
-    status_t dumpPermissionDenial(int fd, const Vector<String16>& args);
-    status_t dumpClients(int fd, const Vector<String16>& args);
-    status_t dumpInternals(int fd, const Vector<String16>& args);
+    // Internal dump utilities.
+    void dumpPermissionDenial(int fd, const Vector<String16>& args);
+    void dumpClients(int fd, const Vector<String16>& args);
+    void dumpInternals(int fd, const Vector<String16>& args);
 
     // --- Client ---
     class Client : public RefBase {
@@ -350,11 +352,11 @@
             RECORD              // Thread class is RecordThread
         };
 
-        ThreadBase (const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id, uint32_t device, type_t type);
+        ThreadBase (const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id, audio_devices_t device, type_t type);
         virtual             ~ThreadBase();
 
-        status_t dumpBase(int fd, const Vector<String16>& args);
-        status_t dumpEffectChains(int fd, const Vector<String16>& args);
+        void dumpBase(int fd, const Vector<String16>& args);
+        void dumpEffectChains(int fd, const Vector<String16>& args);
 
         void clearPowerManager();
 
@@ -380,14 +382,14 @@
                                         const sp<Client>& client,
                                         uint32_t sampleRate,
                                         audio_format_t format,
-                                        uint32_t channelMask,
+                                        audio_channel_mask_t channelMask,
                                         int frameCount,
                                         const sp<IMemory>& sharedBuffer,
                                         int sessionId);
             virtual             ~TrackBase();
 
-            virtual status_t    start(AudioSystem::sync_event_t event = AudioSystem::SYNC_EVENT_NONE,
-                                     int triggerSession = 0) = 0;
+            virtual status_t    start(AudioSystem::sync_event_t event,
+                                     int triggerSession) = 0;
             virtual void        stop() = 0;
                     sp<IMemory> getCblk() const { return mCblkMemory; }
                     audio_track_cblk_t* cblk() const { return mCblk; }
@@ -412,10 +414,17 @@
 
             int channelCount() const { return mChannelCount; }
 
-            uint32_t channelMask() const { return mChannelMask; }
+            audio_channel_mask_t channelMask() const { return mChannelMask; }
 
             int sampleRate() const; // FIXME inline after cblk sr moved
 
+            // Return a pointer to the start of a contiguous slice of the track buffer.
+            // Parameter 'offset' is the requested start position, expressed in
+            // monotonically increasing frame units relative to the track epoch.
+            // Parameter 'frames' is the requested length, also in frame units.
+            // Always returns non-NULL.  It is the caller's responsibility to
+            // verify that this will be successful; the result of calling this
+            // function with invalid 'offset' or 'frames' is undefined.
             void* getBuffer(uint32_t offset, uint32_t frames) const;
 
             bool isStopped() const {
@@ -455,7 +464,7 @@
             bool                mStepServerFailed;
             const int           mSessionId;
             uint8_t             mChannelCount;
-            uint32_t            mChannelMask;
+            audio_channel_mask_t mChannelMask;
             Vector < sp<SyncEvent> >mSyncEvents;
         };
 
@@ -483,14 +492,20 @@
         };
 
         virtual     status_t    initCheck() const = 0;
+
+                    // static externally-visible
                     type_t      type() const { return mType; }
+                    audio_io_handle_t id() const { return mId;}
+
+                    // dynamic externally-visible
                     uint32_t    sampleRate() const { return mSampleRate; }
                     int         channelCount() const { return mChannelCount; }
+                    audio_channel_mask_t channelMask() const { return mChannelMask; }
                     audio_format_t format() const { return mFormat; }
                     // Called by AudioFlinger::frameCount(audio_io_handle_t output) and effects,
                     // and returns the normal mix buffer's frame count.  No API for HAL frame count.
                     size_t      frameCount() const { return mNormalFrameCount; }
-                    void        wakeUp()    { mWaitWorkCV.broadcast(); }
+
         // Should be "virtual status_t requestExitAndWait()" and override same
         // method in Thread, but Thread::requestExitAndWait() is not yet virtual.
                     void        exit();
@@ -501,9 +516,11 @@
                     void        sendConfigEvent(int event, int param = 0);
                     void        sendConfigEvent_l(int event, int param = 0);
                     void        processConfigEvents();
-                    audio_io_handle_t id() const { return mId;}
+
+                    // see note at declaration of mStandby and mDevice
                     bool        standby() const { return mStandby; }
-                    uint32_t    device() const { return mDevice; }
+                    audio_devices_t device() const { return mDevice; }
+
         virtual     audio_stream_t* stream() const = 0;
 
                     sp<EffectHandle> createEffect_l(
@@ -515,7 +532,7 @@
                                         int *enabled,
                                         status_t *status);
                     void disconnectEffect(const sp< EffectModule>& effect,
-                                          const wp<EffectHandle>& handle,
+                                          EffectHandle *handle,
                                           bool unpinIfLast);
 
                     // return values for hasAudioSession (bit field)
@@ -598,7 +615,7 @@
                     void        releaseWakeLock_l();
                     void setEffectSuspended_l(const effect_uuid_t *type,
                                               bool suspend,
-                                              int sessionId = AUDIO_SESSION_OUTPUT_MIX);
+                                              int sessionId);
                     // updated mSuspendedSessions when an effect suspended or restored
                     void        updateSuspendedSessions_l(const effect_uuid_t *type,
                                                           bool suspend,
@@ -617,7 +634,7 @@
                     uint32_t                mSampleRate;
                     size_t                  mFrameCount;       // output HAL, direct output, record
                     size_t                  mNormalFrameCount; // normal mixer and effects
-                    uint32_t                mChannelMask;
+                    audio_channel_mask_t    mChannelMask;
                     uint16_t                mChannelCount;
                     size_t                  mFrameSize;
                     audio_format_t          mFormat;
@@ -646,11 +663,19 @@
                     status_t                mParamStatus;
 
                     Vector<ConfigEvent>     mConfigEvents;
-                    bool                    mStandby;
+
+                    // These fields are written and read by thread itself without lock or barrier,
+                    // and read by other threads without lock or barrier via standby() and device().
+                    // Because of the absence of a lock or barrier, any other thread that reads
+                    // these fields must use the information in isolation, or be prepared to deal
+                    // with possibility that it might be inconsistent with other information.
+                    bool                    mStandby;   // Whether thread is currently in standby.
+                    audio_devices_t         mDevice;    // output device for PlaybackThread
+                                                        // input + output devices for RecordThread
+
                     const audio_io_handle_t mId;
                     Vector< sp<EffectChain> > mEffectChains;
-                    uint32_t                mDevice;    // output device for PlaybackThread
-                                                        // input + output devices for RecordThread
+
                     static const int        kNameLength = 16;   // prctl(PR_SET_NAME) limit
                     char                    mName[kNameLength];
                     sp<IPowerManager>       mPowerManager;
@@ -691,7 +716,7 @@
                                         audio_stream_type_t streamType,
                                         uint32_t sampleRate,
                                         audio_format_t format,
-                                        uint32_t channelMask,
+                                        audio_channel_mask_t channelMask,
                                         int frameCount,
                                         const sp<IMemory>& sharedBuffer,
                                         int sessionId,
@@ -708,9 +733,7 @@
                     void        flush();
                     void        destroy();
                     void        mute(bool);
-                    int name() const {
-                        return mName;
-                    }
+                    int         name() const { return mName; }
 
                     audio_stream_type_t streamType() const {
                         return mStreamType;
@@ -767,10 +790,14 @@
             void triggerEvents(AudioSystem::sync_event_t type);
             virtual bool isTimedTrack() const { return false; }
             bool isFastTrack() const { return (mFlags & IAudioFlinger::TRACK_FAST) != 0; }
+
         protected:
 
-            // we don't really need a lock for these
-            volatile bool       mMute;
+            // written by Track::mute() called by binder thread(s), without a mutex or barrier.
+            // read by Track::isMuted() called by playback thread, also without a mutex or barrier.
+            // The lack of mutex or barrier is safe because the mute status is only used by itself.
+            bool                mMute;
+
             // FILLED state is used for suppressing volume ramp at begin of playing
             enum {FS_INVALID, FS_FILLING, FS_FILLED, FS_ACTIVE};
             mutable uint8_t     mFillingUpStatus;
@@ -813,11 +840,11 @@
                                          audio_stream_type_t streamType,
                                          uint32_t sampleRate,
                                          audio_format_t format,
-                                         uint32_t channelMask,
+                                         audio_channel_mask_t channelMask,
                                          int frameCount,
                                          const sp<IMemory>& sharedBuffer,
                                          int sessionId);
-            ~TimedTrack();
+            virtual ~TimedTrack();
 
             class TimedBuffer {
               public:
@@ -856,7 +883,7 @@
                        audio_stream_type_t streamType,
                        uint32_t sampleRate,
                        audio_format_t format,
-                       uint32_t channelMask,
+                       audio_channel_mask_t channelMask,
                        int frameCount,
                        const sp<IMemory>& sharedBuffer,
                        int sessionId);
@@ -905,7 +932,7 @@
                                         DuplicatingThread *sourceThread,
                                         uint32_t sampleRate,
                                         audio_format_t format,
-                                        uint32_t channelMask,
+                                        audio_channel_mask_t channelMask,
                                         int frameCount);
             virtual             ~OutputTrack();
 
@@ -936,10 +963,10 @@
         };  // end of OutputTrack
 
         PlaybackThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
-                        audio_io_handle_t id, uint32_t device, type_t type);
+                        audio_io_handle_t id, audio_devices_t device, type_t type);
         virtual             ~PlaybackThread();
 
-                    status_t    dump(int fd, const Vector<String16>& args);
+                    void        dump(int fd, const Vector<String16>& args);
 
         // Thread virtuals
         virtual     status_t    readyToRun();
@@ -984,7 +1011,7 @@
                                     audio_stream_type_t streamType,
                                     uint32_t sampleRate,
                                     audio_format_t format,
-                                    uint32_t channelMask,
+                                    audio_channel_mask_t channelMask,
                                     int frameCount,
                                     const sp<IMemory>& sharedBuffer,
                                     int sessionId,
@@ -996,9 +1023,19 @@
                     AudioStreamOut* clearOutput();
                     virtual audio_stream_t* stream() const;
 
-                    void        suspend() { mSuspended++; }
-                    void        restore() { if (mSuspended > 0) mSuspended--; }
-                    bool        isSuspended() const { return (mSuspended > 0); }
+                    // a very large number of suspend() will eventually wraparound, but unlikely
+                    void        suspend() { (void) android_atomic_inc(&mSuspended); }
+                    void        restore()
+                                    {
+                                        // if restore() is done without suspend(), get back into
+                                        // range so that the next suspend() will operate correctly
+                                        if (android_atomic_dec(&mSuspended) <= 0) {
+                                            android_atomic_release_store(0, &mSuspended);
+                                        }
+                                    }
+                    bool        isSuspended() const
+                                    { return android_atomic_acquire_load(&mSuspended) > 0; }
+
         virtual     String8     getParameters(const String8& keys);
         virtual     void        audioConfigChanged_l(int event, int param = 0);
                     status_t    getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames);
@@ -1018,10 +1055,19 @@
 
                     virtual status_t setSyncEvent(const sp<SyncEvent>& event);
                     virtual bool     isValidSyncEvent(const sp<SyncEvent>& event);
+                            void     invalidateTracks(audio_stream_type_t streamType);
+
 
     protected:
         int16_t*                        mMixBuffer;
-        uint32_t                        mSuspended;     // suspend count, > 0 means suspended
+
+        // suspend count, > 0 means suspended.  While suspended, the thread continues to pull from
+        // tracks and mix, but doesn't write to HAL.  A2DP and SCO HAL implementations can't handle
+        // concurrent use of both of them, so Audio Policy Service suspends one of the threads to
+        // workaround that restriction.
+        // 'volatile' means accessed via atomic operations and no lock.
+        volatile int32_t                mSuspended;
+
         int                             mBytesWritten;
     private:
         // mMasterMute is in both PlaybackThread and in AudioFlinger.  When a
@@ -1069,13 +1115,14 @@
 
         void        readOutputParameters();
 
-        virtual status_t    dumpInternals(int fd, const Vector<String16>& args);
-        status_t    dumpTracks(int fd, const Vector<String16>& args);
+        virtual void dumpInternals(int fd, const Vector<String16>& args);
+        void        dumpTracks(int fd, const Vector<String16>& args);
 
         SortedVector< sp<Track> >       mTracks;
         // mStreamTypes[] uses 1 additional stream type internally for the OutputTrack used by DuplicatingThread
         stream_type_t                   mStreamTypes[AUDIO_STREAM_CNT + 1];
         AudioStreamOut                  *mOutput;
+
         float                           mMasterVolume;
         nsecs_t                         mLastWriteTime;
         int                             mNumWrites;
@@ -1100,7 +1147,6 @@
 
         // FIXME move these declarations into the specific sub-class that needs them
         // MIXER only
-        bool                            longStandbyExit;
         uint32_t                        sleepTimeShift;
 
         // same as AudioFlinger::mStandbyTimeInNsecs except for DIRECT which uses a shorter value
@@ -1139,15 +1185,14 @@
         MixerThread (const sp<AudioFlinger>& audioFlinger,
                      AudioStreamOut* output,
                      audio_io_handle_t id,
-                     uint32_t device,
+                     audio_devices_t device,
                      type_t type = MIXER);
         virtual             ~MixerThread();
 
         // Thread virtuals
 
-                    void        invalidateTracks(audio_stream_type_t streamType);
         virtual     bool        checkForNewParameters_l();
-        virtual     status_t    dumpInternals(int fd, const Vector<String16>& args);
+        virtual     void        dumpInternals(int fd, const Vector<String16>& args);
 
     protected:
         virtual     mixer_state prepareTracks_l(Vector< sp<Track> > *tracksToRemove);
@@ -1167,9 +1212,6 @@
 
                     AudioMixer* mAudioMixer;    // normal mixer
     private:
-#ifdef SOAKER
-                    Thread*     mSoaker;
-#endif
                     // one-time initialization, no locks required
                     FastMixer*  mFastMixer;         // non-NULL if there is also a fast mixer
                     sp<AudioWatchdog> mAudioWatchdog; // non-0 if there is an audio watchdog thread
@@ -1198,7 +1240,7 @@
     public:
 
         DirectOutputThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
-                            audio_io_handle_t id, uint32_t device);
+                            audio_io_handle_t id, audio_devices_t device);
         virtual                 ~DirectOutputThread();
 
         // Thread virtuals
@@ -1287,7 +1329,7 @@
                                      bool reRegister);
               // return thread associated with primary hardware device, or NULL
               PlaybackThread *primaryPlaybackThread_l() const;
-              uint32_t primaryOutputDevice_l() const;
+              audio_devices_t primaryOutputDevice_l() const;
 
               sp<PlaybackThread> getEffectThread_l(int sessionId, int EffectId);
 
@@ -1331,18 +1373,22 @@
                                         const sp<Client>& client,
                                         uint32_t sampleRate,
                                         audio_format_t format,
-                                        uint32_t channelMask,
+                                        audio_channel_mask_t channelMask,
                                         int frameCount,
                                         int sessionId);
             virtual             ~RecordTrack();
 
-            virtual status_t    start(AudioSystem::sync_event_t event = AudioSystem::SYNC_EVENT_NONE,
-                                     int triggerSession = 0);
+            virtual status_t    start(AudioSystem::sync_event_t event, int triggerSession);
             virtual void        stop();
 
-                    bool        overflow() { bool tmp = mOverflow; mOverflow = false; return tmp; }
+                    void        destroy();
+
+                    // clear the buffer overflow flag
+                    void        clearOverflow() { mOverflow = false; }
+                    // set the buffer overflow flag and return previous value
                     bool        setOverflow() { bool tmp = mOverflow; mOverflow = true; return tmp; }
 
+            static  void        appendDumpHeader(String8& result);
                     void        dump(char* buffer, size_t size);
 
         private:
@@ -1355,18 +1401,24 @@
             virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer, int64_t pts = kInvalidPTS);
             // releaseBuffer() not overridden
 
-            bool                mOverflow;
+            bool                mOverflow;  // overflow on most recent attempt to fill client buffer
         };
 
-
                 RecordThread(const sp<AudioFlinger>& audioFlinger,
                         AudioStreamIn *input,
                         uint32_t sampleRate,
-                        uint32_t channels,
+                        audio_channel_mask_t channelMask,
                         audio_io_handle_t id,
-                        uint32_t device);
+                        audio_devices_t device);
                 virtual     ~RecordThread();
 
+        // no addTrack_l ?
+        void        destroyTrack_l(const sp<RecordTrack>& track);
+        void        removeTrack_l(const sp<RecordTrack>& track);
+
+        void        dumpInternals(int fd, const Vector<String16>& args);
+        void        dumpTracks(int fd, const Vector<String16>& args);
+
         // Thread
         virtual bool        threadLoop();
         virtual status_t    readyToRun();
@@ -1379,17 +1431,22 @@
                         const sp<AudioFlinger::Client>& client,
                         uint32_t sampleRate,
                         audio_format_t format,
-                        int channelMask,
+                        audio_channel_mask_t channelMask,
                         int frameCount,
                         int sessionId,
+                        IAudioFlinger::track_flags_t flags,
+                        pid_t tid,
                         status_t *status);
 
                 status_t    start(RecordTrack* recordTrack,
                                   AudioSystem::sync_event_t event,
                                   int triggerSession);
-                void        stop(RecordTrack* recordTrack);
-                status_t    dump(int fd, const Vector<String16>& args);
-                AudioStreamIn* getInput() const;
+
+                // ask the thread to stop the specified track, and
+                // return true if the caller should then do it's part of the stopping process
+                bool        stop_l(RecordTrack* recordTrack);
+
+                void        dump(int fd, const Vector<String16>& args);
                 AudioStreamIn* clearInput();
                 virtual audio_stream_t* stream() const;
 
@@ -1406,7 +1463,11 @@
         virtual status_t addEffectChain_l(const sp<EffectChain>& chain);
         virtual size_t removeEffectChain_l(const sp<EffectChain>& chain);
         virtual uint32_t hasAudioSession(int sessionId);
-                RecordTrack* track();
+
+                // Return the set of unique session IDs across all tracks.
+                // The keys are the session IDs, and the associated values are meaningless.
+                // FIXME replace by Set [and implement Bag/Multiset for other uses].
+                KeyedVector<int, bool> sessionIds();
 
         virtual status_t setSyncEvent(const sp<SyncEvent>& event);
         virtual bool     isValidSyncEvent(const sp<SyncEvent>& event);
@@ -1417,9 +1478,16 @@
     private:
                 void clearSyncStartEvent();
 
-                RecordThread();
+                // Enter standby if not already in standby, and set mStandby flag
+                void standby();
+
+                // Call the HAL standby method unconditionally, and don't change mStandby flag
+                void inputStandBy();
+
                 AudioStreamIn                       *mInput;
-                RecordTrack*                        mTrack;
+                SortedVector < sp<RecordTrack> >    mTracks;
+                // mActiveTrack has dual roles:  it indicates the current active track, and
+                // is used together with mStartStopCond to indicate start()/stop() progress
                 sp<RecordTrack>                     mActiveTrack;
                 Condition                           mStartStopCond;
                 AudioResampler                      *mResampler;
@@ -1445,12 +1513,15 @@
         RecordHandle(const sp<RecordThread::RecordTrack>& recordTrack);
         virtual             ~RecordHandle();
         virtual sp<IMemory> getCblk() const;
-        virtual status_t    start(int event, int triggerSession);
+        virtual status_t    start(int /*AudioSystem::sync_event_t*/ event, int triggerSession);
         virtual void        stop();
         virtual status_t onTransact(
             uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
     private:
         const sp<RecordThread::RecordTrack> mRecordTrack;
+
+        // for use from destructor
+        void                stop_nonvirtual();
     };
 
     //--- Audio Effect Management
@@ -1510,6 +1581,7 @@
             return mSessionId;
         }
         status_t    setEnabled(bool enabled);
+        status_t    setEnabled_l(bool enabled);
         bool isEnabled() const;
         bool isProcessEnabled() const;
 
@@ -1521,14 +1593,14 @@
         void        setThread(const wp<ThreadBase>& thread) { mThread = thread; }
         const wp<ThreadBase>& thread() { return mThread; }
 
-        status_t addHandle(const sp<EffectHandle>& handle);
-        void disconnect(const wp<EffectHandle>& handle, bool unpinIfLast);
-        size_t removeHandle (const wp<EffectHandle>& handle);
+        status_t addHandle(EffectHandle *handle);
+        size_t disconnect(EffectHandle *handle, bool unpinIfLast);
+        size_t removeHandle(EffectHandle *handle);
 
-        effect_descriptor_t& desc() { return mDescriptor; }
+        const effect_descriptor_t& desc() const { return mDescriptor; }
         wp<EffectChain>&     chain() { return mChain; }
 
-        status_t         setDevice(uint32_t device);
+        status_t         setDevice(audio_devices_t device);
         status_t         setVolume(uint32_t *left, uint32_t *right, bool controller);
         status_t         setMode(audio_mode_t mode);
         status_t         start();
@@ -1536,12 +1608,15 @@
         void             setSuspended(bool suspended);
         bool             suspended() const;
 
-        sp<EffectHandle> controlHandle();
+        EffectHandle*    controlHandle_l();
 
         bool             isPinned() const { return mPinned; }
         void             unPin() { mPinned = false; }
+        bool             purgeHandles();
+        void             lock() { mLock.lock(); }
+        void             unlock() { mLock.unlock(); }
 
-        status_t         dump(int fd, const Vector<String16>& args);
+        void             dump(int fd, const Vector<String16>& args);
 
     protected:
         friend class AudioFlinger;      // for mHandles
@@ -1559,14 +1634,14 @@
 mutable Mutex               mLock;      // mutex for process, commands and handles list protection
         wp<ThreadBase>      mThread;    // parent thread
         wp<EffectChain>     mChain;     // parent effect chain
-        int                 mId;        // this instance unique ID
-        int                 mSessionId; // audio session ID
-        effect_descriptor_t mDescriptor;// effect descriptor received from effect engine
+        const int           mId;        // this instance unique ID
+        const int           mSessionId; // audio session ID
+        const effect_descriptor_t mDescriptor;// effect descriptor received from effect engine
         effect_config_t     mConfig;    // input and output audio configuration
         effect_handle_t  mEffectInterface; // Effect module C API
         status_t            mStatus;    // initialization status
         effect_state        mState;     // current activation state
-        Vector< wp<EffectHandle> > mHandles;    // list of client handles
+        Vector<EffectHandle *> mHandles;    // list of client handles
                     // First handle in mHandles has highest priority and controls the effect module
         uint32_t mMaxDisableWaitCnt;    // maximum grace period before forcing an effect off after
                                         // sending disable command.
@@ -1624,6 +1699,8 @@
         int priority() const { return mPriority; }
         bool hasControl() const { return mHasControl; }
         sp<EffectModule> effect() const { return mEffect; }
+        // destroyed_l() must be called with the associated EffectModule mLock held
+        bool destroyed_l() const { return mDestroyed; }
 
         void dump(char* buffer, size_t size);
 
@@ -1642,6 +1719,8 @@
         bool mHasControl;                   // true if this handle is controlling the effect
         bool mEnabled;                      // cached enable state: needed when the effect is
                                             // restored after being suspended
+        bool mDestroyed;                    // Set to true by destructor. Access with EffectModule
+                                            // mLock held
     };
 
     // the EffectChain class represents a group of effects associated to one audio session.
@@ -1684,7 +1763,7 @@
         sp<EffectModule> getEffectFromId_l(int id);
         sp<EffectModule> getEffectFromType_l(const effect_uuid_t *type);
         bool setVolume_l(uint32_t *left, uint32_t *right);
-        void setDevice_l(uint32_t device);
+        void setDevice_l(audio_devices_t device);
         void setMode_l(audio_mode_t mode);
 
         void setInBuffer(int16_t *buffer, bool ownsBuffer = false) {
@@ -1703,12 +1782,12 @@
 
         void incTrackCnt() { android_atomic_inc(&mTrackCnt); }
         void decTrackCnt() { android_atomic_dec(&mTrackCnt); }
-        int32_t trackCnt() const { return mTrackCnt;}
+        int32_t trackCnt() const { return android_atomic_acquire_load(&mTrackCnt); }
 
         void incActiveTrackCnt() { android_atomic_inc(&mActiveTrackCnt);
                                    mTailBufferCount = mMaxTailBuffers; }
         void decActiveTrackCnt() { android_atomic_dec(&mActiveTrackCnt); }
-        int32_t activeTrackCnt() const { return mActiveTrackCnt;}
+        int32_t activeTrackCnt() const { return android_atomic_acquire_load(&mActiveTrackCnt); }
 
         uint32_t strategy() const { return mStrategy; }
         void setStrategy(uint32_t strategy)
@@ -1725,7 +1804,7 @@
 
         void clearInputBuffer();
 
-        status_t dump(int fd, const Vector<String16>& args);
+        void dump(int fd, const Vector<String16>& args);
 
     protected:
         friend class AudioFlinger;  // for mThread, mEffects
@@ -1760,8 +1839,11 @@
         int mSessionId;             // audio session ID
         int16_t *mInBuffer;         // chain input buffer
         int16_t *mOutBuffer;        // chain output buffer
-        volatile int32_t mActiveTrackCnt;  // number of active tracks connected
-        volatile int32_t mTrackCnt;        // number of tracks connected
+
+        // 'volatile' here means these are accessed with atomic operations instead of mutex
+        volatile int32_t mActiveTrackCnt;    // number of active tracks connected
+        volatile int32_t mTrackCnt;          // number of tracks connected
+
         int32_t mTailBufferCount;   // current effect tail buffer count
         int32_t mMaxTailBuffers;    // maximum effect tail buffers
         bool mOwnInBuffer;          // true if the chain owns its input buffer
@@ -1833,7 +1915,7 @@
     public:
         AudioHwDevice(const char *moduleName, audio_hw_device_t *hwDevice) :
             mModuleName(strdup(moduleName)), mHwDevice(hwDevice){}
-        ~AudioHwDevice() { free((void *)mModuleName); }
+        /*virtual*/ ~AudioHwDevice() { free((void *)mModuleName); }
 
         const char *moduleName() const { return mModuleName; }
         audio_hw_device_t *hwDevice() const { return mHwDevice; }
@@ -1910,6 +1992,9 @@
 private:
     sp<Client>  registerPid_l(pid_t pid);    // always returns non-0
 
+    // for use from destructor
+    status_t    closeOutput_nonvirtual(audio_io_handle_t output);
+    status_t    closeInput_nonvirtual(audio_io_handle_t input);
 };
 
 
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index 0c8b3ce..3a8c54d 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -412,7 +412,7 @@
     case TRACK:
         switch (param) {
         case CHANNEL_MASK: {
-            uint32_t mask = (uint32_t)value;
+            audio_channel_mask_t mask = (audio_channel_mask_t) value;
             if (track.channelMask != mask) {
                 uint32_t channelCount = popcount(mask);
                 ALOG_ASSERT((channelCount <= MAX_NUM_CHANNELS_TO_DOWNMIX) && channelCount);
diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp
index 0d13970..3a2dbe2 100644
--- a/services/audioflinger/AudioPolicyService.cpp
+++ b/services/audioflinger/AudioPolicyService.cpp
@@ -223,7 +223,7 @@
 audio_io_handle_t AudioPolicyService::getOutput(audio_stream_type_t stream,
                                     uint32_t samplingRate,
                                     audio_format_t format,
-                                    uint32_t channels,
+                                    audio_channel_mask_t channelMask,
                                     audio_output_flags_t flags)
 {
     if (mpAudioPolicy == NULL) {
@@ -231,7 +231,7 @@
     }
     ALOGV("getOutput() tid %d", gettid());
     Mutex::Autolock _l(mLock);
-    return mpAudioPolicy->get_output(mpAudioPolicy, stream, samplingRate, format, channels, flags);
+    return mpAudioPolicy->get_output(mpAudioPolicy, stream, samplingRate, format, channelMask, flags);
 }
 
 status_t AudioPolicyService::startOutput(audio_io_handle_t output,
@@ -271,8 +271,7 @@
 audio_io_handle_t AudioPolicyService::getInput(audio_source_t inputSource,
                                     uint32_t samplingRate,
                                     audio_format_t format,
-                                    uint32_t channels,
-                                    audio_in_acoustics_t acoustics,
+                                    audio_channel_mask_t channelMask,
                                     int audioSession)
 {
     if (mpAudioPolicy == NULL) {
@@ -283,8 +282,9 @@
         return 0;
     }
     Mutex::Autolock _l(mLock);
+    // the audio_in_acoustics_t parameter is ignored by get_input()
     audio_io_handle_t input = mpAudioPolicy->get_input(mpAudioPolicy, inputSource, samplingRate,
-                                                       format, channels, acoustics);
+                                                       format, channelMask, (audio_in_acoustics_t) 0);
 
     if (input == 0) {
         return input;
@@ -373,6 +373,7 @@
     if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
         return BAD_VALUE;
     }
+    Mutex::Autolock _l(mLock);
     mpAudioPolicy->init_stream_volume(mpAudioPolicy, stream, indexMin, indexMax);
     return NO_ERROR;
 }
@@ -390,7 +391,7 @@
     if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
         return BAD_VALUE;
     }
-
+    Mutex::Autolock _l(mLock);
     if (mpAudioPolicy->set_stream_volume_index_for_device) {
         return mpAudioPolicy->set_stream_volume_index_for_device(mpAudioPolicy,
                                                                 stream,
@@ -411,6 +412,7 @@
     if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
         return BAD_VALUE;
     }
+    Mutex::Autolock _l(mLock);
     if (mpAudioPolicy->get_stream_volume_index_for_device) {
         return mpAudioPolicy->get_stream_volume_index_for_device(mpAudioPolicy,
                                                                 stream,
@@ -439,7 +441,7 @@
     return mpAudioPolicy->get_devices_for_stream(mpAudioPolicy, stream);
 }
 
-audio_io_handle_t AudioPolicyService::getOutputForEffect(effect_descriptor_t *desc)
+audio_io_handle_t AudioPolicyService::getOutputForEffect(const effect_descriptor_t *desc)
 {
     if (mpAudioPolicy == NULL) {
         return NO_INIT;
@@ -448,7 +450,7 @@
     return mpAudioPolicy->get_output_for_effect(mpAudioPolicy, desc);
 }
 
-status_t AudioPolicyService::registerEffect(effect_descriptor_t *desc,
+status_t AudioPolicyService::registerEffect(const effect_descriptor_t *desc,
                                 audio_io_handle_t io,
                                 uint32_t strategy,
                                 int session,
@@ -512,7 +514,7 @@
     for (size_t i = 0; i < effects.size(); i++) {
         effect_descriptor_t desc = effects[i]->descriptor();
         if (i < *count) {
-            memcpy(descriptors + i, &desc, sizeof(effect_descriptor_t));
+            descriptors[i] = desc;
         }
     }
     if (effects.size() > *count) {
@@ -778,7 +780,6 @@
     data->mType = type;
     data->mStream = stream;
     command->mParam = (void *)data;
-    command->mWaitStatus = false;
     Mutex::Autolock _l(mLock);
     insertCommand_l(command);
     ALOGV("AudioCommandThread() adding tone start type %d, stream %d", type, stream);
@@ -790,7 +791,6 @@
     AudioCommand *command = new AudioCommand();
     command->mCommand = STOP_TONE;
     command->mParam = NULL;
-    command->mWaitStatus = false;
     Mutex::Autolock _l(mLock);
     insertCommand_l(command);
     ALOGV("AudioCommandThread() adding tone stop");
@@ -811,11 +811,6 @@
     data->mVolume = volume;
     data->mIO = output;
     command->mParam = data;
-    if (delayMs == 0) {
-        command->mWaitStatus = true;
-    } else {
-        command->mWaitStatus = false;
-    }
     Mutex::Autolock _l(mLock);
     insertCommand_l(command, delayMs);
     ALOGV("AudioCommandThread() adding set volume stream %d, volume %f, output %d",
@@ -841,11 +836,6 @@
     data->mIO = ioHandle;
     data->mKeyValuePairs = String8(keyValuePairs);
     command->mParam = data;
-    if (delayMs == 0) {
-        command->mWaitStatus = true;
-    } else {
-        command->mWaitStatus = false;
-    }
     Mutex::Autolock _l(mLock);
     insertCommand_l(command, delayMs);
     ALOGV("AudioCommandThread() adding set parameter string %s, io %d ,delay %d",
@@ -868,11 +858,6 @@
     VoiceVolumeData *data = new VoiceVolumeData();
     data->mVolume = volume;
     command->mParam = data;
-    if (delayMs == 0) {
-        command->mWaitStatus = true;
-    } else {
-        command->mWaitStatus = false;
-    }
     Mutex::Autolock _l(mLock);
     insertCommand_l(command, delayMs);
     ALOGV("AudioCommandThread() adding set voice volume volume %f", volume);
@@ -891,6 +876,7 @@
     ssize_t i;  // not size_t because i will count down to -1
     Vector <AudioCommand *> removedCommands;
 
+    nsecs_t time = 0;
     command->mTime = systemTime() + milliseconds(delayMs);
 
     // acquire wake lock to make sure delayed commands are processed
@@ -936,6 +922,7 @@
             } else {
                 data2->mKeyValuePairs = param2.toString();
             }
+            time = command2->mTime;
         } break;
 
         case SET_VOLUME: {
@@ -946,6 +933,7 @@
             ALOGV("Filtering out volume command on output %d for stream %d",
                     data->mIO, data->mStream);
             removedCommands.add(command2);
+            time = command2->mTime;
         } break;
         case START_TONE:
         case STOP_TONE:
@@ -967,6 +955,17 @@
     }
     removedCommands.clear();
 
+    // wait for status only if delay is 0 and command time was not modified above
+    if (delayMs == 0 && time == 0) {
+        command->mWaitStatus = true;
+    } else {
+        command->mWaitStatus = false;
+    }
+    // update command time if modified above
+    if (time != 0) {
+        command->mTime = time;
+    }
+
     // insert command at the right place according to its time stamp
     ALOGV("inserting command: %d at index %d, num commands %d",
             command->mCommand, (int)i+1, mAudioCommands.size());
@@ -1422,7 +1421,7 @@
     return af->restoreOutput(output);
 }
 
-// deprecated: replaced by aps_open_input_on_module()
+// deprecated: replaced by aps_open_input_on_module(), and acoustics parameter is ignored
 static audio_io_handle_t aps_open_input(void *service,
                                         audio_devices_t *pDevices,
                                         uint32_t *pSamplingRate,
diff --git a/services/audioflinger/AudioPolicyService.h b/services/audioflinger/AudioPolicyService.h
index fbca000..a086734 100644
--- a/services/audioflinger/AudioPolicyService.h
+++ b/services/audioflinger/AudioPolicyService.h
@@ -64,7 +64,7 @@
     virtual audio_io_handle_t getOutput(audio_stream_type_t stream,
                                         uint32_t samplingRate = 0,
                                         audio_format_t format = AUDIO_FORMAT_DEFAULT,
-                                        uint32_t channels = 0,
+                                        audio_channel_mask_t channelMask = 0,
                                         audio_output_flags_t flags =
                                                 AUDIO_OUTPUT_FLAG_NONE);
     virtual status_t startOutput(audio_io_handle_t output,
@@ -77,9 +77,7 @@
     virtual audio_io_handle_t getInput(audio_source_t inputSource,
                                     uint32_t samplingRate = 0,
                                     audio_format_t format = AUDIO_FORMAT_DEFAULT,
-                                    uint32_t channels = 0,
-                                    audio_in_acoustics_t acoustics =
-                                            (audio_in_acoustics_t)0 /*AUDIO_IN_ACOUSTICS_NONE*/,
+                                    audio_channel_mask_t channelMask = 0,
                                     int audioSession = 0);
     virtual status_t startInput(audio_io_handle_t input);
     virtual status_t stopInput(audio_io_handle_t input);
@@ -97,8 +95,8 @@
     virtual uint32_t getStrategyForStream(audio_stream_type_t stream);
     virtual audio_devices_t getDevicesForStream(audio_stream_type_t stream);
 
-    virtual audio_io_handle_t getOutputForEffect(effect_descriptor_t *desc);
-    virtual status_t registerEffect(effect_descriptor_t *desc,
+    virtual audio_io_handle_t getOutputForEffect(const effect_descriptor_t *desc);
+    virtual status_t registerEffect(const effect_descriptor_t *desc,
                                     audio_io_handle_t io,
                                     uint32_t strategy,
                                     int session,
diff --git a/services/audioflinger/Soaker.h b/services/audioflinger/Soaker.h
deleted file mode 100644
index 43d9d2f..0000000
--- a/services/audioflinger/Soaker.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _ANDROID_AUDIO_SOAKER_H
-#define _ANDROID_AUDIO_SOAKER_H
-
-#include <utils/Thread.h>
-
-namespace android {
-
-class Soaker : public Thread {
-public:
-    Soaker() : Thread() { }
-    virtual ~Soaker() { }
-protected:
-    virtual bool threadLoop() {
-        int j = 0;
-        for (;;) {
-            for (int i = 0; i < 10000; ++i) {
-                j += i * i;
-            }
-            if (exitPending()) {
-                return false;
-            }
-        }
-        return j < 555555;
-    }
-};
-
-}   // namespace android
-
-#endif  // _ANDROID_AUDIO_SOAKER_H
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index 3cae1f5..c14ae22 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -7,7 +7,11 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=               \
-    CameraService.cpp
+    CameraService.cpp \
+    CameraClient.cpp \
+    Camera2Client.cpp \
+    Camera2Device.cpp \
+    MediaConsumer.cpp
 
 LOCAL_SHARED_LIBRARIES:= \
     libui \
@@ -18,7 +22,12 @@
     libmedia_native \
     libcamera_client \
     libgui \
-    libhardware
+    libhardware \
+    libsync \
+    libcamera_metadata
+
+LOCAL_C_INCLUDES += \
+    system/media/camera/include
 
 LOCAL_MODULE:= libcameraservice
 
diff --git a/services/camera/libcameraservice/Camera2Client.cpp b/services/camera/libcameraservice/Camera2Client.cpp
new file mode 100644
index 0000000..62741d5
--- /dev/null
+++ b/services/camera/libcameraservice/Camera2Client.cpp
@@ -0,0 +1,3165 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Camera2Client"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+
+#include <cutils/properties.h>
+#include <gui/SurfaceTextureClient.h>
+#include <gui/Surface.h>
+#include <media/hardware/MetadataBufferType.h>
+
+#include <math.h>
+
+#include "Camera2Client.h"
+
+namespace android {
+
+#define ALOG1(...) ALOGD_IF(gLogLevel >= 1, __VA_ARGS__);
+#define ALOG2(...) ALOGD_IF(gLogLevel >= 2, __VA_ARGS__);
+
+static int getCallingPid() {
+    return IPCThreadState::self()->getCallingPid();
+}
+
+static int getCallingUid() {
+    return IPCThreadState::self()->getCallingUid();
+}
+
+// Interface used by CameraService
+
+Camera2Client::Camera2Client(const sp<CameraService>& cameraService,
+        const sp<ICameraClient>& cameraClient,
+        int cameraId,
+        int cameraFacing,
+        int clientPid):
+        Client(cameraService, cameraClient,
+                cameraId, cameraFacing, clientPid),
+        mState(NOT_INITIALIZED),
+        mPreviewStreamId(NO_STREAM),
+        mPreviewRequest(NULL),
+        mCaptureStreamId(NO_STREAM),
+        mCaptureRequest(NULL),
+        mRecordingStreamId(NO_STREAM),
+        mRecordingRequest(NULL)
+{
+    ATRACE_CALL();
+
+    mDevice = new Camera2Device(cameraId);
+}
+
+status_t Camera2Client::initialize(camera_module_t *module)
+{
+    ATRACE_CALL();
+    ALOGV("%s: E", __FUNCTION__);
+    status_t res;
+
+    res = mDevice->initialize(module);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",
+                __FUNCTION__, mCameraId, strerror(-res), res);
+        return NO_INIT;
+    }
+
+    res = buildDefaultParameters();
+    if (res != OK) {
+        ALOGE("%s: Camera %d: unable to build defaults: %s (%d)",
+                __FUNCTION__, mCameraId, strerror(-res), res);
+        return NO_INIT;
+    }
+
+    if (gLogLevel >= 1) {
+        LockedParameters::Key k(mParameters);
+        ALOGD("%s: Default parameters converted from camera %d:", __FUNCTION__,
+              mCameraId);
+        ALOGD("%s", k.mParameters.paramsFlattened.string());
+    }
+
+    mState = STOPPED;
+
+    return OK;
+}
+
+Camera2Client::~Camera2Client() {
+    ATRACE_CALL();
+    ALOGV("%s: Camera %d: Shutting down", __FUNCTION__, mCameraId);
+
+    mDestructionStarted = true;
+
+    disconnect();
+
+}
+
+status_t Camera2Client::dump(int fd, const Vector<String16>& args) {
+    String8 result;
+    result.appendFormat("Client2[%d] (%p) PID: %d, dump:\n",
+            mCameraId,
+            getCameraClient()->asBinder().get(),
+            mClientPid);
+    result.append("  State: ");
+#define CASE_APPEND_ENUM(x) case x: result.append(#x "\n"); break;
+
+    const Parameters& p = mParameters.unsafeUnlock();
+
+    result.append(getStateName(mState));
+
+    result.append("\n  Current parameters:\n");
+    result.appendFormat("    Preview size: %d x %d\n",
+            p.previewWidth, p.previewHeight);
+    result.appendFormat("    Preview FPS range: %d - %d\n",
+            p.previewFpsRange[0], p.previewFpsRange[1]);
+    result.appendFormat("    Preview HAL pixel format: 0x%x\n",
+            p.previewFormat);
+    result.appendFormat("    Preview transform: %x\n",
+            p.previewTransform);
+    result.appendFormat("    Picture size: %d x %d\n",
+            p.pictureWidth, p.pictureHeight);
+    result.appendFormat("    Jpeg thumbnail size: %d x %d\n",
+            p.jpegThumbSize[0], p.jpegThumbSize[1]);
+    result.appendFormat("    Jpeg quality: %d, thumbnail quality: %d\n",
+            p.jpegQuality, p.jpegThumbQuality);
+    result.appendFormat("    Jpeg rotation: %d\n", p.jpegRotation);
+    result.appendFormat("    GPS tags %s\n",
+            p.gpsEnabled ? "enabled" : "disabled");
+    if (p.gpsEnabled) {
+        result.appendFormat("    GPS lat x long x alt: %f x %f x %f\n",
+                p.gpsCoordinates[0], p.gpsCoordinates[1],
+                p.gpsCoordinates[2]);
+        result.appendFormat("    GPS timestamp: %lld\n",
+                p.gpsTimestamp);
+        result.appendFormat("    GPS processing method: %s\n",
+                p.gpsProcessingMethod.string());
+    }
+
+    result.append("    White balance mode: ");
+    switch (p.wbMode) {
+        CASE_APPEND_ENUM(ANDROID_CONTROL_AWB_AUTO)
+        CASE_APPEND_ENUM(ANDROID_CONTROL_AWB_INCANDESCENT)
+        CASE_APPEND_ENUM(ANDROID_CONTROL_AWB_FLUORESCENT)
+        CASE_APPEND_ENUM(ANDROID_CONTROL_AWB_WARM_FLUORESCENT)
+        CASE_APPEND_ENUM(ANDROID_CONTROL_AWB_DAYLIGHT)
+        CASE_APPEND_ENUM(ANDROID_CONTROL_AWB_CLOUDY_DAYLIGHT)
+        CASE_APPEND_ENUM(ANDROID_CONTROL_AWB_TWILIGHT)
+        CASE_APPEND_ENUM(ANDROID_CONTROL_AWB_SHADE)
+        default: result.append("UNKNOWN\n");
+    }
+
+    result.append("    Effect mode: ");
+    switch (p.effectMode) {
+        CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_OFF)
+        CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_MONO)
+        CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_NEGATIVE)
+        CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_SOLARIZE)
+        CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_SEPIA)
+        CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_POSTERIZE)
+        CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_WHITEBOARD)
+        CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_BLACKBOARD)
+        CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_AQUA)
+        default: result.append("UNKNOWN\n");
+    }
+
+    result.append("    Antibanding mode: ");
+    switch (p.antibandingMode) {
+        CASE_APPEND_ENUM(ANDROID_CONTROL_AE_ANTIBANDING_AUTO)
+        CASE_APPEND_ENUM(ANDROID_CONTROL_AE_ANTIBANDING_OFF)
+        CASE_APPEND_ENUM(ANDROID_CONTROL_AE_ANTIBANDING_50HZ)
+        CASE_APPEND_ENUM(ANDROID_CONTROL_AE_ANTIBANDING_60HZ)
+        default: result.append("UNKNOWN\n");
+    }
+
+    result.append("    Scene mode: ");
+    switch (p.sceneMode) {
+        case ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED:
+            result.append("AUTO\n"); break;
+        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_ACTION)
+        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_PORTRAIT)
+        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_LANDSCAPE)
+        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_NIGHT)
+        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_NIGHT_PORTRAIT)
+        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_THEATRE)
+        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_BEACH)
+        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_SNOW)
+        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_SUNSET)
+        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_STEADYPHOTO)
+        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_FIREWORKS)
+        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_SPORTS)
+        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_PARTY)
+        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_CANDLELIGHT)
+        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_BARCODE)
+        default: result.append("UNKNOWN\n");
+    }
+
+    result.append("    Flash mode: ");
+    switch (p.flashMode) {
+        CASE_APPEND_ENUM(Parameters::FLASH_MODE_OFF)
+        CASE_APPEND_ENUM(Parameters::FLASH_MODE_AUTO)
+        CASE_APPEND_ENUM(Parameters::FLASH_MODE_ON)
+        CASE_APPEND_ENUM(Parameters::FLASH_MODE_TORCH)
+        CASE_APPEND_ENUM(Parameters::FLASH_MODE_RED_EYE)
+        CASE_APPEND_ENUM(Parameters::FLASH_MODE_INVALID)
+        default: result.append("UNKNOWN\n");
+    }
+
+    result.append("    Focus mode: ");
+    switch (p.focusMode) {
+        CASE_APPEND_ENUM(Parameters::FOCUS_MODE_AUTO)
+        CASE_APPEND_ENUM(Parameters::FOCUS_MODE_MACRO)
+        CASE_APPEND_ENUM(Parameters::FOCUS_MODE_CONTINUOUS_VIDEO)
+        CASE_APPEND_ENUM(Parameters::FOCUS_MODE_CONTINUOUS_PICTURE)
+        CASE_APPEND_ENUM(Parameters::FOCUS_MODE_EDOF)
+        CASE_APPEND_ENUM(Parameters::FOCUS_MODE_INFINITY)
+        CASE_APPEND_ENUM(Parameters::FOCUS_MODE_FIXED)
+        CASE_APPEND_ENUM(Parameters::FOCUS_MODE_INVALID)
+        default: result.append("UNKNOWN\n");
+    }
+
+    result.append("    Focusing areas:\n");
+    for (size_t i = 0; i < p.focusingAreas.size(); i++) {
+        result.appendFormat("      [ (%d, %d, %d, %d), weight %d ]\n",
+                p.focusingAreas[i].left,
+                p.focusingAreas[i].top,
+                p.focusingAreas[i].right,
+                p.focusingAreas[i].bottom,
+                p.focusingAreas[i].weight);
+    }
+
+    result.appendFormat("    Exposure compensation index: %d\n",
+            p.exposureCompensation);
+
+    result.appendFormat("    AE lock %s, AWB lock %s\n",
+            p.autoExposureLock ? "enabled" : "disabled",
+            p.autoWhiteBalanceLock ? "enabled" : "disabled" );
+
+    result.appendFormat("    Metering areas:\n");
+    for (size_t i = 0; i < p.meteringAreas.size(); i++) {
+        result.appendFormat("      [ (%d, %d, %d, %d), weight %d ]\n",
+                p.meteringAreas[i].left,
+                p.meteringAreas[i].top,
+                p.meteringAreas[i].right,
+                p.meteringAreas[i].bottom,
+                p.meteringAreas[i].weight);
+    }
+
+    result.appendFormat("    Zoom index: %d\n", p.zoom);
+    result.appendFormat("    Video size: %d x %d\n", p.videoWidth,
+            p.videoHeight);
+
+    result.appendFormat("    Recording hint is %s\n",
+            p.recordingHint ? "set" : "not set");
+
+    result.appendFormat("    Video stabilization is %s\n",
+            p.videoStabilization ? "enabled" : "disabled");
+
+    result.append("  Current streams:\n");
+    result.appendFormat("    Preview stream ID: %d\n", mPreviewStreamId);
+    result.appendFormat("    Capture stream ID: %d\n", mCaptureStreamId);
+    result.appendFormat("    Recording stream ID: %d\n", mRecordingStreamId);
+
+    result.append("  Current requests:\n");
+    if (mPreviewRequest != NULL) {
+        result.append("    Preview request:\n");
+        write(fd, result.string(), result.size());
+        dump_indented_camera_metadata(mPreviewRequest, fd, 2, 6);
+    } else {
+        result.append("    Preview request: undefined\n");
+        write(fd, result.string(), result.size());
+    }
+
+    if (mCaptureRequest != NULL) {
+        result = "    Capture request:\n";
+        write(fd, result.string(), result.size());
+        dump_indented_camera_metadata(mCaptureRequest, fd, 2, 6);
+    } else {
+        result = "    Capture request: undefined\n";
+        write(fd, result.string(), result.size());
+    }
+
+    if (mRecordingRequest != NULL) {
+        result = "    Recording request:\n";
+        write(fd, result.string(), result.size());
+        dump_indented_camera_metadata(mRecordingRequest, fd, 2, 6);
+    } else {
+        result = "    Recording request: undefined\n";
+        write(fd, result.string(), result.size());
+    }
+
+    result = "  Device dump:\n";
+    write(fd, result.string(), result.size());
+
+    status_t res = mDevice->dump(fd, args);
+    if (res != OK) {
+        result = String8::format("   Error dumping device: %s (%d)",
+                strerror(-res), res);
+        write(fd, result.string(), result.size());
+    }
+
+#undef CASE_APPEND_ENUM
+    return NO_ERROR;
+}
+
+const char* Camera2Client::getStateName(State state) {
+#define CASE_ENUM_TO_CHAR(x) case x: return(#x); break;
+    switch(state) {
+        CASE_ENUM_TO_CHAR(NOT_INITIALIZED)
+        CASE_ENUM_TO_CHAR(STOPPED)
+        CASE_ENUM_TO_CHAR(WAITING_FOR_PREVIEW_WINDOW)
+        CASE_ENUM_TO_CHAR(PREVIEW)
+        CASE_ENUM_TO_CHAR(RECORD)
+        CASE_ENUM_TO_CHAR(STILL_CAPTURE)
+        CASE_ENUM_TO_CHAR(VIDEO_SNAPSHOT)
+        default:
+            return "Unknown state!";
+            break;
+    }
+#undef CASE_ENUM_TO_CHAR
+}
+
+// ICamera interface
+
+void Camera2Client::disconnect() {
+    ATRACE_CALL();
+    ALOGV("%s: E", __FUNCTION__);
+    Mutex::Autolock icl(mICameraLock);
+
+    if (mDevice == 0) return;
+
+    stopPreviewLocked();
+
+    mDevice->waitUntilDrained();
+
+    if (mPreviewStreamId != NO_STREAM) {
+        mDevice->deleteStream(mPreviewStreamId);
+        mPreviewStreamId = NO_STREAM;
+    }
+
+    if (mCaptureStreamId != NO_STREAM) {
+        mDevice->deleteStream(mCaptureStreamId);
+        mCaptureStreamId = NO_STREAM;
+    }
+
+    if (mRecordingStreamId != NO_STREAM) {
+        mDevice->deleteStream(mRecordingStreamId);
+        mRecordingStreamId = NO_STREAM;
+    }
+
+    CameraService::Client::disconnect();
+}
+
+status_t Camera2Client::connect(const sp<ICameraClient>& client) {
+    ATRACE_CALL();
+    ALOGV("%s: E", __FUNCTION__);
+    Mutex::Autolock icl(mICameraLock);
+
+    if (mClientPid != 0 && getCallingPid() != mClientPid) {
+        ALOGE("%s: Camera %d: Connection attempt from pid %d; "
+                "current locked to pid %d", __FUNCTION__,
+                mCameraId, getCallingPid(), mClientPid);
+        return BAD_VALUE;
+    }
+
+    mClientPid = getCallingPid();
+    mCameraClient = client;
+
+    return OK;
+}
+
+status_t Camera2Client::lock() {
+    ATRACE_CALL();
+    ALOGV("%s: E", __FUNCTION__);
+    Mutex::Autolock icl(mICameraLock);
+    ALOGV("%s: Camera %d: Lock call from pid %d; current client pid %d",
+            __FUNCTION__, mCameraId, getCallingPid(), mClientPid);
+
+    if (mClientPid == 0) {
+        mClientPid = getCallingPid();
+        return OK;
+    }
+
+    if (mClientPid != getCallingPid()) {
+        ALOGE("%s: Camera %d: Lock call from pid %d; currently locked to pid %d",
+                __FUNCTION__, mCameraId, getCallingPid(), mClientPid);
+        return EBUSY;
+    }
+
+    return OK;
+}
+
+status_t Camera2Client::unlock() {
+    ATRACE_CALL();
+    ALOGV("%s: E", __FUNCTION__);
+    Mutex::Autolock icl(mICameraLock);
+    ALOGV("%s: Camera %d: Unlock call from pid %d; current client pid %d",
+            __FUNCTION__, mCameraId, getCallingPid(), mClientPid);
+
+    // TODO: Check for uninterruptable conditions
+
+    if (mClientPid == getCallingPid()) {
+        mClientPid = 0;
+        mCameraClient.clear();
+        return OK;
+    }
+
+    ALOGE("%s: Camera %d: Unlock call from pid %d; currently locked to pid %d",
+            __FUNCTION__, mCameraId, getCallingPid(), mClientPid);
+    return EBUSY;
+}
+
+status_t Camera2Client::setPreviewDisplay(
+        const sp<Surface>& surface) {
+    ATRACE_CALL();
+    ALOGV("%s: E", __FUNCTION__);
+    Mutex::Autolock icl(mICameraLock);
+
+    sp<IBinder> binder;
+    sp<ANativeWindow> window;
+    if (surface != 0) {
+        binder = surface->asBinder();
+        window = surface;
+    }
+
+    return setPreviewWindowLocked(binder,window);
+}
+
+status_t Camera2Client::setPreviewTexture(
+        const sp<ISurfaceTexture>& surfaceTexture) {
+    ATRACE_CALL();
+    ALOGV("%s: E", __FUNCTION__);
+    Mutex::Autolock icl(mICameraLock);
+
+    sp<IBinder> binder;
+    sp<ANativeWindow> window;
+    if (surfaceTexture != 0) {
+        binder = surfaceTexture->asBinder();
+        window = new SurfaceTextureClient(surfaceTexture);
+    }
+    return setPreviewWindowLocked(binder, window);
+}
+
+status_t Camera2Client::setPreviewWindowLocked(const sp<IBinder>& binder,
+        sp<ANativeWindow> window) {
+    ATRACE_CALL();
+    status_t res;
+
+    if (binder == mPreviewSurface) {
+        ALOGV("%s: Camera %d: New window is same as old window",
+                __FUNCTION__, mCameraId);
+        return NO_ERROR;
+    }
+
+    switch (mState) {
+        case NOT_INITIALIZED:
+        case RECORD:
+        case STILL_CAPTURE:
+        case VIDEO_SNAPSHOT:
+            ALOGE("%s: Camera %d: Cannot set preview display while in state %s",
+                    __FUNCTION__, mCameraId, getStateName(mState));
+            return INVALID_OPERATION;
+        case STOPPED:
+        case WAITING_FOR_PREVIEW_WINDOW:
+            // OK
+            break;
+        case PREVIEW:
+            // Already running preview - need to stop and create a new stream
+            // TODO: Optimize this so that we don't wait for old stream to drain
+            // before spinning up new stream
+            mDevice->setStreamingRequest(NULL);
+            mState = WAITING_FOR_PREVIEW_WINDOW;
+            break;
+    }
+
+    if (mPreviewStreamId != NO_STREAM) {
+        res = mDevice->waitUntilDrained();
+        if (res != OK) {
+            ALOGE("%s: Error waiting for preview to drain: %s (%d)",
+                    __FUNCTION__, strerror(-res), res);
+            return res;
+        }
+        res = mDevice->deleteStream(mPreviewStreamId);
+        if (res != OK) {
+            ALOGE("%s: Unable to delete old preview stream: %s (%d)",
+                    __FUNCTION__, strerror(-res), res);
+            return res;
+        }
+        mPreviewStreamId = NO_STREAM;
+    }
+
+    mPreviewSurface = binder;
+    mPreviewWindow = window;
+
+    if (mState == WAITING_FOR_PREVIEW_WINDOW) {
+        return startPreviewLocked();
+    }
+
+    return OK;
+}
+
+void Camera2Client::setPreviewCallbackFlag(int flag) {
+    ATRACE_CALL();
+    Mutex::Autolock icl(mICameraLock);
+}
+
+status_t Camera2Client::startPreview() {
+    ATRACE_CALL();
+    ALOGV("%s: E", __FUNCTION__);
+    Mutex::Autolock icl(mICameraLock);
+    return startPreviewLocked();
+}
+
+status_t Camera2Client::startPreviewLocked() {
+    ATRACE_CALL();
+    status_t res;
+    if (mState >= PREVIEW) {
+        ALOGE("%s: Can't start preview in state %s",
+                __FUNCTION__, getStateName(mState));
+        return INVALID_OPERATION;
+    }
+
+    if (mPreviewWindow == 0) {
+        mState = WAITING_FOR_PREVIEW_WINDOW;
+        return OK;
+    }
+    mState = STOPPED;
+
+    LockedParameters::Key k(mParameters);
+
+    res = updatePreviewStream(k.mParameters);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Unable to update preview stream: %s (%d)",
+                __FUNCTION__, mCameraId, strerror(-res), res);
+        return res;
+    }
+
+    if (mPreviewRequest == NULL) {
+        res = updatePreviewRequest(k.mParameters);
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Unable to create preview request: %s (%d)",
+                    __FUNCTION__, mCameraId, strerror(-res), res);
+            return res;
+        }
+    }
+
+    res = updateEntry(mPreviewRequest,
+            ANDROID_REQUEST_OUTPUT_STREAMS,
+            &mPreviewStreamId, 1);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Unable to set up preview request: %s (%d)",
+                __FUNCTION__, mCameraId, strerror(-res), res);
+        return res;
+    }
+    res = sort_camera_metadata(mPreviewRequest);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Error sorting preview request: %s (%d)",
+                __FUNCTION__, mCameraId, strerror(-res), res);
+        return res;
+    }
+
+    res = mDevice->setStreamingRequest(mPreviewRequest);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Unable to set preview request to start preview: "
+                "%s (%d)",
+                __FUNCTION__, mCameraId, strerror(-res), res);
+        return res;
+    }
+    mState = PREVIEW;
+
+    return OK;
+}
+
+void Camera2Client::stopPreview() {
+    ATRACE_CALL();
+    ALOGV("%s: E", __FUNCTION__);
+    Mutex::Autolock icl(mICameraLock);
+    stopPreviewLocked();
+}
+
+void Camera2Client::stopPreviewLocked() {
+    ATRACE_CALL();
+    switch (mState) {
+        case NOT_INITIALIZED:
+            ALOGE("%s: Camera %d: Call before initialized",
+                    __FUNCTION__, mCameraId);
+            break;
+        case STOPPED:
+            break;
+        case STILL_CAPTURE:
+            ALOGE("%s: Camera %d: Cannot stop preview during still capture.",
+                    __FUNCTION__, mCameraId);
+            break;
+        case RECORD:
+            // TODO: Handle record stop here
+        case PREVIEW:
+            mDevice->setStreamingRequest(NULL);
+            mDevice->waitUntilDrained();
+        case WAITING_FOR_PREVIEW_WINDOW:
+            mState = STOPPED;
+            break;
+        default:
+            ALOGE("%s: Camera %d: Unknown state %d", __FUNCTION__, mCameraId,
+                    mState);
+    }
+}
+
+bool Camera2Client::previewEnabled() {
+    ATRACE_CALL();
+    Mutex::Autolock icl(mICameraLock);
+    return mState == PREVIEW;
+}
+
+status_t Camera2Client::storeMetaDataInBuffers(bool enabled) {
+    ATRACE_CALL();
+    Mutex::Autolock icl(mICameraLock);
+    switch (mState) {
+        case RECORD:
+        case VIDEO_SNAPSHOT:
+            ALOGE("%s: Camera %d: Can't be called in state %s",
+                    __FUNCTION__, mCameraId, getStateName(mState));
+            return INVALID_OPERATION;
+        default:
+            // OK
+            break;
+    }
+    LockedParameters::Key k(mParameters);
+
+    k.mParameters.storeMetadataInBuffers = enabled;
+
+    return OK;
+}
+
+status_t Camera2Client::startRecording() {
+    ATRACE_CALL();
+    ALOGV("%s: E", __FUNCTION__);
+    Mutex::Autolock icl(mICameraLock);
+    status_t res;
+    switch (mState) {
+        case STOPPED:
+            res = startPreviewLocked();
+            if (res != OK) return res;
+            break;
+        case PREVIEW:
+            // Ready to go
+            break;
+        case RECORD:
+        case VIDEO_SNAPSHOT:
+            // OK to call this when recording is already on
+            return OK;
+            break;
+        default:
+            ALOGE("%s: Camera %d: Can't start recording in state %s",
+                    __FUNCTION__, mCameraId, getStateName(mState));
+            return INVALID_OPERATION;
+    };
+
+    LockedParameters::Key k(mParameters);
+
+    if (!k.mParameters.storeMetadataInBuffers) {
+        ALOGE("%s: Camera %d: Recording only supported in metadata mode, but "
+                "non-metadata recording mode requested!", __FUNCTION__,
+                mCameraId);
+        return INVALID_OPERATION;
+    }
+
+    res = updateRecordingStream(k.mParameters);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Unable to update recording stream: %s (%d)",
+                __FUNCTION__, mCameraId, strerror(-res), res);
+        return res;
+    }
+
+    if (mRecordingRequest == NULL) {
+        res = updateRecordingRequest(k.mParameters);
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Unable to create recording request: %s (%d)",
+                    __FUNCTION__, mCameraId, strerror(-res), res);
+            return res;
+        }
+    }
+
+    uint8_t outputStreams[2] = { mPreviewStreamId, mRecordingStreamId };
+    res = updateEntry(mRecordingRequest,
+            ANDROID_REQUEST_OUTPUT_STREAMS,
+            outputStreams, 2);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Unable to set up recording request: %s (%d)",
+                __FUNCTION__, mCameraId, strerror(-res), res);
+        return res;
+    }
+    res = sort_camera_metadata(mRecordingRequest);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Error sorting recording request: %s (%d)",
+                __FUNCTION__, mCameraId, strerror(-res), res);
+        return res;
+    }
+
+    res = mDevice->setStreamingRequest(mRecordingRequest);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Unable to set recording request to start "
+                "recording: %s (%d)", __FUNCTION__, mCameraId,
+                strerror(-res), res);
+        return res;
+    }
+    mState = RECORD;
+
+    return OK;
+}
+
+void Camera2Client::stopRecording() {
+    ATRACE_CALL();
+    ALOGV("%s: E", __FUNCTION__);
+    Mutex::Autolock icl(mICameraLock);
+    status_t res;
+    switch (mState) {
+        case RECORD:
+            // OK to stop
+            break;
+        case STOPPED:
+        case PREVIEW:
+        case STILL_CAPTURE:
+        case VIDEO_SNAPSHOT:
+        default:
+            ALOGE("%s: Camera %d: Can't stop recording in state %s",
+                    __FUNCTION__, mCameraId, getStateName(mState));
+            return;
+    };
+
+    // Back to preview. Since record can only be reached through preview,
+    // all preview stream setup should be up to date.
+    res = mDevice->setStreamingRequest(mPreviewRequest);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Unable to switch back to preview request: "
+                "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
+        return;
+    }
+
+    // TODO: Should recording heap be freed? Can't do it yet since requests
+    // could still be in flight.
+
+    mState = PREVIEW;
+}
+
+bool Camera2Client::recordingEnabled() {
+    ATRACE_CALL();
+    Mutex::Autolock icl(mICameraLock);
+    return (mState == RECORD || mState == VIDEO_SNAPSHOT);
+}
+
+void Camera2Client::releaseRecordingFrame(const sp<IMemory>& mem) {
+    ATRACE_CALL();
+    Mutex::Autolock icl(mICameraLock);
+    // Make sure this is for the current heap
+    ssize_t offset;
+    size_t size;
+    status_t res;
+    sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+    if (heap->getHeapID() != mRecordingHeap->mHeap->getHeapID()) {
+        ALOGW("%s: Camera %d: Mismatched heap ID, ignoring release "
+                "(got %x, expected %x)", __FUNCTION__, mCameraId,
+                heap->getHeapID(), mRecordingHeap->mHeap->getHeapID());
+        return;
+    }
+    uint8_t *data = (uint8_t*)heap->getBase() + offset;
+    uint32_t type = *(uint32_t*)data;
+    if (type != kMetadataBufferTypeGrallocSource) {
+        ALOGE("%s: Camera %d: Recording frame type invalid (got %x, expected %x)",
+                __FUNCTION__, mCameraId, type, kMetadataBufferTypeGrallocSource);
+        return;
+    }
+    buffer_handle_t imgBuffer = *(buffer_handle_t*)(data + 4);
+    ALOGV("%s: Camera %d: Freeing buffer_handle_t %p", __FUNCTION__, mCameraId,
+            imgBuffer);
+    res = mRecordingConsumer->freeBuffer(imgBuffer);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Unable to free recording frame (buffer_handle_t: %p):"
+                "%s (%d)",
+                __FUNCTION__, mCameraId, imgBuffer, strerror(-res), res);
+        return;
+    }
+
+    mRecordingHeapFree++;
+}
+
+status_t Camera2Client::autoFocus() {
+    ATRACE_CALL();
+    Mutex::Autolock icl(mICameraLock);
+    return OK;
+}
+
+status_t Camera2Client::cancelAutoFocus() {
+    ATRACE_CALL();
+    Mutex::Autolock icl(mICameraLock);
+    return OK;
+}
+
+status_t Camera2Client::takePicture(int msgType) {
+    ATRACE_CALL();
+    Mutex::Autolock icl(mICameraLock);
+    status_t res;
+
+    switch (mState) {
+        case NOT_INITIALIZED:
+        case STOPPED:
+        case WAITING_FOR_PREVIEW_WINDOW:
+            ALOGE("%s: Camera %d: Cannot take picture without preview enabled",
+                    __FUNCTION__, mCameraId);
+            return INVALID_OPERATION;
+        case PREVIEW:
+        case RECORD:
+            // Good to go for takePicture
+            break;
+        case STILL_CAPTURE:
+        case VIDEO_SNAPSHOT:
+            ALOGE("%s: Camera %d: Already taking a picture",
+                    __FUNCTION__, mCameraId);
+            return INVALID_OPERATION;
+    }
+
+    LockedParameters::Key k(mParameters);
+
+    res = updateCaptureStream(k.mParameters);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Can't set up still image stream: %s (%d)",
+                __FUNCTION__, mCameraId, strerror(-res), res);
+        return res;
+    }
+
+    if (mCaptureRequest == NULL) {
+        res = updateCaptureRequest(k.mParameters);
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Can't create still image capture request: "
+                    "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
+            return res;
+        }
+    }
+
+    camera_metadata_entry_t outputStreams;
+    if (mState == PREVIEW) {
+        uint8_t streamIds[2] = { mPreviewStreamId, mCaptureStreamId };
+        res = updateEntry(mCaptureRequest, ANDROID_REQUEST_OUTPUT_STREAMS,
+                &streamIds, 2);
+    } else if (mState == RECORD) {
+        uint8_t streamIds[3] = { mPreviewStreamId, mRecordingStreamId,
+                                 mCaptureStreamId };
+        res = updateEntry(mCaptureRequest, ANDROID_REQUEST_OUTPUT_STREAMS,
+                &streamIds, 3);
+    }
+
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Unable to set up still image capture request: "
+                "%s (%d)",
+                __FUNCTION__, mCameraId, strerror(-res), res);
+        return res;
+    }
+    res = sort_camera_metadata(mCaptureRequest);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Unable to sort capture request: %s (%d)",
+                __FUNCTION__, mCameraId, strerror(-res), res);
+        return res;
+    }
+
+    camera_metadata_t *captureCopy = clone_camera_metadata(mCaptureRequest);
+    if (captureCopy == NULL) {
+        ALOGE("%s: Camera %d: Unable to copy capture request for HAL device",
+                __FUNCTION__, mCameraId);
+        return NO_MEMORY;
+    }
+
+    if (mState == PREVIEW) {
+        res = mDevice->setStreamingRequest(NULL);
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Unable to stop preview for still capture: "
+                    "%s (%d)",
+                    __FUNCTION__, mCameraId, strerror(-res), res);
+            return res;
+        }
+    }
+    // TODO: Capture should be atomic with setStreamingRequest here
+    res = mDevice->capture(captureCopy);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Unable to submit still image capture request: "
+                "%s (%d)",
+                __FUNCTION__, mCameraId, strerror(-res), res);
+        return res;
+    }
+
+    switch (mState) {
+        case PREVIEW:
+            mState = STILL_CAPTURE;
+            break;
+        case RECORD:
+            mState = VIDEO_SNAPSHOT;
+            break;
+        default:
+            ALOGE("%s: Camera %d: Unknown state for still capture!",
+                    __FUNCTION__, mCameraId);
+            return INVALID_OPERATION;
+    }
+
+    return OK;
+}
+
+status_t Camera2Client::setParameters(const String8& params) {
+    ATRACE_CALL();
+    ALOGV("%s: E", __FUNCTION__);
+    Mutex::Autolock icl(mICameraLock);
+    LockedParameters::Key k(mParameters);
+    status_t res;
+
+    CameraParameters newParams(params);
+
+    // TODO: Currently ignoring any changes to supposedly read-only
+    // parameters such as supported preview sizes, etc. Should probably
+    // produce an error if they're changed.
+
+    /** Extract and verify new parameters */
+
+    size_t i;
+
+    // PREVIEW_SIZE
+    int previewWidth, previewHeight;
+    newParams.getPreviewSize(&previewWidth, &previewHeight);
+
+    if (previewWidth != k.mParameters.previewWidth ||
+            previewHeight != k.mParameters.previewHeight) {
+        if (mState >= PREVIEW) {
+            ALOGE("%s: Preview size cannot be updated when preview "
+                    "is active! (Currently %d x %d, requested %d x %d",
+                    __FUNCTION__,
+                    k.mParameters.previewWidth, k.mParameters.previewHeight,
+                    previewWidth, previewHeight);
+            return BAD_VALUE;
+        }
+        camera_metadata_entry_t availablePreviewSizes =
+            staticInfo(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES);
+        for (i = 0; i < availablePreviewSizes.count; i += 2 ) {
+            if (availablePreviewSizes.data.i32[i] == previewWidth &&
+                    availablePreviewSizes.data.i32[i+1] == previewHeight) break;
+        }
+        if (i == availablePreviewSizes.count) {
+            ALOGE("%s: Requested preview size %d x %d is not supported",
+                    __FUNCTION__, previewWidth, previewHeight);
+            return BAD_VALUE;
+        }
+    }
+
+    // PREVIEW_FPS_RANGE
+    int previewFpsRange[2];
+    int previewFps = 0;
+    bool fpsRangeChanged = false;
+    newParams.getPreviewFpsRange(&previewFpsRange[0], &previewFpsRange[1]);
+    if (previewFpsRange[0] != k.mParameters.previewFpsRange[0] ||
+            previewFpsRange[1] != k.mParameters.previewFpsRange[1]) {
+        fpsRangeChanged = true;
+        camera_metadata_entry_t availablePreviewFpsRanges =
+            staticInfo(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, 2);
+        for (i = 0; i < availablePreviewFpsRanges.count; i += 2) {
+            if ((availablePreviewFpsRanges.data.i32[i] ==
+                    previewFpsRange[0]) &&
+                (availablePreviewFpsRanges.data.i32[i+1] ==
+                    previewFpsRange[1]) ) {
+                break;
+            }
+        }
+        if (i == availablePreviewFpsRanges.count) {
+            ALOGE("%s: Requested preview FPS range %d - %d is not supported",
+                __FUNCTION__, previewFpsRange[0], previewFpsRange[1]);
+            return BAD_VALUE;
+        }
+        previewFps = previewFpsRange[0];
+    }
+
+    // PREVIEW_FORMAT
+    int previewFormat = formatStringToEnum(newParams.getPreviewFormat());
+    if (previewFormat != k.mParameters.previewFormat) {
+        if (mState >= PREVIEW) {
+            ALOGE("%s: Preview format cannot be updated when preview "
+                    "is active!", __FUNCTION__);
+            return BAD_VALUE;
+        }
+        camera_metadata_entry_t availableFormats =
+            staticInfo(ANDROID_SCALER_AVAILABLE_FORMATS);
+        for (i = 0; i < availableFormats.count; i++) {
+            if (availableFormats.data.i32[i] == previewFormat) break;
+        }
+        if (i == availableFormats.count) {
+            ALOGE("%s: Requested preview format %s (0x%x) is not supported",
+                    __FUNCTION__, newParams.getPreviewFormat(), previewFormat);
+            return BAD_VALUE;
+        }
+    }
+
+    // PREVIEW_FRAME_RATE
+    // Deprecated, only use if the preview fps range is unchanged this time.
+    // The single-value FPS is the same as the minimum of the range.
+    if (!fpsRangeChanged) {
+        previewFps = newParams.getPreviewFrameRate();
+        if (previewFps != k.mParameters.previewFps) {
+            camera_metadata_entry_t availableFrameRates =
+                staticInfo(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
+            for (i = 0; i < availableFrameRates.count; i+=2) {
+                if (availableFrameRates.data.i32[i] == previewFps) break;
+            }
+            if (i == availableFrameRates.count) {
+                ALOGE("%s: Requested preview frame rate %d is not supported",
+                        __FUNCTION__, previewFps);
+                return BAD_VALUE;
+            }
+            previewFpsRange[0] = availableFrameRates.data.i32[i];
+            previewFpsRange[1] = availableFrameRates.data.i32[i+1];
+        }
+    }
+
+    // PICTURE_SIZE
+    int pictureWidth, pictureHeight;
+    newParams.getPictureSize(&pictureWidth, &pictureHeight);
+    if (pictureWidth == k.mParameters.pictureWidth ||
+            pictureHeight == k.mParameters.pictureHeight) {
+        camera_metadata_entry_t availablePictureSizes =
+            staticInfo(ANDROID_SCALER_AVAILABLE_JPEG_SIZES);
+        for (i = 0; i < availablePictureSizes.count; i+=2) {
+            if (availablePictureSizes.data.i32[i] == pictureWidth &&
+                    availablePictureSizes.data.i32[i+1] == pictureHeight) break;
+        }
+        if (i == availablePictureSizes.count) {
+            ALOGE("%s: Requested picture size %d x %d is not supported",
+                    __FUNCTION__, pictureWidth, pictureHeight);
+            return BAD_VALUE;
+        }
+    }
+
+    // JPEG_THUMBNAIL_WIDTH/HEIGHT
+    int jpegThumbSize[2];
+    jpegThumbSize[0] =
+            newParams.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH);
+    jpegThumbSize[1] =
+            newParams.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT);
+    if (jpegThumbSize[0] != k.mParameters.jpegThumbSize[0] ||
+            jpegThumbSize[1] != k.mParameters.jpegThumbSize[1]) {
+        camera_metadata_entry_t availableJpegThumbSizes =
+            staticInfo(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES);
+        for (i = 0; i < availableJpegThumbSizes.count; i+=2) {
+            if (availableJpegThumbSizes.data.i32[i] == jpegThumbSize[0] &&
+                    availableJpegThumbSizes.data.i32[i+1] == jpegThumbSize[1]) {
+                break;
+            }
+        }
+        if (i == availableJpegThumbSizes.count) {
+            ALOGE("%s: Requested JPEG thumbnail size %d x %d is not supported",
+                    __FUNCTION__, jpegThumbSize[0], jpegThumbSize[1]);
+            return BAD_VALUE;
+        }
+    }
+
+    // JPEG_THUMBNAIL_QUALITY
+    int jpegThumbQuality =
+            newParams.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY);
+    if (jpegThumbQuality < 0 || jpegThumbQuality > 100) {
+        ALOGE("%s: Requested JPEG thumbnail quality %d is not supported",
+                __FUNCTION__, jpegThumbQuality);
+        return BAD_VALUE;
+    }
+
+    // JPEG_QUALITY
+    int jpegQuality =
+            newParams.getInt(CameraParameters::KEY_JPEG_QUALITY);
+    if (jpegQuality < 0 || jpegQuality > 100) {
+        ALOGE("%s: Requested JPEG quality %d is not supported",
+                __FUNCTION__, jpegQuality);
+        return BAD_VALUE;
+    }
+
+    // ROTATION
+    int jpegRotation =
+            newParams.getInt(CameraParameters::KEY_ROTATION);
+    if (jpegRotation != 0 &&
+            jpegRotation != 90 &&
+            jpegRotation != 180 &&
+            jpegRotation != 270) {
+        ALOGE("%s: Requested picture rotation angle %d is not supported",
+                __FUNCTION__, jpegRotation);
+        return BAD_VALUE;
+    }
+
+    // GPS
+    bool gpsEnabled = false;
+    double gpsCoordinates[3] = {0,0,0};
+    int64_t gpsTimestamp = 0;
+    String8 gpsProcessingMethod;
+    const char *gpsLatStr =
+            newParams.get(CameraParameters::KEY_GPS_LATITUDE);
+    if (gpsLatStr != NULL) {
+        const char *gpsLongStr =
+                newParams.get(CameraParameters::KEY_GPS_LONGITUDE);
+        const char *gpsAltitudeStr =
+                newParams.get(CameraParameters::KEY_GPS_ALTITUDE);
+        const char *gpsTimeStr =
+                newParams.get(CameraParameters::KEY_GPS_TIMESTAMP);
+        const char *gpsProcMethodStr =
+                newParams.get(CameraParameters::KEY_GPS_PROCESSING_METHOD);
+        if (gpsLongStr == NULL ||
+                gpsAltitudeStr == NULL ||
+                gpsTimeStr == NULL ||
+                gpsProcMethodStr == NULL) {
+            ALOGE("%s: Incomplete set of GPS parameters provided",
+                    __FUNCTION__);
+            return BAD_VALUE;
+        }
+        char *endPtr;
+        errno = 0;
+        gpsCoordinates[0] = strtod(gpsLatStr, &endPtr);
+        if (errno || endPtr == gpsLatStr) {
+            ALOGE("%s: Malformed GPS latitude: %s", __FUNCTION__, gpsLatStr);
+            return BAD_VALUE;
+        }
+        errno = 0;
+        gpsCoordinates[1] = strtod(gpsLongStr, &endPtr);
+        if (errno || endPtr == gpsLongStr) {
+            ALOGE("%s: Malformed GPS longitude: %s", __FUNCTION__, gpsLongStr);
+            return BAD_VALUE;
+        }
+        errno = 0;
+        gpsCoordinates[2] = strtod(gpsAltitudeStr, &endPtr);
+        if (errno || endPtr == gpsAltitudeStr) {
+            ALOGE("%s: Malformed GPS altitude: %s", __FUNCTION__,
+                    gpsAltitudeStr);
+            return BAD_VALUE;
+        }
+        errno = 0;
+        gpsTimestamp = strtoll(gpsTimeStr, &endPtr, 10);
+        if (errno || endPtr == gpsTimeStr) {
+            ALOGE("%s: Malformed GPS timestamp: %s", __FUNCTION__, gpsTimeStr);
+            return BAD_VALUE;
+        }
+        gpsProcessingMethod = gpsProcMethodStr;
+
+        gpsEnabled = true;
+    }
+
+    // WHITE_BALANCE
+    int wbMode = wbModeStringToEnum(
+        newParams.get(CameraParameters::KEY_WHITE_BALANCE) );
+    if (wbMode != k.mParameters.wbMode) {
+        camera_metadata_entry_t availableWbModes =
+            staticInfo(ANDROID_CONTROL_AWB_AVAILABLE_MODES);
+        for (i = 0; i < availableWbModes.count; i++) {
+            if (wbMode == availableWbModes.data.u8[i]) break;
+        }
+        if (i == availableWbModes.count) {
+            ALOGE("%s: Requested white balance mode %s is not supported",
+                    __FUNCTION__,
+                    newParams.get(CameraParameters::KEY_WHITE_BALANCE));
+            return BAD_VALUE;
+        }
+    }
+
+    // EFFECT
+    int effectMode = effectModeStringToEnum(
+        newParams.get(CameraParameters::KEY_EFFECT) );
+    if (effectMode != k.mParameters.effectMode) {
+        camera_metadata_entry_t availableEffectModes =
+            staticInfo(ANDROID_CONTROL_AVAILABLE_EFFECTS);
+        for (i = 0; i < availableEffectModes.count; i++) {
+            if (effectMode == availableEffectModes.data.u8[i]) break;
+        }
+        if (i == availableEffectModes.count) {
+            ALOGE("%s: Requested effect mode \"%s\" is not supported",
+                    __FUNCTION__,
+                    newParams.get(CameraParameters::KEY_EFFECT) );
+            return BAD_VALUE;
+        }
+    }
+
+    // ANTIBANDING
+    int antibandingMode = abModeStringToEnum(
+        newParams.get(CameraParameters::KEY_ANTIBANDING) );
+    if (antibandingMode != k.mParameters.antibandingMode) {
+        camera_metadata_entry_t availableAbModes =
+            staticInfo(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES);
+        for (i = 0; i < availableAbModes.count; i++) {
+            if (antibandingMode == availableAbModes.data.u8[i]) break;
+        }
+        if (i == availableAbModes.count) {
+            ALOGE("%s: Requested antibanding mode \"%s\" is not supported",
+                    __FUNCTION__,
+                    newParams.get(CameraParameters::KEY_ANTIBANDING));
+            return BAD_VALUE;
+        }
+    }
+
+    // SCENE_MODE
+    int sceneMode = sceneModeStringToEnum(
+        newParams.get(CameraParameters::KEY_SCENE_MODE) );
+    if (sceneMode != k.mParameters.sceneMode) {
+        camera_metadata_entry_t availableSceneModes =
+            staticInfo(ANDROID_CONTROL_AVAILABLE_SCENE_MODES);
+        for (i = 0; i < availableSceneModes.count; i++) {
+            if (sceneMode == availableSceneModes.data.u8[i]) break;
+        }
+        if (i == availableSceneModes.count) {
+            ALOGE("%s: Requested scene mode \"%s\" is not supported",
+                    __FUNCTION__,
+                    newParams.get(CameraParameters::KEY_SCENE_MODE));
+            return BAD_VALUE;
+        }
+    }
+
+    // FLASH_MODE
+    Parameters::flashMode_t flashMode = flashModeStringToEnum(
+        newParams.get(CameraParameters::KEY_FLASH_MODE) );
+    if (flashMode != k.mParameters.flashMode) {
+        camera_metadata_entry_t flashAvailable =
+            staticInfo(ANDROID_FLASH_AVAILABLE, 1, 1);
+        if (!flashAvailable.data.u8[0] &&
+                flashMode != Parameters::FLASH_MODE_OFF) {
+            ALOGE("%s: Requested flash mode \"%s\" is not supported: "
+                    "No flash on device", __FUNCTION__,
+                    newParams.get(CameraParameters::KEY_FLASH_MODE));
+            return BAD_VALUE;
+        } else if (flashMode == Parameters::FLASH_MODE_RED_EYE) {
+            camera_metadata_entry_t availableAeModes =
+                staticInfo(ANDROID_CONTROL_AE_AVAILABLE_MODES);
+            for (i = 0; i < availableAeModes.count; i++) {
+                if (flashMode == availableAeModes.data.u8[i]) break;
+            }
+            if (i == availableAeModes.count) {
+                ALOGE("%s: Requested flash mode \"%s\" is not supported",
+                        __FUNCTION__,
+                        newParams.get(CameraParameters::KEY_FLASH_MODE));
+                return BAD_VALUE;
+            }
+        } else if (flashMode == -1) {
+            ALOGE("%s: Requested flash mode \"%s\" is unknown",
+                    __FUNCTION__,
+                    newParams.get(CameraParameters::KEY_FLASH_MODE));
+            return BAD_VALUE;
+        }
+    }
+
+    // FOCUS_MODE
+    Parameters::focusMode_t focusMode = focusModeStringToEnum(
+        newParams.get(CameraParameters::KEY_FOCUS_MODE));
+    if (focusMode != k.mParameters.focusMode) {
+        if (focusMode != Parameters::FOCUS_MODE_FIXED) {
+            camera_metadata_entry_t minFocusDistance =
+                staticInfo(ANDROID_LENS_MINIMUM_FOCUS_DISTANCE);
+            if (minFocusDistance.data.f[0] == 0) {
+                ALOGE("%s: Requested focus mode \"%s\" is not available: "
+                        "fixed focus lens",
+                        __FUNCTION__,
+                        newParams.get(CameraParameters::KEY_FOCUS_MODE));
+                return BAD_VALUE;
+            } else if (focusMode != Parameters::FOCUS_MODE_INFINITY) {
+                camera_metadata_entry_t availableFocusModes =
+                    staticInfo(ANDROID_CONTROL_AF_AVAILABLE_MODES);
+                for (i = 0; i < availableFocusModes.count; i++) {
+                    if (focusMode == availableFocusModes.data.u8[i]) break;
+                }
+                if (i == availableFocusModes.count) {
+                    ALOGE("%s: Requested focus mode \"%s\" is not supported",
+                            __FUNCTION__,
+                            newParams.get(CameraParameters::KEY_FOCUS_MODE));
+                    return BAD_VALUE;
+                }
+            }
+        }
+    }
+
+    // FOCUS_AREAS
+    Vector<Parameters::Area> focusingAreas;
+    res = parseAreas(newParams.get(CameraParameters::KEY_FOCUS_AREAS),
+            &focusingAreas);
+    size_t max3aRegions =
+        (size_t)staticInfo(ANDROID_CONTROL_MAX_REGIONS, 1, 1).data.i32[0];
+    if (res == OK) res = validateAreas(focusingAreas, max3aRegions);
+    if (res != OK) {
+        ALOGE("%s: Requested focus areas are malformed: %s",
+                __FUNCTION__, newParams.get(CameraParameters::KEY_FOCUS_AREAS));
+        return BAD_VALUE;
+    }
+
+    // EXPOSURE_COMPENSATION
+    int exposureCompensation =
+        newParams.getInt(CameraParameters::KEY_EXPOSURE_COMPENSATION);
+    camera_metadata_entry_t exposureCompensationRange =
+        staticInfo(ANDROID_CONTROL_AE_EXP_COMPENSATION_RANGE);
+    if (exposureCompensation < exposureCompensationRange.data.i32[0] ||
+            exposureCompensation > exposureCompensationRange.data.i32[1]) {
+        ALOGE("%s: Requested exposure compensation index is out of bounds: %d",
+                __FUNCTION__, exposureCompensation);
+        return BAD_VALUE;
+    }
+
+    // AUTO_EXPOSURE_LOCK (always supported)
+    bool autoExposureLock = boolFromString(
+        newParams.get(CameraParameters::KEY_AUTO_EXPOSURE_LOCK));
+
+    // AUTO_WHITEBALANCE_LOCK (always supported)
+    bool autoWhiteBalanceLock = boolFromString(
+        newParams.get(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK));
+
+    // METERING_AREAS
+    Vector<Parameters::Area> meteringAreas;
+    res = parseAreas(newParams.get(CameraParameters::KEY_METERING_AREAS),
+            &meteringAreas);
+    if (res == OK) res = validateAreas(focusingAreas, max3aRegions);
+    if (res != OK) {
+        ALOGE("%s: Requested metering areas are malformed: %s",
+                __FUNCTION__,
+                newParams.get(CameraParameters::KEY_METERING_AREAS));
+        return BAD_VALUE;
+    }
+
+    // ZOOM
+    int zoom = newParams.getInt(CameraParameters::KEY_ZOOM);
+    if (zoom < 0 || zoom > (int)NUM_ZOOM_STEPS) {
+        ALOGE("%s: Requested zoom level %d is not supported",
+                __FUNCTION__, zoom);
+        return BAD_VALUE;
+    }
+
+    // VIDEO_SIZE
+    int videoWidth, videoHeight;
+    newParams.getVideoSize(&videoWidth, &videoHeight);
+    if (videoWidth != k.mParameters.videoWidth ||
+            videoHeight != k.mParameters.videoHeight) {
+        if (mState == RECORD) {
+            ALOGE("%s: Video size cannot be updated when recording is active!",
+                    __FUNCTION__);
+            return BAD_VALUE;
+        }
+        camera_metadata_entry_t availableVideoSizes =
+            staticInfo(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES);
+        for (i = 0; i < availableVideoSizes.count; i += 2 ) {
+            if (availableVideoSizes.data.i32[i] == videoWidth &&
+                    availableVideoSizes.data.i32[i+1] == videoHeight)  break;
+        }
+        if (i == availableVideoSizes.count) {
+            ALOGE("%s: Requested video size %d x %d is not supported",
+                    __FUNCTION__, videoWidth, videoHeight);
+            return BAD_VALUE;
+        }
+    }
+
+    // RECORDING_HINT (always supported)
+    bool recordingHint = boolFromString(
+        newParams.get(CameraParameters::KEY_RECORDING_HINT) );
+
+    // VIDEO_STABILIZATION
+    bool videoStabilization = boolFromString(
+        newParams.get(CameraParameters::KEY_VIDEO_STABILIZATION) );
+    camera_metadata_entry_t availableVideoStabilizationModes =
+        staticInfo(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES);
+    if (videoStabilization && availableVideoStabilizationModes.count == 1) {
+        ALOGE("%s: Video stabilization not supported", __FUNCTION__);
+    }
+
+    /** Update internal parameters */
+
+    k.mParameters.previewWidth = previewWidth;
+    k.mParameters.previewHeight = previewHeight;
+    k.mParameters.previewFpsRange[0] = previewFpsRange[0];
+    k.mParameters.previewFpsRange[1] = previewFpsRange[1];
+    k.mParameters.previewFps = previewFps;
+    k.mParameters.previewFormat = previewFormat;
+
+    k.mParameters.pictureWidth = pictureWidth;
+    k.mParameters.pictureHeight = pictureHeight;
+
+    k.mParameters.jpegThumbSize[0] = jpegThumbSize[0];
+    k.mParameters.jpegThumbSize[1] = jpegThumbSize[1];
+    k.mParameters.jpegQuality = jpegQuality;
+    k.mParameters.jpegThumbQuality = jpegThumbQuality;
+
+    k.mParameters.gpsEnabled = gpsEnabled;
+    k.mParameters.gpsCoordinates[0] = gpsCoordinates[0];
+    k.mParameters.gpsCoordinates[1] = gpsCoordinates[1];
+    k.mParameters.gpsCoordinates[2] = gpsCoordinates[2];
+    k.mParameters.gpsTimestamp = gpsTimestamp;
+    k.mParameters.gpsProcessingMethod = gpsProcessingMethod;
+
+    k.mParameters.wbMode = wbMode;
+    k.mParameters.effectMode = effectMode;
+    k.mParameters.antibandingMode = antibandingMode;
+    k.mParameters.sceneMode = sceneMode;
+
+    k.mParameters.flashMode = flashMode;
+    k.mParameters.focusMode = focusMode;
+
+    k.mParameters.focusingAreas = focusingAreas;
+    k.mParameters.exposureCompensation = exposureCompensation;
+    k.mParameters.autoExposureLock = autoExposureLock;
+    k.mParameters.autoWhiteBalanceLock = autoWhiteBalanceLock;
+    k.mParameters.meteringAreas = meteringAreas;
+    k.mParameters.zoom = zoom;
+
+    k.mParameters.videoWidth = videoWidth;
+    k.mParameters.videoHeight = videoHeight;
+
+    k.mParameters.recordingHint = recordingHint;
+    k.mParameters.videoStabilization = videoStabilization;
+
+    res = updatePreviewRequest(k.mParameters);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Unable to update preview request: %s (%d)",
+                __FUNCTION__, mCameraId, strerror(-res), res);
+        return res;
+    }
+    res = updateCaptureRequest(k.mParameters);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Unable to update capture request: %s (%d)",
+                __FUNCTION__, mCameraId, strerror(-res), res);
+        return res;
+    }
+
+    res = updateRecordingRequest(k.mParameters);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Unable to update recording request: %s (%d)",
+                __FUNCTION__, mCameraId, strerror(-res), res);
+        return res;
+    }
+
+    if (mState == PREVIEW) {
+        res = mDevice->setStreamingRequest(mPreviewRequest);
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Error streaming new preview request: %s (%d)",
+                    __FUNCTION__, mCameraId, strerror(-res), res);
+            return res;
+        }
+    } else if (mState == RECORD || mState == VIDEO_SNAPSHOT) {
+        res = mDevice->setStreamingRequest(mRecordingRequest);
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Error streaming new record request: %s (%d)",
+                    __FUNCTION__, mCameraId, strerror(-res), res);
+            return res;
+        }
+    }
+
+    k.mParameters.paramsFlattened = params;
+
+    return OK;
+}
+
+String8 Camera2Client::getParameters() const {
+    ATRACE_CALL();
+    Mutex::Autolock icl(mICameraLock);
+
+    LockedParameters::ReadKey k(mParameters);
+
+    // TODO: Deal with focus distances
+    return k.mParameters.paramsFlattened;
+}
+
+status_t Camera2Client::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) {
+    ATRACE_CALL();
+    Mutex::Autolock icl(mICameraLock);
+
+    ALOGV("%s: Camera %d: Command %d (%d, %d)", __FUNCTION__, mCameraId,
+            cmd, arg1, arg2);
+
+    if (cmd == CAMERA_CMD_SET_DISPLAY_ORIENTATION) {
+        LockedParameters::Key k(mParameters);
+        int transform = degToTransform(arg1,
+                mCameraFacing == CAMERA_FACING_FRONT);
+        if (transform == -1) {
+            ALOGE("%s: Camera %d: Error setting %d as display orientation value",
+                    __FUNCTION__, mCameraId, arg1);
+            return BAD_VALUE;
+        }
+        if (transform != k.mParameters.previewTransform &&
+                mPreviewStreamId != NO_STREAM) {
+            mDevice->setStreamTransform(mPreviewStreamId, transform);
+        }
+        k.mParameters.previewTransform = transform;
+        return OK;
+    }
+
+    ALOGE("%s: Camera %d: Unimplemented command %d (%d, %d)", __FUNCTION__,
+            mCameraId, cmd, arg1, arg2);
+
+    return OK;
+}
+
+/** Device-related methods */
+
+void Camera2Client::onCaptureAvailable() {
+    ATRACE_CALL();
+    status_t res;
+    sp<ICameraClient> currentClient;
+    ALOGV("%s: Camera %d: Still capture available", __FUNCTION__, mCameraId);
+
+    CpuConsumer::LockedBuffer imgBuffer;
+    {
+        Mutex::Autolock icl(mICameraLock);
+
+        // TODO: Signal errors here upstream
+        if (mState != STILL_CAPTURE && mState != VIDEO_SNAPSHOT) {
+            ALOGE("%s: Camera %d: Still image produced unexpectedly!",
+                    __FUNCTION__, mCameraId);
+            return;
+        }
+
+        res = mCaptureConsumer->lockNextBuffer(&imgBuffer);
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Error receiving still image buffer: %s (%d)",
+                    __FUNCTION__, mCameraId, strerror(-res), res);
+            return;
+        }
+
+        if (imgBuffer.format != HAL_PIXEL_FORMAT_BLOB) {
+            ALOGE("%s: Camera %d: Unexpected format for still image: "
+                    "%x, expected %x", __FUNCTION__, mCameraId,
+                    imgBuffer.format,
+                    HAL_PIXEL_FORMAT_BLOB);
+            mCaptureConsumer->unlockBuffer(imgBuffer);
+            return;
+        }
+
+        // TODO: Optimize this to avoid memcopy
+        void* captureMemory = mCaptureHeap->mHeap->getBase();
+        size_t size = mCaptureHeap->mHeap->getSize();
+        memcpy(captureMemory, imgBuffer.data, size);
+
+        mCaptureConsumer->unlockBuffer(imgBuffer);
+
+        currentClient = mCameraClient;
+        switch (mState) {
+            case STILL_CAPTURE:
+                mState = STOPPED;
+                break;
+            case VIDEO_SNAPSHOT:
+                mState = RECORD;
+                break;
+            default:
+                ALOGE("%s: Camera %d: Unexpected state %d", __FUNCTION__,
+                        mCameraId, mState);
+                break;
+        }
+    }
+    // Call outside mICameraLock to allow re-entrancy from notification
+    if (currentClient != 0) {
+        currentClient->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE,
+                mCaptureHeap->mBuffers[0], NULL);
+    }
+}
+
+void Camera2Client::onRecordingFrameAvailable() {
+    ATRACE_CALL();
+    status_t res;
+    sp<ICameraClient> currentClient;
+    size_t heapIdx = 0;
+    nsecs_t timestamp;
+    {
+        Mutex::Autolock icl(mICameraLock);
+        // TODO: Signal errors here upstream
+        bool discardData = false;
+        if (mState != RECORD && mState != VIDEO_SNAPSHOT) {
+            ALOGV("%s: Camera %d: Discarding recording image buffers received after "
+                    "recording done",
+                    __FUNCTION__, mCameraId);
+            discardData = true;
+        }
+
+        buffer_handle_t imgBuffer;
+        res = mRecordingConsumer->getNextBuffer(&imgBuffer, &timestamp);
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Error receiving recording buffer: %s (%d)",
+                    __FUNCTION__, mCameraId, strerror(-res), res);
+            return;
+        }
+
+        if (discardData) {
+            mRecordingConsumer->freeBuffer(imgBuffer);
+            return;
+        }
+
+        if (mRecordingHeap == 0) {
+            const size_t bufferSize = 4 + sizeof(buffer_handle_t);
+            ALOGV("%s: Camera %d: Creating recording heap with %d buffers of "
+                    "size %d bytes", __FUNCTION__, mCameraId,
+                    kRecordingHeapCount, bufferSize);
+            if (mRecordingHeap != 0) {
+                ALOGV("%s: Camera %d: Previous heap has size %d "
+                        "(new will be %d) bytes", __FUNCTION__, mCameraId,
+                        mRecordingHeap->mHeap->getSize(),
+                        bufferSize * kRecordingHeapCount);
+            }
+            // Need to allocate memory for heap
+            mRecordingHeap.clear();
+
+            mRecordingHeap = new Camera2Heap(bufferSize, kRecordingHeapCount,
+                    "Camera2Client::RecordingHeap");
+            if (mRecordingHeap->mHeap->getSize() == 0) {
+                ALOGE("%s: Camera %d: Unable to allocate memory for recording",
+                        __FUNCTION__, mCameraId);
+                mRecordingConsumer->freeBuffer(imgBuffer);
+                return;
+            }
+            mRecordingHeapHead = 0;
+            mRecordingHeapFree = kRecordingHeapCount;
+        }
+
+        if ( mRecordingHeapFree == 0) {
+            ALOGE("%s: Camera %d: No free recording buffers, dropping frame",
+                    __FUNCTION__, mCameraId);
+            mRecordingConsumer->freeBuffer(imgBuffer);
+            return;
+        }
+        heapIdx = mRecordingHeapHead;
+        mRecordingHeapHead = (mRecordingHeapHead + 1) % kRecordingHeapCount;
+        mRecordingHeapFree--;
+
+        ALOGV("%s: Camera %d: Timestamp %lld",
+                __FUNCTION__, mCameraId, timestamp);
+
+        ssize_t offset;
+        size_t size;
+        sp<IMemoryHeap> heap =
+                mRecordingHeap->mBuffers[heapIdx]->getMemory(&offset,
+                        &size);
+
+        uint8_t *data = (uint8_t*)heap->getBase() + offset;
+        uint32_t type = kMetadataBufferTypeGrallocSource;
+        memcpy(data, &type, 4);
+        memcpy(data + 4, &imgBuffer, sizeof(buffer_handle_t));
+        ALOGV("%s: Camera %d: Sending out buffer_handle_t %p",
+                __FUNCTION__, mCameraId, imgBuffer);
+        currentClient = mCameraClient;
+    }
+    // Call outside mICameraLock to allow re-entrancy from notification
+    if (currentClient != 0) {
+        currentClient->dataCallbackTimestamp(timestamp,
+                CAMERA_MSG_VIDEO_FRAME,
+                mRecordingHeap->mBuffers[heapIdx]);
+    }
+}
+
+camera_metadata_entry_t Camera2Client::staticInfo(uint32_t tag,
+        size_t minCount, size_t maxCount) {
+    status_t res;
+    camera_metadata_entry_t entry;
+    res = find_camera_metadata_entry(mDevice->info(),
+            tag,
+            &entry);
+    if (CC_UNLIKELY( res != OK )) {
+        const char* tagSection = get_camera_metadata_section_name(tag);
+        if (tagSection == NULL) tagSection = "<unknown>";
+        const char* tagName = get_camera_metadata_tag_name(tag);
+        if (tagName == NULL) tagName = "<unknown>";
+
+        ALOGE("Error finding static metadata entry '%s.%s' (%x): %s (%d)",
+                tagSection, tagName, tag, strerror(-res), res);
+        entry.count = 0;
+        entry.data.u8 = NULL;
+    } else if (CC_UNLIKELY(
+            (minCount != 0 && entry.count < minCount) ||
+            (maxCount != 0 && entry.count > maxCount) ) ) {
+        const char* tagSection = get_camera_metadata_section_name(tag);
+        if (tagSection == NULL) tagSection = "<unknown>";
+        const char* tagName = get_camera_metadata_tag_name(tag);
+        if (tagName == NULL) tagName = "<unknown>";
+        ALOGE("Malformed static metadata entry '%s.%s' (%x):"
+                "Expected between %d and %d values, but got %d values",
+                tagSection, tagName, tag, minCount, maxCount, entry.count);
+        entry.count = 0;
+        entry.data.u8 = NULL;
+    }
+
+    return entry;
+}
+
+/** Utility methods */
+
+
+status_t Camera2Client::buildDefaultParameters() {
+    ATRACE_CALL();
+    LockedParameters::Key k(mParameters);
+
+    status_t res;
+    CameraParameters params;
+
+    camera_metadata_entry_t availableProcessedSizes =
+        staticInfo(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES, 2);
+    if (!availableProcessedSizes.count) return NO_INIT;
+
+    // TODO: Pick more intelligently
+    k.mParameters.previewWidth = availableProcessedSizes.data.i32[0];
+    k.mParameters.previewHeight = availableProcessedSizes.data.i32[1];
+    k.mParameters.videoWidth = k.mParameters.previewWidth;
+    k.mParameters.videoHeight = k.mParameters.previewHeight;
+
+    params.setPreviewSize(k.mParameters.previewWidth, k.mParameters.previewHeight);
+    params.setVideoSize(k.mParameters.videoWidth, k.mParameters.videoHeight);
+    params.set(CameraParameters::KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO,
+            String8::format("%dx%d",
+                    k.mParameters.previewWidth, k.mParameters.previewHeight));
+    {
+        String8 supportedPreviewSizes;
+        for (size_t i=0; i < availableProcessedSizes.count; i += 2) {
+            if (i != 0) supportedPreviewSizes += ",";
+            supportedPreviewSizes += String8::format("%dx%d",
+                    availableProcessedSizes.data.i32[i],
+                    availableProcessedSizes.data.i32[i+1]);
+        }
+        params.set(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES,
+                supportedPreviewSizes);
+        params.set(CameraParameters::KEY_SUPPORTED_VIDEO_SIZES,
+                supportedPreviewSizes);
+    }
+
+    camera_metadata_entry_t availableFpsRanges =
+        staticInfo(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, 2);
+    if (!availableFpsRanges.count) return NO_INIT;
+
+    k.mParameters.previewFpsRange[0] = availableFpsRanges.data.i32[0];
+    k.mParameters.previewFpsRange[1] = availableFpsRanges.data.i32[1];
+
+    params.set(CameraParameters::KEY_PREVIEW_FPS_RANGE,
+            String8::format("%d,%d",
+                    k.mParameters.previewFpsRange[0],
+                    k.mParameters.previewFpsRange[1]));
+
+    {
+        String8 supportedPreviewFpsRange;
+        for (size_t i=0; i < availableFpsRanges.count; i += 2) {
+            if (i != 0) supportedPreviewFpsRange += ",";
+            supportedPreviewFpsRange += String8::format("(%d,%d)",
+                    availableFpsRanges.data.i32[i],
+                    availableFpsRanges.data.i32[i+1]);
+        }
+        params.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE,
+                supportedPreviewFpsRange);
+    }
+
+    k.mParameters.previewFormat = HAL_PIXEL_FORMAT_YCrCb_420_SP;
+    params.set(CameraParameters::KEY_PREVIEW_FORMAT,
+            formatEnumToString(k.mParameters.previewFormat)); // NV21
+
+    k.mParameters.previewTransform = degToTransform(0,
+            mCameraFacing == CAMERA_FACING_FRONT);
+
+    camera_metadata_entry_t availableFormats =
+        staticInfo(ANDROID_SCALER_AVAILABLE_FORMATS);
+
+    {
+        String8 supportedPreviewFormats;
+        bool addComma = false;
+        for (size_t i=0; i < availableFormats.count; i++) {
+            if (addComma) supportedPreviewFormats += ",";
+            addComma = true;
+            switch (availableFormats.data.i32[i]) {
+            case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+                supportedPreviewFormats +=
+                    CameraParameters::PIXEL_FORMAT_YUV422SP;
+                break;
+            case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+                supportedPreviewFormats +=
+                    CameraParameters::PIXEL_FORMAT_YUV420SP;
+                break;
+            case HAL_PIXEL_FORMAT_YCbCr_422_I:
+                supportedPreviewFormats +=
+                    CameraParameters::PIXEL_FORMAT_YUV422I;
+                break;
+            case HAL_PIXEL_FORMAT_YV12:
+                supportedPreviewFormats +=
+                    CameraParameters::PIXEL_FORMAT_YUV420P;
+                break;
+            case HAL_PIXEL_FORMAT_RGB_565:
+                supportedPreviewFormats +=
+                    CameraParameters::PIXEL_FORMAT_RGB565;
+                break;
+            case HAL_PIXEL_FORMAT_RGBA_8888:
+                supportedPreviewFormats +=
+                    CameraParameters::PIXEL_FORMAT_RGBA8888;
+                break;
+            // Not advertizing JPEG, RAW_SENSOR, etc, for preview formats
+            case HAL_PIXEL_FORMAT_RAW_SENSOR:
+            case HAL_PIXEL_FORMAT_BLOB:
+                addComma = false;
+                break;
+
+            default:
+                ALOGW("%s: Camera %d: Unknown preview format: %x",
+                        __FUNCTION__, mCameraId, availableFormats.data.i32[i]);
+                addComma = false;
+                break;
+            }
+        }
+        params.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS,
+                supportedPreviewFormats);
+    }
+
+    // PREVIEW_FRAME_RATE / SUPPORTED_PREVIEW_FRAME_RATES are deprecated, but
+    // still have to do something sane for them
+
+    params.set(CameraParameters::KEY_PREVIEW_FRAME_RATE,
+            k.mParameters.previewFpsRange[0]);
+
+    {
+        String8 supportedPreviewFrameRates;
+        for (size_t i=0; i < availableFpsRanges.count; i += 2) {
+            if (i != 0) supportedPreviewFrameRates += ",";
+            supportedPreviewFrameRates += String8::format("%d",
+                    availableFpsRanges.data.i32[i]);
+        }
+        params.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES,
+                supportedPreviewFrameRates);
+    }
+
+    camera_metadata_entry_t availableJpegSizes =
+        staticInfo(ANDROID_SCALER_AVAILABLE_JPEG_SIZES, 2);
+    if (!availableJpegSizes.count) return NO_INIT;
+
+    // TODO: Pick maximum
+    k.mParameters.pictureWidth = availableJpegSizes.data.i32[0];
+    k.mParameters.pictureHeight = availableJpegSizes.data.i32[1];
+
+    params.setPictureSize(k.mParameters.pictureWidth,
+            k.mParameters.pictureHeight);
+
+    {
+        String8 supportedPictureSizes;
+        for (size_t i=0; i < availableJpegSizes.count; i += 2) {
+            if (i != 0) supportedPictureSizes += ",";
+            supportedPictureSizes += String8::format("%dx%d",
+                    availableJpegSizes.data.i32[i],
+                    availableJpegSizes.data.i32[i+1]);
+        }
+        params.set(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES,
+                supportedPictureSizes);
+    }
+
+    params.setPictureFormat(CameraParameters::PIXEL_FORMAT_JPEG);
+    params.set(CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS,
+            CameraParameters::PIXEL_FORMAT_JPEG);
+
+    camera_metadata_entry_t availableJpegThumbnailSizes =
+        staticInfo(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES, 2);
+    if (!availableJpegThumbnailSizes.count) return NO_INIT;
+
+    // TODO: Pick default thumbnail size sensibly
+    k.mParameters.jpegThumbSize[0] = availableJpegThumbnailSizes.data.i32[0];
+    k.mParameters.jpegThumbSize[1] = availableJpegThumbnailSizes.data.i32[1];
+
+    params.set(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH,
+            k.mParameters.jpegThumbSize[0]);
+    params.set(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT,
+            k.mParameters.jpegThumbSize[1]);
+
+    {
+        String8 supportedJpegThumbSizes;
+        for (size_t i=0; i < availableJpegThumbnailSizes.count; i += 2) {
+            if (i != 0) supportedJpegThumbSizes += ",";
+            supportedJpegThumbSizes += String8::format("%dx%d",
+                    availableJpegThumbnailSizes.data.i32[i],
+                    availableJpegThumbnailSizes.data.i32[i+1]);
+        }
+        params.set(CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES,
+                supportedJpegThumbSizes);
+    }
+
+    k.mParameters.jpegThumbQuality = 90;
+    params.set(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY,
+            k.mParameters.jpegThumbQuality);
+    k.mParameters.jpegQuality = 90;
+    params.set(CameraParameters::KEY_JPEG_QUALITY,
+            k.mParameters.jpegQuality);
+    k.mParameters.jpegRotation = 0;
+    params.set(CameraParameters::KEY_ROTATION,
+            k.mParameters.jpegRotation);
+
+    k.mParameters.gpsEnabled = false;
+    k.mParameters.gpsProcessingMethod = "unknown";
+    // GPS fields in CameraParameters are not set by implementation
+
+    k.mParameters.wbMode = ANDROID_CONTROL_AWB_AUTO;
+    params.set(CameraParameters::KEY_WHITE_BALANCE,
+            CameraParameters::WHITE_BALANCE_AUTO);
+
+    camera_metadata_entry_t availableWhiteBalanceModes =
+        staticInfo(ANDROID_CONTROL_AWB_AVAILABLE_MODES);
+    {
+        String8 supportedWhiteBalance;
+        bool addComma = false;
+        for (size_t i=0; i < availableWhiteBalanceModes.count; i++) {
+            if (addComma) supportedWhiteBalance += ",";
+            addComma = true;
+            switch (availableWhiteBalanceModes.data.u8[i]) {
+            case ANDROID_CONTROL_AWB_AUTO:
+                supportedWhiteBalance +=
+                    CameraParameters::WHITE_BALANCE_AUTO;
+                break;
+            case ANDROID_CONTROL_AWB_INCANDESCENT:
+                supportedWhiteBalance +=
+                    CameraParameters::WHITE_BALANCE_INCANDESCENT;
+                break;
+            case ANDROID_CONTROL_AWB_FLUORESCENT:
+                supportedWhiteBalance +=
+                    CameraParameters::WHITE_BALANCE_FLUORESCENT;
+                break;
+            case ANDROID_CONTROL_AWB_WARM_FLUORESCENT:
+                supportedWhiteBalance +=
+                    CameraParameters::WHITE_BALANCE_WARM_FLUORESCENT;
+                break;
+            case ANDROID_CONTROL_AWB_DAYLIGHT:
+                supportedWhiteBalance +=
+                    CameraParameters::WHITE_BALANCE_DAYLIGHT;
+                break;
+            case ANDROID_CONTROL_AWB_CLOUDY_DAYLIGHT:
+                supportedWhiteBalance +=
+                    CameraParameters::WHITE_BALANCE_CLOUDY_DAYLIGHT;
+                break;
+            case ANDROID_CONTROL_AWB_TWILIGHT:
+                supportedWhiteBalance +=
+                    CameraParameters::WHITE_BALANCE_TWILIGHT;
+                break;
+            case ANDROID_CONTROL_AWB_SHADE:
+                supportedWhiteBalance +=
+                    CameraParameters::WHITE_BALANCE_SHADE;
+                break;
+            // Skipping values not mappable to v1 API
+            case ANDROID_CONTROL_AWB_OFF:
+                addComma = false;
+                break;
+            default:
+                ALOGW("%s: Camera %d: Unknown white balance value: %d",
+                        __FUNCTION__, mCameraId,
+                        availableWhiteBalanceModes.data.u8[i]);
+                addComma = false;
+                break;
+            }
+        }
+        params.set(CameraParameters::KEY_SUPPORTED_WHITE_BALANCE,
+                supportedWhiteBalance);
+    }
+
+    k.mParameters.effectMode = ANDROID_CONTROL_EFFECT_OFF;
+    params.set(CameraParameters::KEY_EFFECT,
+            CameraParameters::EFFECT_NONE);
+
+    camera_metadata_entry_t availableEffects =
+        staticInfo(ANDROID_CONTROL_AVAILABLE_EFFECTS);
+    if (!availableEffects.count) return NO_INIT;
+    {
+        String8 supportedEffects;
+        bool addComma = false;
+        for (size_t i=0; i < availableEffects.count; i++) {
+            if (addComma) supportedEffects += ",";
+            addComma = true;
+            switch (availableEffects.data.u8[i]) {
+                case ANDROID_CONTROL_EFFECT_OFF:
+                    supportedEffects +=
+                        CameraParameters::EFFECT_NONE;
+                    break;
+                case ANDROID_CONTROL_EFFECT_MONO:
+                    supportedEffects +=
+                        CameraParameters::EFFECT_MONO;
+                    break;
+                case ANDROID_CONTROL_EFFECT_NEGATIVE:
+                    supportedEffects +=
+                        CameraParameters::EFFECT_NEGATIVE;
+                    break;
+                case ANDROID_CONTROL_EFFECT_SOLARIZE:
+                    supportedEffects +=
+                        CameraParameters::EFFECT_SOLARIZE;
+                    break;
+                case ANDROID_CONTROL_EFFECT_SEPIA:
+                    supportedEffects +=
+                        CameraParameters::EFFECT_SEPIA;
+                    break;
+                case ANDROID_CONTROL_EFFECT_POSTERIZE:
+                    supportedEffects +=
+                        CameraParameters::EFFECT_POSTERIZE;
+                    break;
+                case ANDROID_CONTROL_EFFECT_WHITEBOARD:
+                    supportedEffects +=
+                        CameraParameters::EFFECT_WHITEBOARD;
+                    break;
+                case ANDROID_CONTROL_EFFECT_BLACKBOARD:
+                    supportedEffects +=
+                        CameraParameters::EFFECT_BLACKBOARD;
+                    break;
+                case ANDROID_CONTROL_EFFECT_AQUA:
+                    supportedEffects +=
+                        CameraParameters::EFFECT_AQUA;
+                    break;
+                default:
+                    ALOGW("%s: Camera %d: Unknown effect value: %d",
+                        __FUNCTION__, mCameraId, availableEffects.data.u8[i]);
+                    addComma = false;
+                    break;
+            }
+        }
+        params.set(CameraParameters::KEY_SUPPORTED_EFFECTS, supportedEffects);
+    }
+
+    k.mParameters.antibandingMode = ANDROID_CONTROL_AE_ANTIBANDING_AUTO;
+    params.set(CameraParameters::KEY_ANTIBANDING,
+            CameraParameters::ANTIBANDING_AUTO);
+
+    camera_metadata_entry_t availableAntibandingModes =
+        staticInfo(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES);
+    if (!availableAntibandingModes.count) return NO_INIT;
+    {
+        String8 supportedAntibanding;
+        bool addComma = false;
+        for (size_t i=0; i < availableAntibandingModes.count; i++) {
+            if (addComma) supportedAntibanding += ",";
+            addComma = true;
+            switch (availableAntibandingModes.data.u8[i]) {
+                case ANDROID_CONTROL_AE_ANTIBANDING_OFF:
+                    supportedAntibanding +=
+                        CameraParameters::ANTIBANDING_OFF;
+                    break;
+                case ANDROID_CONTROL_AE_ANTIBANDING_50HZ:
+                    supportedAntibanding +=
+                        CameraParameters::ANTIBANDING_50HZ;
+                    break;
+                case ANDROID_CONTROL_AE_ANTIBANDING_60HZ:
+                    supportedAntibanding +=
+                        CameraParameters::ANTIBANDING_60HZ;
+                    break;
+                case ANDROID_CONTROL_AE_ANTIBANDING_AUTO:
+                    supportedAntibanding +=
+                        CameraParameters::ANTIBANDING_AUTO;
+                    break;
+                default:
+                    ALOGW("%s: Camera %d: Unknown antibanding value: %d",
+                        __FUNCTION__, mCameraId,
+                            availableAntibandingModes.data.u8[i]);
+                    addComma = false;
+                    break;
+            }
+        }
+        params.set(CameraParameters::KEY_SUPPORTED_ANTIBANDING,
+                supportedAntibanding);
+    }
+
+    k.mParameters.sceneMode = ANDROID_CONTROL_OFF;
+    params.set(CameraParameters::KEY_SCENE_MODE,
+            CameraParameters::SCENE_MODE_AUTO);
+
+    camera_metadata_entry_t availableSceneModes =
+        staticInfo(ANDROID_CONTROL_AVAILABLE_SCENE_MODES);
+    if (!availableSceneModes.count) return NO_INIT;
+    {
+        String8 supportedSceneModes(CameraParameters::SCENE_MODE_AUTO);
+        bool addComma = true;
+        bool noSceneModes = false;
+        for (size_t i=0; i < availableSceneModes.count; i++) {
+            if (addComma) supportedSceneModes += ",";
+            addComma = true;
+            switch (availableSceneModes.data.u8[i]) {
+                case ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED:
+                    noSceneModes = true;
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_FACE_PRIORITY:
+                    // Not in old API
+                    addComma = false;
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_ACTION:
+                    supportedSceneModes +=
+                        CameraParameters::SCENE_MODE_ACTION;
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_PORTRAIT:
+                    supportedSceneModes +=
+                        CameraParameters::SCENE_MODE_PORTRAIT;
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_LANDSCAPE:
+                    supportedSceneModes +=
+                        CameraParameters::SCENE_MODE_LANDSCAPE;
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_NIGHT:
+                    supportedSceneModes +=
+                        CameraParameters::SCENE_MODE_NIGHT;
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_NIGHT_PORTRAIT:
+                    supportedSceneModes +=
+                        CameraParameters::SCENE_MODE_NIGHT_PORTRAIT;
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_THEATRE:
+                    supportedSceneModes +=
+                        CameraParameters::SCENE_MODE_THEATRE;
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_BEACH:
+                    supportedSceneModes +=
+                        CameraParameters::SCENE_MODE_BEACH;
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_SNOW:
+                    supportedSceneModes +=
+                        CameraParameters::SCENE_MODE_SNOW;
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_SUNSET:
+                    supportedSceneModes +=
+                        CameraParameters::SCENE_MODE_SUNSET;
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_STEADYPHOTO:
+                    supportedSceneModes +=
+                        CameraParameters::SCENE_MODE_STEADYPHOTO;
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_FIREWORKS:
+                    supportedSceneModes +=
+                        CameraParameters::SCENE_MODE_FIREWORKS;
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_SPORTS:
+                    supportedSceneModes +=
+                        CameraParameters::SCENE_MODE_SPORTS;
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_PARTY:
+                    supportedSceneModes +=
+                        CameraParameters::SCENE_MODE_PARTY;
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_CANDLELIGHT:
+                    supportedSceneModes +=
+                        CameraParameters::SCENE_MODE_CANDLELIGHT;
+                    break;
+                case ANDROID_CONTROL_SCENE_MODE_BARCODE:
+                    supportedSceneModes +=
+                        CameraParameters::SCENE_MODE_BARCODE;
+                    break;
+                default:
+                    ALOGW("%s: Camera %d: Unknown scene mode value: %d",
+                        __FUNCTION__, mCameraId,
+                            availableSceneModes.data.u8[i]);
+                    addComma = false;
+                    break;
+            }
+        }
+        if (!noSceneModes) {
+            params.set(CameraParameters::KEY_SUPPORTED_SCENE_MODES,
+                    supportedSceneModes);
+        }
+    }
+
+    camera_metadata_entry_t flashAvailable =
+        staticInfo(ANDROID_FLASH_AVAILABLE, 1, 1);
+    if (!flashAvailable.count) return NO_INIT;
+
+    camera_metadata_entry_t availableAeModes =
+        staticInfo(ANDROID_CONTROL_AE_AVAILABLE_MODES);
+    if (!availableAeModes.count) return NO_INIT;
+
+    if (flashAvailable.data.u8[0]) {
+        k.mParameters.flashMode = Parameters::FLASH_MODE_AUTO;
+        params.set(CameraParameters::KEY_FLASH_MODE,
+                CameraParameters::FLASH_MODE_AUTO);
+
+        String8 supportedFlashModes(CameraParameters::FLASH_MODE_OFF);
+        supportedFlashModes = supportedFlashModes +
+            "," + CameraParameters::FLASH_MODE_AUTO +
+            "," + CameraParameters::FLASH_MODE_ON +
+            "," + CameraParameters::FLASH_MODE_TORCH;
+        for (size_t i=0; i < availableAeModes.count; i++) {
+            if (availableAeModes.data.u8[i] ==
+                    ANDROID_CONTROL_AE_ON_AUTO_FLASH_REDEYE) {
+                supportedFlashModes = supportedFlashModes + "," +
+                    CameraParameters::FLASH_MODE_RED_EYE;
+                break;
+            }
+        }
+        params.set(CameraParameters::KEY_SUPPORTED_FLASH_MODES,
+                supportedFlashModes);
+    } else {
+        k.mParameters.flashMode = Parameters::FLASH_MODE_OFF;
+        params.set(CameraParameters::KEY_FLASH_MODE,
+                CameraParameters::FLASH_MODE_OFF);
+        params.set(CameraParameters::KEY_SUPPORTED_FLASH_MODES,
+                CameraParameters::FLASH_MODE_OFF);
+    }
+
+    camera_metadata_entry_t minFocusDistance =
+        staticInfo(ANDROID_LENS_MINIMUM_FOCUS_DISTANCE, 1, 1);
+    if (!minFocusDistance.count) return NO_INIT;
+
+    camera_metadata_entry_t availableAfModes =
+        staticInfo(ANDROID_CONTROL_AF_AVAILABLE_MODES);
+    if (!availableAfModes.count) return NO_INIT;
+
+    if (minFocusDistance.data.f[0] == 0) {
+        // Fixed-focus lens
+        k.mParameters.focusMode = Parameters::FOCUS_MODE_FIXED;
+        params.set(CameraParameters::KEY_FOCUS_MODE,
+                CameraParameters::FOCUS_MODE_FIXED);
+        params.set(CameraParameters::KEY_SUPPORTED_FOCUS_MODES,
+                CameraParameters::FOCUS_MODE_FIXED);
+    } else {
+        k.mParameters.focusMode = Parameters::FOCUS_MODE_AUTO;
+        params.set(CameraParameters::KEY_FOCUS_MODE,
+                CameraParameters::FOCUS_MODE_AUTO);
+        String8 supportedFocusModes(CameraParameters::FOCUS_MODE_FIXED);
+        supportedFocusModes = supportedFocusModes + "," +
+            CameraParameters::FOCUS_MODE_INFINITY;
+        bool addComma = true;
+
+        for (size_t i=0; i < availableAfModes.count; i++) {
+            if (addComma) supportedFocusModes += ",";
+            addComma = true;
+            switch (availableAfModes.data.u8[i]) {
+                case ANDROID_CONTROL_AF_AUTO:
+                    supportedFocusModes +=
+                        CameraParameters::FOCUS_MODE_AUTO;
+                    break;
+                case ANDROID_CONTROL_AF_MACRO:
+                    supportedFocusModes +=
+                        CameraParameters::FOCUS_MODE_MACRO;
+                    break;
+                case ANDROID_CONTROL_AF_CONTINUOUS_VIDEO:
+                    supportedFocusModes +=
+                        CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO;
+                    break;
+                case ANDROID_CONTROL_AF_CONTINUOUS_PICTURE:
+                    supportedFocusModes +=
+                        CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE;
+                    break;
+                case ANDROID_CONTROL_AF_EDOF:
+                    supportedFocusModes +=
+                        CameraParameters::FOCUS_MODE_EDOF;
+                    break;
+                // Not supported in old API
+                case ANDROID_CONTROL_AF_OFF:
+                    addComma = false;
+                    break;
+                default:
+                    ALOGW("%s: Camera %d: Unknown AF mode value: %d",
+                        __FUNCTION__, mCameraId, availableAfModes.data.u8[i]);
+                    addComma = false;
+                    break;
+            }
+        }
+        params.set(CameraParameters::KEY_SUPPORTED_FOCUS_MODES,
+                supportedFocusModes);
+    }
+
+    camera_metadata_entry_t max3aRegions =
+        staticInfo(ANDROID_CONTROL_MAX_REGIONS, 1, 1);
+    if (!max3aRegions.count) return NO_INIT;
+
+    params.set(CameraParameters::KEY_MAX_NUM_FOCUS_AREAS,
+            max3aRegions.data.i32[0]);
+    params.set(CameraParameters::KEY_FOCUS_AREAS,
+            "(0,0,0,0,0)");
+    k.mParameters.focusingAreas.clear();
+    k.mParameters.focusingAreas.add(Parameters::Area(0,0,0,0,0));
+
+    camera_metadata_entry_t availableFocalLengths =
+        staticInfo(ANDROID_LENS_AVAILABLE_FOCAL_LENGTHS);
+    if (!availableFocalLengths.count) return NO_INIT;
+
+    float minFocalLength = availableFocalLengths.data.f[0];
+    params.setFloat(CameraParameters::KEY_FOCAL_LENGTH, minFocalLength);
+
+    camera_metadata_entry_t sensorSize =
+        staticInfo(ANDROID_SENSOR_PHYSICAL_SIZE, 2, 2);
+    if (!sensorSize.count) return NO_INIT;
+
+    // The fields of view here assume infinity focus, maximum wide angle
+    float horizFov = 180 / M_PI *
+            2 * atanf(sensorSize.data.f[0] / (2 * minFocalLength));
+    float vertFov  = 180 / M_PI *
+            2 * atanf(sensorSize.data.f[1] / (2 * minFocalLength));
+    params.setFloat(CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE, horizFov);
+    params.setFloat(CameraParameters::KEY_VERTICAL_VIEW_ANGLE, vertFov);
+
+    k.mParameters.exposureCompensation = 0;
+    params.set(CameraParameters::KEY_EXPOSURE_COMPENSATION,
+                k.mParameters.exposureCompensation);
+
+    camera_metadata_entry_t exposureCompensationRange =
+        staticInfo(ANDROID_CONTROL_AE_EXP_COMPENSATION_RANGE, 2, 2);
+    if (!exposureCompensationRange.count) return NO_INIT;
+
+    params.set(CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION,
+            exposureCompensationRange.data.i32[1]);
+    params.set(CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION,
+            exposureCompensationRange.data.i32[0]);
+
+    camera_metadata_entry_t exposureCompensationStep =
+        staticInfo(ANDROID_CONTROL_AE_EXP_COMPENSATION_STEP, 1, 1);
+    if (!exposureCompensationStep.count) return NO_INIT;
+
+    params.setFloat(CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP,
+            exposureCompensationStep.data.r[0].numerator /
+            exposureCompensationStep.data.r[0].denominator);
+
+    k.mParameters.autoExposureLock = false;
+    params.set(CameraParameters::KEY_AUTO_EXPOSURE_LOCK,
+            CameraParameters::FALSE);
+    params.set(CameraParameters::KEY_AUTO_EXPOSURE_LOCK_SUPPORTED,
+            CameraParameters::TRUE);
+
+    k.mParameters.autoWhiteBalanceLock = false;
+    params.set(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK,
+            CameraParameters::FALSE);
+    params.set(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED,
+            CameraParameters::TRUE);
+
+    k.mParameters.meteringAreas.add(Parameters::Area(0, 0, 0, 0, 0));
+    params.set(CameraParameters::KEY_MAX_NUM_METERING_AREAS,
+            max3aRegions.data.i32[0]);
+    params.set(CameraParameters::KEY_METERING_AREAS,
+            "(0,0,0,0,0)");
+
+    k.mParameters.zoom = 0;
+    params.set(CameraParameters::KEY_ZOOM, k.mParameters.zoom);
+    params.set(CameraParameters::KEY_MAX_ZOOM, NUM_ZOOM_STEPS - 1);
+
+    camera_metadata_entry_t maxDigitalZoom =
+        staticInfo(ANDROID_SCALER_AVAILABLE_MAX_ZOOM, 1, 1);
+    if (!maxDigitalZoom.count) return NO_INIT;
+
+    {
+        String8 zoomRatios;
+        float zoom = 1.f;
+        float zoomIncrement = (maxDigitalZoom.data.f[0] - zoom) /
+                (NUM_ZOOM_STEPS-1);
+        bool addComma = false;
+        for (size_t i=0; i < NUM_ZOOM_STEPS; i++) {
+            if (addComma) zoomRatios += ",";
+            addComma = true;
+            zoomRatios += String8::format("%d", static_cast<int>(zoom * 100));
+            zoom += zoomIncrement;
+        }
+        params.set(CameraParameters::KEY_ZOOM_RATIOS, zoomRatios);
+    }
+
+    params.set(CameraParameters::KEY_ZOOM_SUPPORTED,
+            CameraParameters::TRUE);
+    params.set(CameraParameters::KEY_SMOOTH_ZOOM_SUPPORTED,
+            CameraParameters::TRUE);
+
+    params.set(CameraParameters::KEY_FOCUS_DISTANCES,
+            "Infinity,Infinity,Infinity");
+
+    camera_metadata_entry_t maxFacesDetected =
+        staticInfo(ANDROID_STATS_MAX_FACE_COUNT, 1, 1);
+    params.set(CameraParameters::KEY_MAX_NUM_DETECTED_FACES_HW,
+            maxFacesDetected.data.i32[0]);
+    params.set(CameraParameters::KEY_MAX_NUM_DETECTED_FACES_SW,
+            0);
+
+    params.set(CameraParameters::KEY_VIDEO_FRAME_FORMAT,
+            CameraParameters::PIXEL_FORMAT_ANDROID_OPAQUE);
+
+    params.set(CameraParameters::KEY_RECORDING_HINT,
+            CameraParameters::FALSE);
+
+    params.set(CameraParameters::KEY_VIDEO_SNAPSHOT_SUPPORTED,
+            CameraParameters::TRUE);
+
+    params.set(CameraParameters::KEY_VIDEO_STABILIZATION,
+            CameraParameters::FALSE);
+
+    camera_metadata_entry_t availableVideoStabilizationModes =
+        staticInfo(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES);
+    if (!availableVideoStabilizationModes.count) return NO_INIT;
+
+    if (availableVideoStabilizationModes.count > 1) {
+        params.set(CameraParameters::KEY_VIDEO_STABILIZATION_SUPPORTED,
+                CameraParameters::TRUE);
+    } else {
+        params.set(CameraParameters::KEY_VIDEO_STABILIZATION_SUPPORTED,
+                CameraParameters::FALSE);
+    }
+
+    // Always use metadata mode for recording
+    k.mParameters.storeMetadataInBuffers = true;
+
+    k.mParameters.paramsFlattened = params.flatten();
+
+    return OK;
+}
+
+status_t Camera2Client::updatePreviewStream(const Parameters &params) {
+    ATRACE_CALL();
+    status_t res;
+
+    if (mPreviewStreamId != NO_STREAM) {
+        // Check if stream parameters have to change
+        uint32_t currentWidth, currentHeight;
+        res = mDevice->getStreamInfo(mPreviewStreamId,
+                &currentWidth, &currentHeight, 0);
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Error querying preview stream info: "
+                    "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
+            return res;
+        }
+        if (currentWidth != (uint32_t)params.previewWidth ||
+                currentHeight != (uint32_t)params.previewHeight) {
+            ALOGV("%s: Camera %d: Preview size switch: %d x %d -> %d x %d",
+                    __FUNCTION__, mCameraId, currentWidth, currentHeight,
+                    params.previewWidth, params.previewHeight);
+            res = mDevice->waitUntilDrained();
+            if (res != OK) {
+                ALOGE("%s: Camera %d: Error waiting for preview to drain: "
+                        "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
+                return res;
+            }
+            res = mDevice->deleteStream(mPreviewStreamId);
+            if (res != OK) {
+                ALOGE("%s: Camera %d: Unable to delete old output stream "
+                        "for preview: %s (%d)", __FUNCTION__, mCameraId,
+                        strerror(-res), res);
+                return res;
+            }
+            mPreviewStreamId = NO_STREAM;
+        }
+    }
+
+    if (mPreviewStreamId == NO_STREAM) {
+        res = mDevice->createStream(mPreviewWindow,
+                params.previewWidth, params.previewHeight,
+                CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, 0,
+                &mPreviewStreamId);
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Unable to create preview stream: %s (%d)",
+                    __FUNCTION__, mCameraId, strerror(-res), res);
+            return res;
+        }
+    }
+
+    res = mDevice->setStreamTransform(mPreviewStreamId,
+            params.previewTransform);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Unable to set preview stream transform: "
+                "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
+        return res;
+    }
+
+    return OK;
+}
+
+status_t Camera2Client::updatePreviewRequest(const Parameters &params) {
+    ATRACE_CALL();
+    status_t res;
+    if (mPreviewRequest == NULL) {
+        res = mDevice->createDefaultRequest(CAMERA2_TEMPLATE_PREVIEW,
+                &mPreviewRequest);
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Unable to create default preview request: "
+                    "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
+            return res;
+        }
+    }
+
+    res = updateRequestCommon(mPreviewRequest, params);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Unable to update common entries of preview "
+                "request: %s (%d)", __FUNCTION__, mCameraId,
+                strerror(-res), res);
+        return res;
+    }
+
+    return OK;
+}
+
+status_t Camera2Client::updateCaptureStream(const Parameters &params) {
+    ATRACE_CALL();
+    status_t res;
+    // Find out buffer size for JPEG
+    camera_metadata_entry_t maxJpegSize =
+            staticInfo(ANDROID_JPEG_MAX_SIZE);
+    if (maxJpegSize.count == 0) {
+        ALOGE("%s: Camera %d: Can't find ANDROID_JPEG_MAX_SIZE!",
+                __FUNCTION__, mCameraId);
+        return INVALID_OPERATION;
+    }
+
+    if (mCaptureConsumer == 0) {
+        // Create CPU buffer queue endpoint
+        mCaptureConsumer = new CpuConsumer(1);
+        mCaptureConsumer->setFrameAvailableListener(new CaptureWaiter(this));
+        mCaptureConsumer->setName(String8("Camera2Client::CaptureConsumer"));
+        mCaptureWindow = new SurfaceTextureClient(
+            mCaptureConsumer->getProducerInterface());
+        // Create memory for API consumption
+        mCaptureHeap = new Camera2Heap(maxJpegSize.data.i32[0], 1,
+                                       "Camera2Client::CaptureHeap");
+        if (mCaptureHeap->mHeap->getSize() == 0) {
+            ALOGE("%s: Camera %d: Unable to allocate memory for capture",
+                    __FUNCTION__, mCameraId);
+            return NO_MEMORY;
+        }
+    }
+
+    if (mCaptureStreamId != NO_STREAM) {
+        // Check if stream parameters have to change
+        uint32_t currentWidth, currentHeight;
+        res = mDevice->getStreamInfo(mCaptureStreamId,
+                &currentWidth, &currentHeight, 0);
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Error querying capture output stream info: "
+                    "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
+            return res;
+        }
+        if (currentWidth != (uint32_t)params.pictureWidth ||
+                currentHeight != (uint32_t)params.pictureHeight) {
+            res = mDevice->deleteStream(mCaptureStreamId);
+            if (res != OK) {
+                ALOGE("%s: Camera %d: Unable to delete old output stream "
+                        "for capture: %s (%d)", __FUNCTION__, mCameraId,
+                        strerror(-res), res);
+                return res;
+            }
+            mCaptureStreamId = NO_STREAM;
+        }
+    }
+
+    if (mCaptureStreamId == NO_STREAM) {
+        // Create stream for HAL production
+        res = mDevice->createStream(mCaptureWindow,
+                params.pictureWidth, params.pictureHeight,
+                HAL_PIXEL_FORMAT_BLOB, maxJpegSize.data.i32[0],
+                &mCaptureStreamId);
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Can't create output stream for capture: "
+                    "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
+            return res;
+        }
+
+    }
+    return OK;
+}
+
+status_t Camera2Client::updateCaptureRequest(const Parameters &params) {
+    ATRACE_CALL();
+    status_t res;
+    if (mCaptureRequest == NULL) {
+        res = mDevice->createDefaultRequest(CAMERA2_TEMPLATE_STILL_CAPTURE,
+                &mCaptureRequest);
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Unable to create default still image request:"
+                    " %s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
+            return res;
+        }
+    }
+
+    res = updateRequestCommon(mCaptureRequest, params);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Unable to update common entries of capture "
+                "request: %s (%d)", __FUNCTION__, mCameraId,
+                strerror(-res), res);
+        return res;
+    }
+
+    res = updateEntry(mCaptureRequest,
+            ANDROID_JPEG_THUMBNAIL_SIZE,
+            params.jpegThumbSize, 2);
+    if (res != OK) return res;
+    res = updateEntry(mCaptureRequest,
+            ANDROID_JPEG_THUMBNAIL_QUALITY,
+            &params.jpegThumbQuality, 1);
+    if (res != OK) return res;
+    res = updateEntry(mCaptureRequest,
+            ANDROID_JPEG_QUALITY,
+            &params.jpegQuality, 1);
+    if (res != OK) return res;
+    res = updateEntry(mCaptureRequest,
+            ANDROID_JPEG_ORIENTATION,
+            &params.jpegRotation, 1);
+    if (res != OK) return res;
+
+    if (params.gpsEnabled) {
+        res = updateEntry(mCaptureRequest,
+                ANDROID_JPEG_GPS_COORDINATES,
+                params.gpsCoordinates, 3);
+        if (res != OK) return res;
+        res = updateEntry(mCaptureRequest,
+                ANDROID_JPEG_GPS_TIMESTAMP,
+                &params.gpsTimestamp, 1);
+        if (res != OK) return res;
+        res = updateEntry(mCaptureRequest,
+                ANDROID_JPEG_GPS_PROCESSING_METHOD,
+                params.gpsProcessingMethod.string(),
+                params.gpsProcessingMethod.size());
+        if (res != OK) return res;
+    } else {
+        res = deleteEntry(mCaptureRequest,
+                ANDROID_JPEG_GPS_COORDINATES);
+        if (res != OK) return res;
+        res = deleteEntry(mCaptureRequest,
+                ANDROID_JPEG_GPS_TIMESTAMP);
+        if (res != OK) return res;
+        res = deleteEntry(mCaptureRequest,
+                ANDROID_JPEG_GPS_PROCESSING_METHOD);
+        if (res != OK) return res;
+    }
+
+    return OK;
+}
+
+status_t Camera2Client::updateRecordingRequest(const Parameters &params) {
+    ATRACE_CALL();
+    status_t res;
+    if (mRecordingRequest == NULL) {
+        res = mDevice->createDefaultRequest(CAMERA2_TEMPLATE_VIDEO_RECORD,
+                &mRecordingRequest);
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Unable to create default recording request:"
+                    " %s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
+            return res;
+        }
+    }
+
+    res = updateRequestCommon(mRecordingRequest, params);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Unable to update common entries of recording "
+                "request: %s (%d)", __FUNCTION__, mCameraId,
+                strerror(-res), res);
+        return res;
+    }
+
+    return OK;
+}
+
+status_t Camera2Client::updateRecordingStream(const Parameters &params) {
+    status_t res;
+
+    if (mRecordingConsumer == 0) {
+        // Create CPU buffer queue endpoint
+        mRecordingConsumer = new MediaConsumer(kRecordingHeapCount);
+        mRecordingConsumer->setFrameAvailableListener(new RecordingWaiter(this));
+        mRecordingConsumer->setName(String8("Camera2Client::RecordingConsumer"));
+        mRecordingWindow = new SurfaceTextureClient(
+            mRecordingConsumer->getProducerInterface());
+        // Allocate memory later, since we don't know buffer size until receipt
+    }
+
+    if (mRecordingStreamId != NO_STREAM) {
+        // Check if stream parameters have to change
+        uint32_t currentWidth, currentHeight;
+        res = mDevice->getStreamInfo(mRecordingStreamId,
+                &currentWidth, &currentHeight, 0);
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Error querying recording output stream info: "
+                    "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
+            return res;
+        }
+        if (currentWidth != (uint32_t)params.videoWidth ||
+                currentHeight != (uint32_t)params.videoHeight) {
+            // TODO: Should wait to be sure previous recording has finished
+            res = mDevice->deleteStream(mRecordingStreamId);
+            if (res != OK) {
+                ALOGE("%s: Camera %d: Unable to delete old output stream "
+                        "for recording: %s (%d)", __FUNCTION__, mCameraId,
+                        strerror(-res), res);
+                return res;
+            }
+            mRecordingStreamId = NO_STREAM;
+        }
+    }
+
+    if (mRecordingStreamId == NO_STREAM) {
+        res = mDevice->createStream(mRecordingWindow,
+                params.videoWidth, params.videoHeight,
+                CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, 0, &mRecordingStreamId);
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Can't create output stream for recording: "
+                    "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
+            return res;
+        }
+    }
+
+    return OK;
+}
+
+status_t Camera2Client::updateRequestCommon(camera_metadata_t *request,
+        const Parameters &params) {
+    ATRACE_CALL();
+    status_t res;
+    res = updateEntry(request,
+            ANDROID_CONTROL_AE_TARGET_FPS_RANGE, params.previewFpsRange, 2);
+    if (res != OK) return res;
+
+    uint8_t wbMode = params.autoWhiteBalanceLock ?
+            ANDROID_CONTROL_AWB_LOCKED : params.wbMode;
+    res = updateEntry(request,
+            ANDROID_CONTROL_AWB_MODE, &wbMode, 1);
+    if (res != OK) return res;
+    res = updateEntry(request,
+            ANDROID_CONTROL_EFFECT_MODE, &params.effectMode, 1);
+    if (res != OK) return res;
+    res = updateEntry(request,
+            ANDROID_CONTROL_AE_ANTIBANDING_MODE,
+            &params.antibandingMode, 1);
+    if (res != OK) return res;
+
+    uint8_t controlMode =
+            (params.sceneMode == ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED) ?
+            ANDROID_CONTROL_AUTO : ANDROID_CONTROL_USE_SCENE_MODE;
+    res = updateEntry(request,
+            ANDROID_CONTROL_MODE, &controlMode, 1);
+    if (res != OK) return res;
+    if (controlMode == ANDROID_CONTROL_USE_SCENE_MODE) {
+        res = updateEntry(request,
+                ANDROID_CONTROL_SCENE_MODE,
+                &params.sceneMode, 1);
+        if (res != OK) return res;
+    }
+
+    uint8_t flashMode = ANDROID_FLASH_OFF;
+    uint8_t aeMode;
+    switch (params.flashMode) {
+        case Parameters::FLASH_MODE_OFF:
+            aeMode = ANDROID_CONTROL_AE_ON; break;
+        case Parameters::FLASH_MODE_AUTO:
+            aeMode = ANDROID_CONTROL_AE_ON_AUTO_FLASH; break;
+        case Parameters::FLASH_MODE_ON:
+            aeMode = ANDROID_CONTROL_AE_ON_ALWAYS_FLASH; break;
+        case Parameters::FLASH_MODE_TORCH:
+            aeMode = ANDROID_CONTROL_AE_ON;
+            flashMode = ANDROID_FLASH_TORCH;
+            break;
+        case Parameters::FLASH_MODE_RED_EYE:
+            aeMode = ANDROID_CONTROL_AE_ON_AUTO_FLASH_REDEYE; break;
+        default:
+            ALOGE("%s: Camera %d: Unknown flash mode %d", __FUNCTION__,
+                    mCameraId, params.flashMode);
+            return BAD_VALUE;
+    }
+    if (params.autoExposureLock) aeMode = ANDROID_CONTROL_AE_LOCKED;
+
+    res = updateEntry(request,
+            ANDROID_FLASH_MODE, &flashMode, 1);
+    if (res != OK) return res;
+    res = updateEntry(request,
+            ANDROID_CONTROL_AE_MODE, &aeMode, 1);
+    if (res != OK) return res;
+
+    float focusDistance = 0; // infinity focus in diopters
+    uint8_t focusMode;
+    switch (params.focusMode) {
+        case Parameters::FOCUS_MODE_AUTO:
+        case Parameters::FOCUS_MODE_MACRO:
+        case Parameters::FOCUS_MODE_CONTINUOUS_VIDEO:
+        case Parameters::FOCUS_MODE_CONTINUOUS_PICTURE:
+        case Parameters::FOCUS_MODE_EDOF:
+            focusMode = params.focusMode;
+            break;
+        case Parameters::FOCUS_MODE_INFINITY:
+        case Parameters::FOCUS_MODE_FIXED:
+            focusMode = ANDROID_CONTROL_AF_OFF;
+            break;
+        default:
+            ALOGE("%s: Camera %d: Unknown focus mode %d", __FUNCTION__,
+                    mCameraId, params.focusMode);
+            return BAD_VALUE;
+    }
+    res = updateEntry(request,
+            ANDROID_LENS_FOCUS_DISTANCE, &focusDistance, 1);
+    if (res != OK) return res;
+    res = updateEntry(request,
+            ANDROID_CONTROL_AF_MODE, &focusMode, 1);
+    if (res != OK) return res;
+
+    size_t focusingAreasSize = params.focusingAreas.size() * 5;
+    int32_t *focusingAreas = new int32_t[focusingAreasSize];
+    for (size_t i = 0; i < focusingAreasSize; i += 5) {
+        focusingAreas[i + 0] = params.focusingAreas[i].left;
+        focusingAreas[i + 1] = params.focusingAreas[i].top;
+        focusingAreas[i + 2] = params.focusingAreas[i].right;
+        focusingAreas[i + 3] = params.focusingAreas[i].bottom;
+        focusingAreas[i + 4] = params.focusingAreas[i].weight;
+    }
+    res = updateEntry(request,
+            ANDROID_CONTROL_AF_REGIONS, focusingAreas,focusingAreasSize);
+    if (res != OK) return res;
+    delete[] focusingAreas;
+
+    res = updateEntry(request,
+            ANDROID_CONTROL_AE_EXP_COMPENSATION,
+            &params.exposureCompensation, 1);
+    if (res != OK) return res;
+
+    size_t meteringAreasSize = params.meteringAreas.size() * 5;
+    int32_t *meteringAreas = new int32_t[meteringAreasSize];
+    for (size_t i = 0; i < meteringAreasSize; i += 5) {
+        meteringAreas[i + 0] = params.meteringAreas[i].left;
+        meteringAreas[i + 1] = params.meteringAreas[i].top;
+        meteringAreas[i + 2] = params.meteringAreas[i].right;
+        meteringAreas[i + 3] = params.meteringAreas[i].bottom;
+        meteringAreas[i + 4] = params.meteringAreas[i].weight;
+    }
+    res = updateEntry(request,
+            ANDROID_CONTROL_AE_REGIONS, meteringAreas, meteringAreasSize);
+    if (res != OK) return res;
+
+    res = updateEntry(request,
+            ANDROID_CONTROL_AWB_REGIONS, meteringAreas, meteringAreasSize);
+    if (res != OK) return res;
+    delete[] meteringAreas;
+
+    // Need to convert zoom index into a crop rectangle. The rectangle is
+    // chosen to maximize its area on the sensor
+
+    camera_metadata_entry_t maxDigitalZoom =
+            staticInfo(ANDROID_SCALER_AVAILABLE_MAX_ZOOM);
+    float zoomIncrement = (maxDigitalZoom.data.f[0] - 1) /
+            (NUM_ZOOM_STEPS-1);
+    float zoomRatio = 1 + zoomIncrement * params.zoom;
+
+    camera_metadata_entry_t activePixelArraySize =
+            staticInfo(ANDROID_SENSOR_ACTIVE_ARRAY_SIZE, 2, 2);
+    int32_t arrayWidth = activePixelArraySize.data.i32[0];
+    int32_t arrayHeight = activePixelArraySize.data.i32[1];
+    float zoomLeft, zoomTop, zoomWidth, zoomHeight;
+    if (params.previewWidth >= params.previewHeight) {
+        zoomWidth =  arrayWidth / zoomRatio;
+        zoomHeight = zoomWidth *
+                params.previewHeight / params.previewWidth;
+    } else {
+        zoomHeight = arrayHeight / zoomRatio;
+        zoomWidth = zoomHeight *
+                params.previewWidth / params.previewHeight;
+    }
+    zoomLeft = (arrayWidth - zoomWidth) / 2;
+    zoomTop = (arrayHeight - zoomHeight) / 2;
+
+    int32_t cropRegion[3] = { zoomLeft, zoomTop, zoomWidth };
+    res = updateEntry(request,
+            ANDROID_SCALER_CROP_REGION, cropRegion, 3);
+    if (res != OK) return res;
+
+    // TODO: Decide how to map recordingHint, or whether just to ignore it
+
+    uint8_t vstabMode = params.videoStabilization ?
+            ANDROID_CONTROL_VIDEO_STABILIZATION_ON :
+            ANDROID_CONTROL_VIDEO_STABILIZATION_OFF;
+    res = updateEntry(request,
+            ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
+            &vstabMode, 1);
+    if (res != OK) return res;
+
+    return OK;
+}
+
+status_t Camera2Client::updateEntry(camera_metadata_t *buffer,
+        uint32_t tag, const void *data, size_t data_count) {
+    camera_metadata_entry_t entry;
+    status_t res;
+    res = find_camera_metadata_entry(buffer, tag, &entry);
+    if (res == NAME_NOT_FOUND) {
+        res = add_camera_metadata_entry(buffer,
+                tag, data, data_count);
+    } else if (res == OK) {
+        res = update_camera_metadata_entry(buffer,
+                entry.index, data, data_count, NULL);
+    }
+
+    if (res != OK) {
+        ALOGE("%s: Unable to update metadata entry %s.%s (%x): %s (%d)",
+                __FUNCTION__, get_camera_metadata_section_name(tag),
+                get_camera_metadata_tag_name(tag), tag, strerror(-res), res);
+    }
+    return res;
+}
+
+status_t Camera2Client::deleteEntry(camera_metadata_t *buffer, uint32_t tag) {
+    camera_metadata_entry_t entry;
+    status_t res;
+    res = find_camera_metadata_entry(buffer, tag, &entry);
+    if (res == NAME_NOT_FOUND) {
+        return OK;
+    } else if (res != OK) {
+        ALOGE("%s: Error looking for entry %s.%s (%x): %s %d",
+                __FUNCTION__,
+                get_camera_metadata_section_name(tag),
+                get_camera_metadata_tag_name(tag), tag, strerror(-res), res);
+        return res;
+    }
+    res = delete_camera_metadata_entry(buffer, entry.index);
+    if (res != OK) {
+        ALOGE("%s: Error deleting entry %s.%s (%x): %s %d",
+                __FUNCTION__,
+                get_camera_metadata_section_name(tag),
+                get_camera_metadata_tag_name(tag), tag, strerror(-res), res);
+    }
+    return res;
+}
+
+int Camera2Client::formatStringToEnum(const char *format) {
+    return
+        !strcmp(format, CameraParameters::PIXEL_FORMAT_YUV422SP) ?
+            HAL_PIXEL_FORMAT_YCbCr_422_SP : // NV16
+        !strcmp(format, CameraParameters::PIXEL_FORMAT_YUV420SP) ?
+            HAL_PIXEL_FORMAT_YCrCb_420_SP : // NV21
+        !strcmp(format, CameraParameters::PIXEL_FORMAT_YUV422I) ?
+            HAL_PIXEL_FORMAT_YCbCr_422_I :  // YUY2
+        !strcmp(format, CameraParameters::PIXEL_FORMAT_YUV420P) ?
+            HAL_PIXEL_FORMAT_YV12 :         // YV12
+        !strcmp(format, CameraParameters::PIXEL_FORMAT_RGB565) ?
+            HAL_PIXEL_FORMAT_RGB_565 :      // RGB565
+        !strcmp(format, CameraParameters::PIXEL_FORMAT_RGBA8888) ?
+            HAL_PIXEL_FORMAT_RGBA_8888 :    // RGB8888
+        !strcmp(format, CameraParameters::PIXEL_FORMAT_BAYER_RGGB) ?
+            HAL_PIXEL_FORMAT_RAW_SENSOR :   // Raw sensor data
+        -1;
+}
+
+const char* Camera2Client::formatEnumToString(int format) {
+    const char *fmt;
+    switch(format) {
+        case HAL_PIXEL_FORMAT_YCbCr_422_SP: // NV16
+            fmt = CameraParameters::PIXEL_FORMAT_YUV422SP;
+            break;
+        case HAL_PIXEL_FORMAT_YCrCb_420_SP: // NV21
+            fmt = CameraParameters::PIXEL_FORMAT_YUV420SP;
+            break;
+        case HAL_PIXEL_FORMAT_YCbCr_422_I: // YUY2
+            fmt = CameraParameters::PIXEL_FORMAT_YUV422I;
+            break;
+        case HAL_PIXEL_FORMAT_YV12:        // YV12
+            fmt = CameraParameters::PIXEL_FORMAT_YUV420P;
+            break;
+        case HAL_PIXEL_FORMAT_RGB_565:     // RGB565
+            fmt = CameraParameters::PIXEL_FORMAT_RGB565;
+            break;
+        case HAL_PIXEL_FORMAT_RGBA_8888:   // RGBA8888
+            fmt = CameraParameters::PIXEL_FORMAT_RGBA8888;
+            break;
+        case HAL_PIXEL_FORMAT_RAW_SENSOR:
+            ALOGW("Raw sensor preview format requested.");
+            fmt = CameraParameters::PIXEL_FORMAT_BAYER_RGGB;
+            break;
+        default:
+            ALOGE("%s: Unknown preview format: %x",
+                    __FUNCTION__,  format);
+            fmt = NULL;
+            break;
+    }
+    return fmt;
+}
+
+int Camera2Client::wbModeStringToEnum(const char *wbMode) {
+    return
+        !strcmp(wbMode, CameraParameters::WHITE_BALANCE_AUTO) ?
+            ANDROID_CONTROL_AWB_AUTO :
+        !strcmp(wbMode, CameraParameters::WHITE_BALANCE_INCANDESCENT) ?
+            ANDROID_CONTROL_AWB_INCANDESCENT :
+        !strcmp(wbMode, CameraParameters::WHITE_BALANCE_FLUORESCENT) ?
+            ANDROID_CONTROL_AWB_FLUORESCENT :
+        !strcmp(wbMode, CameraParameters::WHITE_BALANCE_WARM_FLUORESCENT) ?
+            ANDROID_CONTROL_AWB_WARM_FLUORESCENT :
+        !strcmp(wbMode, CameraParameters::WHITE_BALANCE_DAYLIGHT) ?
+            ANDROID_CONTROL_AWB_DAYLIGHT :
+        !strcmp(wbMode, CameraParameters::WHITE_BALANCE_CLOUDY_DAYLIGHT) ?
+            ANDROID_CONTROL_AWB_CLOUDY_DAYLIGHT :
+        !strcmp(wbMode, CameraParameters::WHITE_BALANCE_TWILIGHT) ?
+            ANDROID_CONTROL_AWB_TWILIGHT :
+        !strcmp(wbMode, CameraParameters::WHITE_BALANCE_SHADE) ?
+            ANDROID_CONTROL_AWB_SHADE :
+        -1;
+}
+
+int Camera2Client::effectModeStringToEnum(const char *effectMode) {
+    return
+        !strcmp(effectMode, CameraParameters::EFFECT_NONE) ?
+            ANDROID_CONTROL_EFFECT_OFF :
+        !strcmp(effectMode, CameraParameters::EFFECT_MONO) ?
+            ANDROID_CONTROL_EFFECT_MONO :
+        !strcmp(effectMode, CameraParameters::EFFECT_NEGATIVE) ?
+            ANDROID_CONTROL_EFFECT_NEGATIVE :
+        !strcmp(effectMode, CameraParameters::EFFECT_SOLARIZE) ?
+            ANDROID_CONTROL_EFFECT_SOLARIZE :
+        !strcmp(effectMode, CameraParameters::EFFECT_SEPIA) ?
+            ANDROID_CONTROL_EFFECT_SEPIA :
+        !strcmp(effectMode, CameraParameters::EFFECT_POSTERIZE) ?
+            ANDROID_CONTROL_EFFECT_POSTERIZE :
+        !strcmp(effectMode, CameraParameters::EFFECT_WHITEBOARD) ?
+            ANDROID_CONTROL_EFFECT_WHITEBOARD :
+        !strcmp(effectMode, CameraParameters::EFFECT_BLACKBOARD) ?
+            ANDROID_CONTROL_EFFECT_BLACKBOARD :
+        !strcmp(effectMode, CameraParameters::EFFECT_AQUA) ?
+            ANDROID_CONTROL_EFFECT_AQUA :
+        -1;
+}
+
+int Camera2Client::abModeStringToEnum(const char *abMode) {
+    return
+        !strcmp(abMode, CameraParameters::ANTIBANDING_AUTO) ?
+            ANDROID_CONTROL_AE_ANTIBANDING_AUTO :
+        !strcmp(abMode, CameraParameters::ANTIBANDING_OFF) ?
+            ANDROID_CONTROL_AE_ANTIBANDING_OFF :
+        !strcmp(abMode, CameraParameters::ANTIBANDING_50HZ) ?
+            ANDROID_CONTROL_AE_ANTIBANDING_50HZ :
+        !strcmp(abMode, CameraParameters::ANTIBANDING_60HZ) ?
+            ANDROID_CONTROL_AE_ANTIBANDING_60HZ :
+        -1;
+}
+
+int Camera2Client::sceneModeStringToEnum(const char *sceneMode) {
+    return
+        !strcmp(sceneMode, CameraParameters::SCENE_MODE_AUTO) ?
+            ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED :
+        !strcmp(sceneMode, CameraParameters::SCENE_MODE_ACTION) ?
+            ANDROID_CONTROL_SCENE_MODE_ACTION :
+        !strcmp(sceneMode, CameraParameters::SCENE_MODE_PORTRAIT) ?
+            ANDROID_CONTROL_SCENE_MODE_PORTRAIT :
+        !strcmp(sceneMode, CameraParameters::SCENE_MODE_LANDSCAPE) ?
+            ANDROID_CONTROL_SCENE_MODE_LANDSCAPE :
+        !strcmp(sceneMode, CameraParameters::SCENE_MODE_NIGHT) ?
+            ANDROID_CONTROL_SCENE_MODE_NIGHT :
+        !strcmp(sceneMode, CameraParameters::SCENE_MODE_NIGHT_PORTRAIT) ?
+            ANDROID_CONTROL_SCENE_MODE_NIGHT_PORTRAIT :
+        !strcmp(sceneMode, CameraParameters::SCENE_MODE_THEATRE) ?
+            ANDROID_CONTROL_SCENE_MODE_THEATRE :
+        !strcmp(sceneMode, CameraParameters::SCENE_MODE_BEACH) ?
+            ANDROID_CONTROL_SCENE_MODE_BEACH :
+        !strcmp(sceneMode, CameraParameters::SCENE_MODE_SNOW) ?
+            ANDROID_CONTROL_SCENE_MODE_SNOW :
+        !strcmp(sceneMode, CameraParameters::SCENE_MODE_SUNSET) ?
+            ANDROID_CONTROL_SCENE_MODE_SUNSET :
+        !strcmp(sceneMode, CameraParameters::SCENE_MODE_STEADYPHOTO) ?
+            ANDROID_CONTROL_SCENE_MODE_STEADYPHOTO :
+        !strcmp(sceneMode, CameraParameters::SCENE_MODE_FIREWORKS) ?
+            ANDROID_CONTROL_SCENE_MODE_FIREWORKS :
+        !strcmp(sceneMode, CameraParameters::SCENE_MODE_SPORTS) ?
+            ANDROID_CONTROL_SCENE_MODE_SPORTS :
+        !strcmp(sceneMode, CameraParameters::SCENE_MODE_PARTY) ?
+            ANDROID_CONTROL_SCENE_MODE_PARTY :
+        !strcmp(sceneMode, CameraParameters::SCENE_MODE_CANDLELIGHT) ?
+            ANDROID_CONTROL_SCENE_MODE_CANDLELIGHT :
+        !strcmp(sceneMode, CameraParameters::SCENE_MODE_BARCODE) ?
+            ANDROID_CONTROL_SCENE_MODE_BARCODE:
+        -1;
+}
+
+Camera2Client::Parameters::flashMode_t Camera2Client::flashModeStringToEnum(
+        const char *flashMode) {
+    return
+        !strcmp(flashMode, CameraParameters::FLASH_MODE_OFF) ?
+            Parameters::FLASH_MODE_OFF :
+        !strcmp(flashMode, CameraParameters::FLASH_MODE_AUTO) ?
+            Parameters::FLASH_MODE_AUTO :
+        !strcmp(flashMode, CameraParameters::FLASH_MODE_ON) ?
+            Parameters::FLASH_MODE_ON :
+        !strcmp(flashMode, CameraParameters::FLASH_MODE_RED_EYE) ?
+            Parameters::FLASH_MODE_RED_EYE :
+        !strcmp(flashMode, CameraParameters::FLASH_MODE_TORCH) ?
+            Parameters::FLASH_MODE_TORCH :
+        Parameters::FLASH_MODE_INVALID;
+}
+
+Camera2Client::Parameters::focusMode_t Camera2Client::focusModeStringToEnum(
+        const char *focusMode) {
+    return
+        !strcmp(focusMode, CameraParameters::FOCUS_MODE_AUTO) ?
+            Parameters::FOCUS_MODE_AUTO :
+        !strcmp(focusMode, CameraParameters::FOCUS_MODE_INFINITY) ?
+            Parameters::FOCUS_MODE_INFINITY :
+        !strcmp(focusMode, CameraParameters::FOCUS_MODE_MACRO) ?
+            Parameters::FOCUS_MODE_MACRO :
+        !strcmp(focusMode, CameraParameters::FOCUS_MODE_FIXED) ?
+            Parameters::FOCUS_MODE_FIXED :
+        !strcmp(focusMode, CameraParameters::FOCUS_MODE_EDOF) ?
+            Parameters::FOCUS_MODE_EDOF :
+        !strcmp(focusMode, CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO) ?
+            Parameters::FOCUS_MODE_CONTINUOUS_VIDEO :
+        !strcmp(focusMode, CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE) ?
+            Parameters::FOCUS_MODE_CONTINUOUS_PICTURE :
+        Parameters::FOCUS_MODE_INVALID;
+}
+
+status_t Camera2Client::parseAreas(const char *areasCStr,
+        Vector<Parameters::Area> *areas) {
+    static const size_t NUM_FIELDS = 5;
+    areas->clear();
+    if (areasCStr == NULL) {
+        // If no key exists, use default (0,0,0,0,0)
+        areas->push();
+        return OK;
+    }
+    String8 areasStr(areasCStr);
+    ssize_t areaStart = areasStr.find("(", 0) + 1;
+    while (areaStart != 0) {
+        const char* area = areasStr.string() + areaStart;
+        char *numEnd;
+        int vals[NUM_FIELDS];
+        for (size_t i = 0; i < NUM_FIELDS; i++) {
+            errno = 0;
+            vals[i] = strtol(area, &numEnd, 10);
+            if (errno || numEnd == area) return BAD_VALUE;
+            area = numEnd + 1;
+        }
+        areas->push(Parameters::Area(
+            vals[0], vals[1], vals[2], vals[3], vals[4]) );
+        areaStart = areasStr.find("(", areaStart) + 1;
+    }
+    return OK;
+}
+
+status_t Camera2Client::validateAreas(const Vector<Parameters::Area> &areas,
+                                      size_t maxRegions) {
+    // Definition of valid area can be found in
+    // include/camera/CameraParameters.h
+    if (areas.size() == 0) return BAD_VALUE;
+    if (areas.size() == 1) {
+        if (areas[0].left == 0 &&
+                areas[0].top == 0 &&
+                areas[0].right == 0 &&
+                areas[0].bottom == 0 &&
+                areas[0].weight == 0) {
+            // Single (0,0,0,0,0) entry is always valid (== driver decides)
+            return OK;
+        }
+    }
+    if (areas.size() > maxRegions) {
+        ALOGE("%s: Too many areas requested: %d",
+                __FUNCTION__, areas.size());
+        return BAD_VALUE;
+    }
+
+    for (Vector<Parameters::Area>::const_iterator a = areas.begin();
+         a != areas.end(); a++) {
+        if (a->weight < 1 || a->weight > 1000) return BAD_VALUE;
+        if (a->left < -1000 || a->left > 1000) return BAD_VALUE;
+        if (a->top < -1000 || a->top > 1000) return BAD_VALUE;
+        if (a->right < -1000 || a->right > 1000) return BAD_VALUE;
+        if (a->bottom < -1000 || a->bottom > 1000) return BAD_VALUE;
+        if (a->left >= a->right) return BAD_VALUE;
+        if (a->top >= a->bottom) return BAD_VALUE;
+    }
+    return OK;
+}
+
+bool Camera2Client::boolFromString(const char *boolStr) {
+    return !boolStr ? false :
+        !strcmp(boolStr, CameraParameters::TRUE) ? true :
+        false;
+}
+
+int Camera2Client::degToTransform(int degrees, bool mirror) {
+    if (!mirror) {
+        if (degrees == 0) return 0;
+        else if (degrees == 90) return HAL_TRANSFORM_ROT_90;
+        else if (degrees == 180) return HAL_TRANSFORM_ROT_180;
+        else if (degrees == 270) return HAL_TRANSFORM_ROT_270;
+    } else {  // Do mirror (horizontal flip)
+        if (degrees == 0) {           // FLIP_H and ROT_0
+            return HAL_TRANSFORM_FLIP_H;
+        } else if (degrees == 90) {   // FLIP_H and ROT_90
+            return HAL_TRANSFORM_FLIP_H | HAL_TRANSFORM_ROT_90;
+        } else if (degrees == 180) {  // FLIP_H and ROT_180
+            return HAL_TRANSFORM_FLIP_V;
+        } else if (degrees == 270) {  // FLIP_H and ROT_270
+            return HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_ROT_90;
+        }
+    }
+    ALOGE("%s: Bad input: %d", __FUNCTION__, degrees);
+    return -1;
+}
+
+} // namespace android
diff --git a/services/camera/libcameraservice/Camera2Client.h b/services/camera/libcameraservice/Camera2Client.h
new file mode 100644
index 0000000..3494114
--- /dev/null
+++ b/services/camera/libcameraservice/Camera2Client.h
@@ -0,0 +1,377 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SERVERS_CAMERA_CAMERA2CLIENT_H
+#define ANDROID_SERVERS_CAMERA_CAMERA2CLIENT_H
+
+#include "Camera2Device.h"
+#include "CameraService.h"
+#include "camera/CameraParameters.h"
+#include <binder/MemoryBase.h>
+#include <binder/MemoryHeapBase.h>
+#include <gui/CpuConsumer.h>
+#include "MediaConsumer.h"
+
+namespace android {
+
+/**
+ * Implements the android.hardware.camera API on top of
+ * camera device HAL version 2.
+ */
+class Camera2Client : public CameraService::Client
+{
+public:
+    // ICamera interface (see ICamera for details)
+    virtual void            disconnect();
+    virtual status_t        connect(const sp<ICameraClient>& client);
+    virtual status_t        lock();
+    virtual status_t        unlock();
+    virtual status_t        setPreviewDisplay(const sp<Surface>& surface);
+    virtual status_t        setPreviewTexture(
+        const sp<ISurfaceTexture>& surfaceTexture);
+    virtual void            setPreviewCallbackFlag(int flag);
+    virtual status_t        startPreview();
+    virtual void            stopPreview();
+    virtual bool            previewEnabled();
+    virtual status_t        storeMetaDataInBuffers(bool enabled);
+    virtual status_t        startRecording();
+    virtual void            stopRecording();
+    virtual bool            recordingEnabled();
+    virtual void            releaseRecordingFrame(const sp<IMemory>& mem);
+    virtual status_t        autoFocus();
+    virtual status_t        cancelAutoFocus();
+    virtual status_t        takePicture(int msgType);
+    virtual status_t        setParameters(const String8& params);
+    virtual String8         getParameters() const;
+    virtual status_t        sendCommand(int32_t cmd, int32_t arg1, int32_t arg2);
+
+    // Interface used by CameraService
+    Camera2Client(const sp<CameraService>& cameraService,
+            const sp<ICameraClient>& cameraClient,
+            int cameraId,
+            int cameraFacing,
+            int clientPid);
+    ~Camera2Client();
+
+    status_t initialize(camera_module_t *module);
+
+    virtual status_t dump(int fd, const Vector<String16>& args);
+
+private:
+    enum State {
+        NOT_INITIALIZED,
+        STOPPED,
+        WAITING_FOR_PREVIEW_WINDOW,
+        PREVIEW,
+        RECORD,
+        STILL_CAPTURE,
+        VIDEO_SNAPSHOT
+    } mState;
+
+    static const char *getStateName(State state);
+
+    /** ICamera interface-related private members */
+
+    // Mutex that must be locked by methods implementing the ICamera interface.
+    // Ensures serialization between incoming ICamera calls
+    mutable Mutex mICameraLock;
+
+    // The following must be called with mICameraLock already locked
+
+    status_t setPreviewWindowLocked(const sp<IBinder>& binder,
+            sp<ANativeWindow> window);
+
+    void stopPreviewLocked();
+    status_t startPreviewLocked();
+
+    // Current camera state; this is the contents of the CameraParameters object
+    // in a more-efficient format. The enum values are mostly based off the
+    // corresponding camera2 enums, not the camera1 strings. A few are defined
+    // here if they don't cleanly map to camera2 values.
+    struct Parameters {
+        int previewWidth, previewHeight;
+        int32_t previewFpsRange[2];
+        int previewFps; // deprecated, here only for tracking changes
+        int previewFormat;
+
+        int previewTransform; // set by CAMERA_CMD_SET_DISPLAY_ORIENTATION
+
+        int pictureWidth, pictureHeight;
+
+        int32_t jpegThumbSize[2];
+        int32_t jpegQuality, jpegThumbQuality;
+        int32_t jpegRotation;
+
+        bool gpsEnabled;
+        double gpsCoordinates[3];
+        int64_t gpsTimestamp;
+        String8 gpsProcessingMethod;
+
+        int wbMode;
+        int effectMode;
+        int antibandingMode;
+        int sceneMode;
+
+        enum flashMode_t {
+            FLASH_MODE_OFF = 0,
+            FLASH_MODE_AUTO,
+            FLASH_MODE_ON,
+            FLASH_MODE_TORCH,
+            FLASH_MODE_RED_EYE = ANDROID_CONTROL_AE_ON_AUTO_FLASH_REDEYE,
+            FLASH_MODE_INVALID = -1
+        } flashMode;
+
+        enum focusMode_t {
+            FOCUS_MODE_AUTO = ANDROID_CONTROL_AF_AUTO,
+            FOCUS_MODE_MACRO = ANDROID_CONTROL_AF_MACRO,
+            FOCUS_MODE_CONTINUOUS_VIDEO = ANDROID_CONTROL_AF_CONTINUOUS_VIDEO,
+            FOCUS_MODE_CONTINUOUS_PICTURE =
+                ANDROID_CONTROL_AF_CONTINUOUS_PICTURE,
+            FOCUS_MODE_EDOF = ANDROID_CONTROL_AF_EDOF,
+            FOCUS_MODE_INFINITY,
+            FOCUS_MODE_FIXED,
+            FOCUS_MODE_INVALID = -1
+        } focusMode;
+
+        struct Area {
+            int left, top, right, bottom;
+            int weight;
+            Area() {}
+            Area(int left, int top, int right, int bottom, int weight):
+                    left(left), top(top), right(right), bottom(bottom),
+                    weight(weight) {}
+        };
+        Vector<Area> focusingAreas;
+
+        int32_t exposureCompensation;
+        bool autoExposureLock;
+        bool autoWhiteBalanceLock;
+
+        Vector<Area> meteringAreas;
+
+        int zoom;
+
+        int videoWidth, videoHeight;
+
+        bool recordingHint;
+        bool videoStabilization;
+
+        bool storeMetadataInBuffers;
+
+        String8 paramsFlattened;
+    };
+
+    class LockedParameters {
+      public:
+        class Key {
+          public:
+            Key(LockedParameters &p):
+                    mParameters(p.mParameters),
+                    mLockedParameters(p) {
+                mLockedParameters.mLock.lock();
+            }
+
+            ~Key() {
+                mLockedParameters.mLock.unlock();
+            }
+            Parameters &mParameters;
+          private:
+            // Disallow copying, default construction
+            Key();
+            Key(const Key &);
+            Key &operator=(const Key &);
+            LockedParameters &mLockedParameters;
+        };
+        class ReadKey {
+          public:
+            ReadKey(const LockedParameters &p):
+                    mParameters(p.mParameters),
+                    mLockedParameters(p) {
+                mLockedParameters.mLock.lock();
+            }
+
+            ~ReadKey() {
+                mLockedParameters.mLock.unlock();
+            }
+            const Parameters &mParameters;
+          private:
+            // Disallow copying, default construction
+            ReadKey();
+            ReadKey(const ReadKey &);
+            ReadKey &operator=(const ReadKey &);
+            const LockedParameters &mLockedParameters;
+        };
+
+        // Only use for dumping or other debugging
+        const Parameters &unsafeUnlock() {
+            return mParameters;
+        }
+      private:
+        Parameters mParameters;
+        mutable Mutex mLock;
+
+    } mParameters;
+
+    /** Camera device-related private members */
+
+    class Camera2Heap;
+
+    // Number of zoom steps to simulate
+    static const unsigned int NUM_ZOOM_STEPS = 10;
+    // Used with stream IDs
+    static const int NO_STREAM = -1;
+
+    /* Preview related members */
+
+    int mPreviewStreamId;
+    camera_metadata_t *mPreviewRequest;
+    sp<IBinder> mPreviewSurface;
+    sp<ANativeWindow> mPreviewWindow;
+
+    status_t updatePreviewRequest(const Parameters &params);
+    status_t updatePreviewStream(const Parameters &params);
+
+    /* Still image capture related members */
+
+    int mCaptureStreamId;
+    sp<CpuConsumer>    mCaptureConsumer;
+    sp<ANativeWindow>  mCaptureWindow;
+    // Simple listener that forwards frame available notifications from
+    // a CPU consumer to the capture notification
+    class CaptureWaiter: public CpuConsumer::FrameAvailableListener {
+      public:
+        CaptureWaiter(Camera2Client *parent) : mParent(parent) {}
+        void onFrameAvailable() { mParent->onCaptureAvailable(); }
+      private:
+        Camera2Client *mParent;
+    };
+    sp<CaptureWaiter>  mCaptureWaiter;
+    camera_metadata_t *mCaptureRequest;
+    sp<Camera2Heap>    mCaptureHeap;
+    // Handle captured image buffers
+    void onCaptureAvailable();
+
+    status_t updateCaptureRequest(const Parameters &params);
+    status_t updateCaptureStream(const Parameters &params);
+
+    /* Recording related members */
+
+    int mRecordingStreamId;
+    sp<MediaConsumer>    mRecordingConsumer;
+    sp<ANativeWindow>  mRecordingWindow;
+    // Simple listener that forwards frame available notifications from
+    // a CPU consumer to the recording notification
+    class RecordingWaiter: public MediaConsumer::FrameAvailableListener {
+      public:
+        RecordingWaiter(Camera2Client *parent) : mParent(parent) {}
+        void onFrameAvailable() { mParent->onRecordingFrameAvailable(); }
+      private:
+        Camera2Client *mParent;
+    };
+    sp<RecordingWaiter>  mRecordingWaiter;
+    camera_metadata_t *mRecordingRequest;
+    sp<Camera2Heap> mRecordingHeap;
+
+    // TODO: This needs to be queried from somewhere, or the BufferQueue needs
+    // to be passed all the way to stagefright. Right now, set to a large number
+    // to avoid starvation of the video encoders.
+    static const size_t kRecordingHeapCount = 8;
+    size_t mRecordingHeapHead, mRecordingHeapFree;
+    // Handle new recording image buffers
+    void onRecordingFrameAvailable();
+
+    status_t updateRecordingRequest(const Parameters &params);
+    status_t updateRecordingStream(const Parameters &params);
+
+    /** Camera2Device instance wrapping HAL2 entry */
+
+    sp<Camera2Device> mDevice;
+
+    /** Utility members */
+
+    // Utility class for managing a set of IMemory blocks
+    class Camera2Heap : public RefBase {
+    public:
+        Camera2Heap(size_t buf_size, uint_t num_buffers = 1,
+                const char *name = NULL) :
+                         mBufSize(buf_size),
+                         mNumBufs(num_buffers) {
+            mHeap = new MemoryHeapBase(buf_size * num_buffers, 0, name);
+            mBuffers = new sp<MemoryBase>[mNumBufs];
+            for (uint_t i = 0; i < mNumBufs; i++)
+                mBuffers[i] = new MemoryBase(mHeap,
+                                             i * mBufSize,
+                                             mBufSize);
+        }
+
+        virtual ~Camera2Heap()
+        {
+            delete [] mBuffers;
+        }
+
+        size_t mBufSize;
+        uint_t mNumBufs;
+        sp<MemoryHeapBase> mHeap;
+        sp<MemoryBase> *mBuffers;
+    };
+
+    // Get values for static camera info entry. min/maxCount are used for error
+    // checking the number of values in the entry. 0 for max/minCount means to
+    // do no bounds check in that direction. In case of error, the entry data
+    // pointer is null and the count is 0.
+    camera_metadata_entry_t staticInfo(uint32_t tag,
+            size_t minCount=0, size_t maxCount=0);
+
+    // Convert static camera info from a camera2 device to the
+    // old API parameter map.
+    status_t buildDefaultParameters();
+
+    // Update parameters all requests use, based on mParameters
+    status_t updateRequestCommon(camera_metadata_t *request, const Parameters &params);
+
+    // Update specific metadata entry with new values. Adds entry if it does not
+    // exist, which will invalidate sorting
+    static status_t updateEntry(camera_metadata_t *buffer,
+            uint32_t tag, const void *data, size_t data_count);
+
+    // Remove metadata entry. Will invalidate sorting. If entry does not exist,
+    // does nothing.
+    static status_t deleteEntry(camera_metadata_t *buffer,
+            uint32_t tag);
+
+    // Convert camera1 preview format string to camera2 enum
+    static int formatStringToEnum(const char *format);
+    static const char *formatEnumToString(int format);
+
+    static int wbModeStringToEnum(const char *wbMode);
+    static int effectModeStringToEnum(const char *effectMode);
+    static int abModeStringToEnum(const char *abMode);
+    static int sceneModeStringToEnum(const char *sceneMode);
+    static Parameters::flashMode_t flashModeStringToEnum(const char *flashMode);
+    static Parameters::focusMode_t focusModeStringToEnum(const char *focusMode);
+    static status_t parseAreas(const char *areasCStr,
+            Vector<Parameters::Area> *areas);
+    static status_t validateAreas(const Vector<Parameters::Area> &areas,
+                                  size_t maxRegions);
+    static bool boolFromString(const char *boolStr);
+
+    // Map from camera orientation + facing to gralloc transform enum
+    static int degToTransform(int degrees, bool mirror);
+};
+
+}; // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/Camera2Device.cpp b/services/camera/libcameraservice/Camera2Device.cpp
new file mode 100644
index 0000000..d760313
--- /dev/null
+++ b/services/camera/libcameraservice/Camera2Device.cpp
@@ -0,0 +1,952 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Camera2Device"
+//#define LOG_NDEBUG 0
+//#define LOG_NNDEBUG 0  // Per-frame verbose logging
+
+#ifdef LOG_NNDEBUG
+#define ALOGVV(...) ALOGV(__VA_ARGS__)
+#else
+#define ALOGVV(...) ((void)0)
+#endif
+
+#include <utils/Log.h>
+#include "Camera2Device.h"
+
+namespace android {
+
+Camera2Device::Camera2Device(int id):
+        mId(id),
+        mDevice(NULL)
+{
+    ALOGV("%s: E", __FUNCTION__);
+}
+
+Camera2Device::~Camera2Device()
+{
+    ALOGV("%s: E", __FUNCTION__);
+    if (mDevice) {
+        status_t res;
+        res = mDevice->common.close(&mDevice->common);
+        if (res != OK) {
+            ALOGE("%s: Could not close camera %d: %s (%d)",
+                    __FUNCTION__,
+                    mId, strerror(-res), res);
+        }
+        mDevice = NULL;
+    }
+}
+
+status_t Camera2Device::initialize(camera_module_t *module)
+{
+    ALOGV("%s: E", __FUNCTION__);
+
+    status_t res;
+    char name[10];
+    snprintf(name, sizeof(name), "%d", mId);
+
+    res = module->common.methods->open(&module->common, name,
+            reinterpret_cast<hw_device_t**>(&mDevice));
+
+    if (res != OK) {
+        ALOGE("%s: Could not open camera %d: %s (%d)", __FUNCTION__,
+                mId, strerror(-res), res);
+        return res;
+    }
+
+    if (mDevice->common.version != CAMERA_DEVICE_API_VERSION_2_0) {
+        ALOGE("%s: Could not open camera %d: "
+                "Camera device is not version %x, reports %x instead",
+                __FUNCTION__, mId, CAMERA_DEVICE_API_VERSION_2_0,
+                mDevice->common.version);
+        return BAD_VALUE;
+    }
+
+    camera_info info;
+    res = module->get_camera_info(mId, &info);
+    if (res != OK ) return res;
+
+    if (info.device_version != mDevice->common.version) {
+        ALOGE("%s: HAL reporting mismatched camera_info version (%x)"
+                " and device version (%x).", __FUNCTION__,
+                mDevice->common.version, info.device_version);
+        return BAD_VALUE;
+    }
+
+    mDeviceInfo = info.static_camera_characteristics;
+
+    res = mRequestQueue.setConsumerDevice(mDevice);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Unable to connect request queue to device: %s (%d)",
+                __FUNCTION__, mId, strerror(-res), res);
+        return res;
+    }
+    res = mFrameQueue.setProducerDevice(mDevice);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Unable to connect frame queue to device: %s (%d)",
+                __FUNCTION__, mId, strerror(-res), res);
+        return res;
+    }
+
+    res = mDevice->ops->get_metadata_vendor_tag_ops(mDevice, &mVendorTagOps);
+    if (res != OK ) {
+        ALOGE("%s: Camera %d: Unable to retrieve tag ops from device: %s (%d)",
+                __FUNCTION__, mId, strerror(-res), res);
+        return res;
+    }
+
+    return OK;
+}
+
+status_t Camera2Device::dump(int fd, const Vector<String16>& args) {
+
+    String8 result;
+
+    result.appendFormat("  Camera2Device[%d] dump:\n", mId);
+
+    result.appendFormat("    Static camera information metadata:\n");
+    write(fd, result.string(), result.size());
+    dump_indented_camera_metadata(mDeviceInfo, fd, 2, 6);
+
+    result = "    Request queue contents:\n";
+    write(fd, result.string(), result.size());
+    mRequestQueue.dump(fd, args);
+
+    result = "    Frame queue contents:\n";
+    write(fd, result.string(), result.size());
+    mFrameQueue.dump(fd, args);
+
+    result = "    Active streams:\n";
+    write(fd, result.string(), result.size());
+    for (StreamList::iterator s = mStreams.begin(); s != mStreams.end(); s++) {
+        (*s)->dump(fd, args);
+    }
+
+    result = "    HAL device dump:\n";
+    write(fd, result.string(), result.size());
+
+    status_t res;
+    res = mDevice->ops->dump(mDevice, fd);
+
+    return res;
+}
+
+camera_metadata_t *Camera2Device::info() {
+    ALOGVV("%s: E", __FUNCTION__);
+
+    return mDeviceInfo;
+}
+
+status_t Camera2Device::capture(camera_metadata_t* request) {
+    ALOGV("%s: E", __FUNCTION__);
+
+    mRequestQueue.enqueue(request);
+    return OK;
+}
+
+
+status_t Camera2Device::setStreamingRequest(camera_metadata_t* request) {
+    ALOGV("%s: E", __FUNCTION__);
+
+    mRequestQueue.setStreamSlot(request);
+    return OK;
+}
+
+status_t Camera2Device::createStream(sp<ANativeWindow> consumer,
+        uint32_t width, uint32_t height, int format, size_t size, int *id) {
+    status_t res;
+    ALOGV("%s: E", __FUNCTION__);
+
+    sp<StreamAdapter> stream = new StreamAdapter(mDevice);
+
+    res = stream->connectToDevice(consumer, width, height, format, size);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Unable to create stream (%d x %d, format %x):"
+                "%s (%d)",
+                __FUNCTION__, mId, width, height, format, strerror(-res), res);
+        return res;
+    }
+
+    *id = stream->getId();
+
+    mStreams.push_back(stream);
+    return OK;
+}
+
+status_t Camera2Device::getStreamInfo(int id,
+        uint32_t *width, uint32_t *height, uint32_t *format) {
+    ALOGV("%s: E", __FUNCTION__);
+    bool found = false;
+    StreamList::iterator streamI;
+    for (streamI = mStreams.begin();
+         streamI != mStreams.end(); streamI++) {
+        if ((*streamI)->getId() == id) {
+            found = true;
+            break;
+        }
+    }
+    if (!found) {
+        ALOGE("%s: Camera %d: Stream %d does not exist",
+                __FUNCTION__, mId, id);
+        return BAD_VALUE;
+    }
+
+    if (width) *width = (*streamI)->getWidth();
+    if (height) *height = (*streamI)->getHeight();
+    if (format) *format = (*streamI)->getFormat();
+
+    return OK;
+}
+
+status_t Camera2Device::setStreamTransform(int id,
+        int transform) {
+    ALOGV("%s: E", __FUNCTION__);
+    bool found = false;
+    StreamList::iterator streamI;
+    for (streamI = mStreams.begin();
+         streamI != mStreams.end(); streamI++) {
+        if ((*streamI)->getId() == id) {
+            found = true;
+            break;
+        }
+    }
+    if (!found) {
+        ALOGE("%s: Camera %d: Stream %d does not exist",
+                __FUNCTION__, mId, id);
+        return BAD_VALUE;
+    }
+
+    return (*streamI)->setTransform(transform);
+}
+
+status_t Camera2Device::deleteStream(int id) {
+    ALOGV("%s: E", __FUNCTION__);
+    bool found = false;
+    for (StreamList::iterator streamI = mStreams.begin();
+         streamI != mStreams.end(); streamI++) {
+        if ((*streamI)->getId() == id) {
+            status_t res = (*streamI)->release();
+            if (res != OK) {
+                ALOGE("%s: Unable to release stream %d from HAL device: "
+                        "%s (%d)", __FUNCTION__, id, strerror(-res), res);
+                return res;
+            }
+            mStreams.erase(streamI);
+            found = true;
+            break;
+        }
+    }
+    if (!found) {
+        ALOGE("%s: Camera %d: Unable to find stream %d to delete",
+                __FUNCTION__, mId, id);
+        return BAD_VALUE;
+    }
+    return OK;
+}
+
+status_t Camera2Device::createDefaultRequest(int templateId,
+        camera_metadata_t **request) {
+    ALOGV("%s: E", __FUNCTION__);
+    return mDevice->ops->construct_default_request(
+        mDevice, templateId, request);
+}
+
+status_t Camera2Device::waitUntilDrained() {
+    static const uint32_t kSleepTime = 50000; // 50 ms
+    static const uint32_t kMaxSleepTime = 10000000; // 10 s
+    ALOGV("%s: E", __FUNCTION__);
+    if (mRequestQueue.getBufferCount() ==
+            CAMERA2_REQUEST_QUEUE_IS_BOTTOMLESS) return INVALID_OPERATION;
+
+    // TODO: Set up notifications from HAL, instead of sleeping here
+    uint32_t totalTime = 0;
+    while (mDevice->ops->get_in_progress_count(mDevice) > 0) {
+        usleep(kSleepTime);
+        totalTime += kSleepTime;
+        if (totalTime > kMaxSleepTime) {
+            ALOGE("%s: Waited %d us, requests still in flight", __FUNCTION__,
+                    totalTime);
+            return TIMED_OUT;
+        }
+    }
+    return OK;
+}
+
+/**
+ * Camera2Device::MetadataQueue
+ */
+
+Camera2Device::MetadataQueue::MetadataQueue():
+            mDevice(NULL),
+            mFrameCount(0),
+            mCount(0),
+            mStreamSlotCount(0),
+            mSignalConsumer(true)
+{
+    camera2_request_queue_src_ops::dequeue_request = consumer_dequeue;
+    camera2_request_queue_src_ops::request_count = consumer_buffer_count;
+    camera2_request_queue_src_ops::free_request = consumer_free;
+
+    camera2_frame_queue_dst_ops::dequeue_frame = producer_dequeue;
+    camera2_frame_queue_dst_ops::cancel_frame = producer_cancel;
+    camera2_frame_queue_dst_ops::enqueue_frame = producer_enqueue;
+}
+
+Camera2Device::MetadataQueue::~MetadataQueue() {
+    Mutex::Autolock l(mMutex);
+    freeBuffers(mEntries.begin(), mEntries.end());
+    freeBuffers(mStreamSlot.begin(), mStreamSlot.end());
+}
+
+// Connect to camera2 HAL as consumer (input requests/reprocessing)
+status_t Camera2Device::MetadataQueue::setConsumerDevice(camera2_device_t *d) {
+    status_t res;
+    res = d->ops->set_request_queue_src_ops(d,
+            this);
+    if (res != OK) return res;
+    mDevice = d;
+    return OK;
+}
+
+status_t Camera2Device::MetadataQueue::setProducerDevice(camera2_device_t *d) {
+    status_t res;
+    res = d->ops->set_frame_queue_dst_ops(d,
+            this);
+    return res;
+}
+
+// Real interfaces
+status_t Camera2Device::MetadataQueue::enqueue(camera_metadata_t *buf) {
+    ALOGVV("%s: E", __FUNCTION__);
+    Mutex::Autolock l(mMutex);
+
+    mCount++;
+    mEntries.push_back(buf);
+
+    return signalConsumerLocked();
+}
+
+int Camera2Device::MetadataQueue::getBufferCount() {
+    Mutex::Autolock l(mMutex);
+    if (mStreamSlotCount > 0) {
+        return CAMERA2_REQUEST_QUEUE_IS_BOTTOMLESS;
+    }
+    return mCount;
+}
+
+status_t Camera2Device::MetadataQueue::dequeue(camera_metadata_t **buf,
+        bool incrementCount)
+{
+    ALOGVV("%s: E", __FUNCTION__);
+    status_t res;
+    Mutex::Autolock l(mMutex);
+
+    if (mCount == 0) {
+        if (mStreamSlotCount == 0) {
+            ALOGVV("%s: Empty", __FUNCTION__);
+            *buf = NULL;
+            mSignalConsumer = true;
+            return OK;
+        }
+        ALOGVV("%s: Streaming %d frames to queue", __FUNCTION__,
+              mStreamSlotCount);
+
+        for (List<camera_metadata_t*>::iterator slotEntry = mStreamSlot.begin();
+                slotEntry != mStreamSlot.end();
+                slotEntry++ ) {
+            size_t entries = get_camera_metadata_entry_count(*slotEntry);
+            size_t dataBytes = get_camera_metadata_data_count(*slotEntry);
+
+            camera_metadata_t *copy =
+                    allocate_camera_metadata(entries, dataBytes);
+            append_camera_metadata(copy, *slotEntry);
+            mEntries.push_back(copy);
+        }
+        mCount = mStreamSlotCount;
+    }
+    ALOGVV("MetadataQueue: deque (%d buffers)", mCount);
+    camera_metadata_t *b = *(mEntries.begin());
+    mEntries.erase(mEntries.begin());
+
+    if (incrementCount) {
+        camera_metadata_entry_t frameCount;
+        res = find_camera_metadata_entry(b,
+                ANDROID_REQUEST_FRAME_COUNT,
+                &frameCount);
+        if (res != OK) {
+            ALOGE("%s: Unable to add frame count: %s (%d)",
+                    __FUNCTION__, strerror(-res), res);
+        } else {
+            *frameCount.data.i32 = mFrameCount;
+        }
+        mFrameCount++;
+    }
+
+    *buf = b;
+    mCount--;
+
+    return OK;
+}
+
+status_t Camera2Device::MetadataQueue::waitForBuffer(nsecs_t timeout)
+{
+    Mutex::Autolock l(mMutex);
+    status_t res;
+    while (mCount == 0) {
+        res = notEmpty.waitRelative(mMutex,timeout);
+        if (res != OK) return res;
+    }
+    return OK;
+}
+
+status_t Camera2Device::MetadataQueue::setStreamSlot(camera_metadata_t *buf)
+{
+    ALOGV("%s: E", __FUNCTION__);
+    Mutex::Autolock l(mMutex);
+    if (buf == NULL) {
+        freeBuffers(mStreamSlot.begin(), mStreamSlot.end());
+        mStreamSlotCount = 0;
+        return OK;
+    }
+    camera_metadata_t *buf2 = clone_camera_metadata(buf);
+    if (!buf2) {
+        ALOGE("%s: Unable to clone metadata buffer!", __FUNCTION__);
+        return NO_MEMORY;
+    }
+
+    if (mStreamSlotCount > 1) {
+        List<camera_metadata_t*>::iterator deleter = ++mStreamSlot.begin();
+        freeBuffers(++mStreamSlot.begin(), mStreamSlot.end());
+        mStreamSlotCount = 1;
+    }
+    if (mStreamSlotCount == 1) {
+        free_camera_metadata( *(mStreamSlot.begin()) );
+        *(mStreamSlot.begin()) = buf2;
+    } else {
+        mStreamSlot.push_front(buf2);
+        mStreamSlotCount = 1;
+    }
+    return signalConsumerLocked();
+}
+
+status_t Camera2Device::MetadataQueue::setStreamSlot(
+        const List<camera_metadata_t*> &bufs)
+{
+    ALOGV("%s: E", __FUNCTION__);
+    Mutex::Autolock l(mMutex);
+    status_t res;
+
+    if (mStreamSlotCount > 0) {
+        freeBuffers(mStreamSlot.begin(), mStreamSlot.end());
+    }
+    mStreamSlotCount = 0;
+    for (List<camera_metadata_t*>::const_iterator r = bufs.begin();
+         r != bufs.end(); r++) {
+        camera_metadata_t *r2 = clone_camera_metadata(*r);
+        if (!r2) {
+            ALOGE("%s: Unable to clone metadata buffer!", __FUNCTION__);
+            return NO_MEMORY;
+        }
+        mStreamSlot.push_back(r2);
+        mStreamSlotCount++;
+    }
+    return signalConsumerLocked();
+}
+
+status_t Camera2Device::MetadataQueue::dump(int fd,
+        const Vector<String16>& args) {
+    String8 result;
+    status_t notLocked;
+    notLocked = mMutex.tryLock();
+    if (notLocked) {
+        result.append("    (Unable to lock queue mutex)\n");
+    }
+    result.appendFormat("      Current frame number: %d\n", mFrameCount);
+    if (mStreamSlotCount == 0) {
+        result.append("      Stream slot: Empty\n");
+        write(fd, result.string(), result.size());
+    } else {
+        result.appendFormat("      Stream slot: %d entries\n",
+                mStreamSlot.size());
+        int i = 0;
+        for (List<camera_metadata_t*>::iterator r = mStreamSlot.begin();
+             r != mStreamSlot.end(); r++) {
+            result = String8::format("       Stream slot buffer %d:\n", i);
+            write(fd, result.string(), result.size());
+            dump_indented_camera_metadata(*r, fd, 2, 10);
+            i++;
+        }
+    }
+    if (mEntries.size() == 0) {
+        result = "      Main queue is empty\n";
+        write(fd, result.string(), result.size());
+    } else {
+        result = String8::format("      Main queue has %d entries:\n",
+                mEntries.size());
+        int i = 0;
+        for (List<camera_metadata_t*>::iterator r = mEntries.begin();
+             r != mEntries.end(); r++) {
+            result = String8::format("       Queue entry %d:\n", i);
+            write(fd, result.string(), result.size());
+            dump_indented_camera_metadata(*r, fd, 2, 10);
+            i++;
+        }
+    }
+
+    if (notLocked == 0) {
+        mMutex.unlock();
+    }
+
+    return OK;
+}
+
+status_t Camera2Device::MetadataQueue::signalConsumerLocked() {
+    status_t res = OK;
+    notEmpty.signal();
+    if (mSignalConsumer && mDevice != NULL) {
+        mSignalConsumer = false;
+
+        mMutex.unlock();
+        ALOGV("%s: Signaling consumer", __FUNCTION__);
+        res = mDevice->ops->notify_request_queue_not_empty(mDevice);
+        mMutex.lock();
+    }
+    return res;
+}
+
+status_t Camera2Device::MetadataQueue::freeBuffers(
+        List<camera_metadata_t*>::iterator start,
+        List<camera_metadata_t*>::iterator end)
+{
+    while (start != end) {
+        free_camera_metadata(*start);
+        start = mStreamSlot.erase(start);
+    }
+    return OK;
+}
+
+Camera2Device::MetadataQueue* Camera2Device::MetadataQueue::getInstance(
+        const camera2_request_queue_src_ops_t *q)
+{
+    const MetadataQueue* cmq = static_cast<const MetadataQueue*>(q);
+    return const_cast<MetadataQueue*>(cmq);
+}
+
+Camera2Device::MetadataQueue* Camera2Device::MetadataQueue::getInstance(
+        const camera2_frame_queue_dst_ops_t *q)
+{
+    const MetadataQueue* cmq = static_cast<const MetadataQueue*>(q);
+    return const_cast<MetadataQueue*>(cmq);
+}
+
+int Camera2Device::MetadataQueue::consumer_buffer_count(
+        const camera2_request_queue_src_ops_t *q)
+{
+    MetadataQueue *queue = getInstance(q);
+    return queue->getBufferCount();
+}
+
+int Camera2Device::MetadataQueue::consumer_dequeue(
+        const camera2_request_queue_src_ops_t *q,
+        camera_metadata_t **buffer)
+{
+    MetadataQueue *queue = getInstance(q);
+    return queue->dequeue(buffer, true);
+}
+
+int Camera2Device::MetadataQueue::consumer_free(
+        const camera2_request_queue_src_ops_t *q,
+        camera_metadata_t *old_buffer)
+{
+    MetadataQueue *queue = getInstance(q);
+    free_camera_metadata(old_buffer);
+    return OK;
+}
+
+int Camera2Device::MetadataQueue::producer_dequeue(
+        const camera2_frame_queue_dst_ops_t *q,
+        size_t entries, size_t bytes,
+        camera_metadata_t **buffer)
+{
+    camera_metadata_t *new_buffer =
+            allocate_camera_metadata(entries, bytes);
+    if (new_buffer == NULL) return NO_MEMORY;
+    *buffer = new_buffer;
+        return OK;
+}
+
+int Camera2Device::MetadataQueue::producer_cancel(
+        const camera2_frame_queue_dst_ops_t *q,
+        camera_metadata_t *old_buffer)
+{
+    free_camera_metadata(old_buffer);
+    return OK;
+}
+
+int Camera2Device::MetadataQueue::producer_enqueue(
+        const camera2_frame_queue_dst_ops_t *q,
+        camera_metadata_t *filled_buffer)
+{
+    MetadataQueue *queue = getInstance(q);
+    return queue->enqueue(filled_buffer);
+}
+
+/**
+ * Camera2Device::StreamAdapter
+ */
+
+#ifndef container_of
+#define container_of(ptr, type, member) \
+    (type *)((char*)(ptr) - offsetof(type, member))
+#endif
+
+Camera2Device::StreamAdapter::StreamAdapter(camera2_device_t *d):
+        mState(RELEASED),
+        mDevice(d),
+        mId(-1),
+        mWidth(0), mHeight(0), mFormat(0), mSize(0), mUsage(0),
+        mMaxProducerBuffers(0), mMaxConsumerBuffers(0),
+        mTotalBuffers(0),
+        mFormatRequested(0),
+        mActiveBuffers(0),
+        mFrameCount(0),
+        mLastTimestamp(0)
+{
+    camera2_stream_ops::dequeue_buffer = dequeue_buffer;
+    camera2_stream_ops::enqueue_buffer = enqueue_buffer;
+    camera2_stream_ops::cancel_buffer = cancel_buffer;
+    camera2_stream_ops::set_crop = set_crop;
+}
+
+Camera2Device::StreamAdapter::~StreamAdapter() {
+    if (mState != RELEASED) {
+        release();
+    }
+}
+
+status_t Camera2Device::StreamAdapter::connectToDevice(
+        sp<ANativeWindow> consumer,
+        uint32_t width, uint32_t height, int format, size_t size) {
+    status_t res;
+    ALOGV("%s: E", __FUNCTION__);
+
+    if (mState != RELEASED) return INVALID_OPERATION;
+    if (consumer == NULL) {
+        ALOGE("%s: Null consumer passed to stream adapter", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    ALOGV("%s: New stream parameters %d x %d, format 0x%x, size %d",
+            __FUNCTION__, width, height, format, size);
+
+    mConsumerInterface = consumer;
+    mWidth = width;
+    mHeight = height;
+    mSize = (format == HAL_PIXEL_FORMAT_BLOB) ? size : 0;
+    mFormatRequested = format;
+
+    // Allocate device-side stream interface
+
+    uint32_t id;
+    uint32_t formatActual;
+    uint32_t usage;
+    uint32_t maxBuffers = 2;
+    res = mDevice->ops->allocate_stream(mDevice,
+            mWidth, mHeight, mFormatRequested, getStreamOps(),
+            &id, &formatActual, &usage, &maxBuffers);
+    if (res != OK) {
+        ALOGE("%s: Device stream allocation failed: %s (%d)",
+                __FUNCTION__, strerror(-res), res);
+        return res;
+    }
+
+    ALOGV("%s: Allocated stream id %d, actual format 0x%x, "
+            "usage 0x%x, producer wants %d buffers", __FUNCTION__,
+            id, formatActual, usage, maxBuffers);
+
+    mId = id;
+    mFormat = formatActual;
+    mUsage = usage;
+    mMaxProducerBuffers = maxBuffers;
+
+    mState = ALLOCATED;
+
+    // Configure consumer-side ANativeWindow interface
+    res = native_window_api_connect(mConsumerInterface.get(),
+            NATIVE_WINDOW_API_CAMERA);
+    if (res != OK) {
+        ALOGE("%s: Unable to connect to native window for stream %d",
+                __FUNCTION__, mId);
+
+        return res;
+    }
+
+    mState = CONNECTED;
+
+    res = native_window_set_usage(mConsumerInterface.get(), mUsage);
+    if (res != OK) {
+        ALOGE("%s: Unable to configure usage %08x for stream %d",
+                __FUNCTION__, mUsage, mId);
+        return res;
+    }
+
+    res = native_window_set_scaling_mode(mConsumerInterface.get(),
+            NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+    if (res != OK) {
+        ALOGE("%s: Unable to configure stream scaling: %s (%d)",
+                __FUNCTION__, strerror(-res), res);
+        return res;
+    }
+
+    res = setTransform(0);
+    if (res != OK) {
+        return res;
+    }
+
+    if (mFormat == HAL_PIXEL_FORMAT_BLOB) {
+        res = native_window_set_buffers_geometry(mConsumerInterface.get(),
+                mSize, 1, mFormat);
+        if (res != OK) {
+            ALOGE("%s: Unable to configure compressed stream buffer geometry"
+                    " %d x %d, size %d for stream %d",
+                    __FUNCTION__, mWidth, mHeight, mSize, mId);
+            return res;
+        }
+    } else {
+        res = native_window_set_buffers_geometry(mConsumerInterface.get(),
+                mWidth, mHeight, mFormat);
+        if (res != OK) {
+            ALOGE("%s: Unable to configure stream buffer geometry"
+                    " %d x %d, format 0x%x for stream %d",
+                    __FUNCTION__, mWidth, mHeight, mFormat, mId);
+            return res;
+        }
+    }
+
+    int maxConsumerBuffers;
+    res = mConsumerInterface->query(mConsumerInterface.get(),
+            NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &maxConsumerBuffers);
+    if (res != OK) {
+        ALOGE("%s: Unable to query consumer undequeued"
+                " buffer count for stream %d", __FUNCTION__, mId);
+        return res;
+    }
+    mMaxConsumerBuffers = maxConsumerBuffers;
+
+    ALOGV("%s: Consumer wants %d buffers", __FUNCTION__,
+            mMaxConsumerBuffers);
+
+    mTotalBuffers = mMaxConsumerBuffers + mMaxProducerBuffers;
+    mActiveBuffers = 0;
+    mFrameCount = 0;
+    mLastTimestamp = 0;
+
+    res = native_window_set_buffer_count(mConsumerInterface.get(),
+            mTotalBuffers);
+    if (res != OK) {
+        ALOGE("%s: Unable to set buffer count for stream %d",
+                __FUNCTION__, mId);
+        return res;
+    }
+
+    // Register allocated buffers with HAL device
+    buffer_handle_t *buffers = new buffer_handle_t[mTotalBuffers];
+    ANativeWindowBuffer **anwBuffers = new ANativeWindowBuffer*[mTotalBuffers];
+    uint32_t bufferIdx = 0;
+    for (; bufferIdx < mTotalBuffers; bufferIdx++) {
+        res = native_window_dequeue_buffer_and_wait(mConsumerInterface.get(),
+                &anwBuffers[bufferIdx]);
+        if (res != OK) {
+            ALOGE("%s: Unable to dequeue buffer %d for initial registration for "
+                    "stream %d", __FUNCTION__, bufferIdx, mId);
+            goto cleanUpBuffers;
+        }
+
+        buffers[bufferIdx] = anwBuffers[bufferIdx]->handle;
+    }
+
+    res = mDevice->ops->register_stream_buffers(mDevice,
+            mId,
+            mTotalBuffers,
+            buffers);
+    if (res != OK) {
+        ALOGE("%s: Unable to register buffers with HAL device for stream %d",
+                __FUNCTION__, mId);
+    } else {
+        mState = ACTIVE;
+    }
+
+cleanUpBuffers:
+    for (uint32_t i = 0; i < bufferIdx; i++) {
+        res = mConsumerInterface->cancelBuffer(mConsumerInterface.get(),
+                anwBuffers[i], -1);
+        if (res != OK) {
+            ALOGE("%s: Unable to cancel buffer %d after registration",
+                    __FUNCTION__, i);
+        }
+    }
+    delete[] anwBuffers;
+    delete[] buffers;
+
+    return res;
+}
+
+status_t Camera2Device::StreamAdapter::release() {
+    status_t res;
+    ALOGV("%s: Releasing stream %d", __FUNCTION__, mId);
+    if (mState >= ALLOCATED) {
+        res = mDevice->ops->release_stream(mDevice, mId);
+        if (res != OK) {
+            ALOGE("%s: Unable to release stream %d",
+                    __FUNCTION__, mId);
+            return res;
+        }
+    }
+    if (mState >= CONNECTED) {
+        res = native_window_api_disconnect(mConsumerInterface.get(),
+                NATIVE_WINDOW_API_CAMERA);
+        if (res != OK) {
+            ALOGE("%s: Unable to disconnect stream %d from native window",
+                    __FUNCTION__, mId);
+            return res;
+        }
+    }
+    mId = -1;
+    mState = RELEASED;
+    return OK;
+}
+
+status_t Camera2Device::StreamAdapter::setTransform(int transform) {
+    status_t res;
+    if (mState < CONNECTED) {
+        ALOGE("%s: Cannot set transform on unconnected stream", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+    res = native_window_set_buffers_transform(mConsumerInterface.get(),
+                                              transform);
+    if (res != OK) {
+        ALOGE("%s: Unable to configure stream transform to %x: %s (%d)",
+                __FUNCTION__, transform, strerror(-res), res);
+    }
+    return res;
+}
+
+status_t Camera2Device::StreamAdapter::dump(int fd,
+        const Vector<String16>& args) {
+    String8 result = String8::format("      Stream %d: %d x %d, format 0x%x\n",
+            mId, mWidth, mHeight, mFormat);
+    result.appendFormat("        size %d, usage 0x%x, requested format 0x%x\n",
+            mSize, mUsage, mFormatRequested);
+    result.appendFormat("        total buffers: %d, dequeued buffers: %d\n",
+            mTotalBuffers, mActiveBuffers);
+    result.appendFormat("        frame count: %d, last timestamp %lld\n",
+            mFrameCount, mLastTimestamp);
+    write(fd, result.string(), result.size());
+    return OK;
+}
+
+const camera2_stream_ops *Camera2Device::StreamAdapter::getStreamOps() {
+    return static_cast<camera2_stream_ops *>(this);
+}
+
+ANativeWindow* Camera2Device::StreamAdapter::toANW(
+        const camera2_stream_ops_t *w) {
+    return static_cast<const StreamAdapter*>(w)->mConsumerInterface.get();
+}
+
+int Camera2Device::StreamAdapter::dequeue_buffer(const camera2_stream_ops_t *w,
+        buffer_handle_t** buffer) {
+    int res;
+    StreamAdapter* stream =
+            const_cast<StreamAdapter*>(static_cast<const StreamAdapter*>(w));
+    if (stream->mState != ACTIVE) {
+        ALOGE("%s: Called when in bad state: %d", __FUNCTION__, stream->mState);
+        return INVALID_OPERATION;
+    }
+
+    ANativeWindow *a = toANW(w);
+    ANativeWindowBuffer* anb;
+    res = native_window_dequeue_buffer_and_wait(a, &anb);
+    if (res != OK) return res;
+
+    *buffer = &(anb->handle);
+    stream->mActiveBuffers++;
+
+    ALOGVV("%s: Buffer %p", __FUNCTION__, *buffer);
+    return res;
+}
+
+int Camera2Device::StreamAdapter::enqueue_buffer(const camera2_stream_ops_t* w,
+        int64_t timestamp,
+        buffer_handle_t* buffer) {
+    StreamAdapter *stream =
+            const_cast<StreamAdapter*>(static_cast<const StreamAdapter*>(w));
+    ALOGVV("%s: Stream %d: Buffer %p captured at %lld ns",
+            __FUNCTION__, stream->mId, buffer, timestamp);
+    int state = stream->mState;
+    if (state != ACTIVE) {
+        ALOGE("%s: Called when in bad state: %d", __FUNCTION__, state);
+        return INVALID_OPERATION;
+    }
+    ANativeWindow *a = toANW(w);
+    status_t err;
+    err = native_window_set_buffers_timestamp(a, timestamp);
+    if (err != OK) {
+        ALOGE("%s: Error setting timestamp on native window: %s (%d)",
+                __FUNCTION__, strerror(-err), err);
+        return err;
+    }
+    err = a->queueBuffer(a,
+            container_of(buffer, ANativeWindowBuffer, handle), -1);
+    if (err != OK) {
+        ALOGE("%s: Error queueing buffer to native window: %s (%d)",
+                __FUNCTION__, strerror(-err), err);
+    }
+    stream->mActiveBuffers--;
+    stream->mFrameCount++;
+    stream->mLastTimestamp = timestamp;
+    return err;
+}
+
+int Camera2Device::StreamAdapter::cancel_buffer(const camera2_stream_ops_t* w,
+        buffer_handle_t* buffer) {
+    StreamAdapter *stream =
+            const_cast<StreamAdapter*>(static_cast<const StreamAdapter*>(w));
+    if (stream->mState != ACTIVE) {
+        ALOGE("%s: Called when in bad state: %d", __FUNCTION__, stream->mState);
+        return INVALID_OPERATION;
+    }
+    stream->mActiveBuffers--;
+    ANativeWindow *a = toANW(w);
+    return a->cancelBuffer(a,
+            container_of(buffer, ANativeWindowBuffer, handle), -1);
+}
+
+int Camera2Device::StreamAdapter::set_crop(const camera2_stream_ops_t* w,
+        int left, int top, int right, int bottom) {
+    int state = static_cast<const StreamAdapter*>(w)->mState;
+    if (state != ACTIVE) {
+        ALOGE("%s: Called when in bad state: %d", __FUNCTION__, state);
+        return INVALID_OPERATION;
+    }
+    ANativeWindow *a = toANW(w);
+    android_native_rect_t crop = { left, top, right, bottom };
+    return native_window_set_crop(a, &crop);
+}
+
+
+}; // namespace android
diff --git a/services/camera/libcameraservice/Camera2Device.h b/services/camera/libcameraservice/Camera2Device.h
new file mode 100644
index 0000000..4ac63df
--- /dev/null
+++ b/services/camera/libcameraservice/Camera2Device.h
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SERVERS_CAMERA_CAMERA2DEVICE_H
+#define ANDROID_SERVERS_CAMERA_CAMERA2DEVICE_H
+
+#include <utils/Condition.h>
+#include <utils/Errors.h>
+#include <utils/List.h>
+#include <utils/Mutex.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+#include "hardware/camera2.h"
+
+namespace android {
+
+class Camera2Device : public virtual RefBase {
+  public:
+    Camera2Device(int id);
+
+    ~Camera2Device();
+
+    status_t initialize(camera_module_t *module);
+
+    status_t dump(int fd, const Vector<String16>& args);
+
+    /**
+     * Get a pointer to the device's static characteristics metadata buffer
+     */
+    camera_metadata_t* info();
+
+    /**
+     * Submit request for capture. The Camera2Device takes ownership of the
+     * passed-in buffer.
+     */
+    status_t capture(camera_metadata_t *request);
+
+    /**
+     * Submit request for streaming. The Camera2Device makes a copy of the
+     * passed-in buffer and the caller retains ownership.
+     */
+    status_t setStreamingRequest(camera_metadata_t *request);
+
+    /**
+     * Create an output stream of the requested size and format.
+     *
+     * If format is CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, then the HAL device selects
+     * an appropriate format; it can be queried with getStreamInfo.
+     *
+     * If format is HAL_PIXEL_FORMAT_COMPRESSED, the size parameter must be
+     * equal to the size in bytes of the buffers to allocate for the stream. For
+     * other formats, the size parameter is ignored.
+     */
+    status_t createStream(sp<ANativeWindow> consumer,
+            uint32_t width, uint32_t height, int format, size_t size,
+            int *id);
+
+    /**
+     * Get information about a given stream.
+     */
+    status_t getStreamInfo(int id,
+            uint32_t *width, uint32_t *height, uint32_t *format);
+
+    /**
+     * Set stream gralloc buffer transform
+     */
+    status_t setStreamTransform(int id, int transform);
+
+    /**
+     * Delete stream. Must not be called if there are requests in flight which
+     * reference that stream.
+     */
+    status_t deleteStream(int id);
+
+    /**
+     * Create a metadata buffer with fields that the HAL device believes are
+     * best for the given use case
+     */
+    status_t createDefaultRequest(int templateId,
+            camera_metadata_t **request);
+
+    /**
+     * Wait until all requests have been processed. Returns INVALID_OPERATION if
+     * the streaming slot is not empty, or TIMED_OUT if the requests haven't
+     * finished processing in 10 seconds.
+     */
+    status_t waitUntilDrained();
+
+  private:
+
+    const int mId;
+    camera2_device_t *mDevice;
+
+    camera_metadata_t *mDeviceInfo;
+    vendor_tag_query_ops_t *mVendorTagOps;
+
+    /**
+     * Queue class for both sending requests to a camera2 device, and for
+     * receiving frames from a camera2 device.
+     */
+    class MetadataQueue: public camera2_request_queue_src_ops_t,
+                         public camera2_frame_queue_dst_ops_t {
+      public:
+        MetadataQueue();
+        ~MetadataQueue();
+
+        // Interface to camera2 HAL device, either for requests (device is
+        // consumer) or for frames (device is producer)
+        const camera2_request_queue_src_ops_t*   getToConsumerInterface();
+        void setFromConsumerInterface(camera2_device_t *d);
+
+        // Connect queue consumer endpoint to a camera2 device
+        status_t setConsumerDevice(camera2_device_t *d);
+        // Connect queue producer endpoint to a camera2 device
+        status_t setProducerDevice(camera2_device_t *d);
+
+        const camera2_frame_queue_dst_ops_t* getToProducerInterface();
+
+        // Real interfaces. On enqueue, queue takes ownership of buffer pointer
+        // On dequeue, user takes ownership of buffer pointer.
+        status_t enqueue(camera_metadata_t *buf);
+        status_t dequeue(camera_metadata_t **buf, bool incrementCount = true);
+        int      getBufferCount();
+        status_t waitForBuffer(nsecs_t timeout);
+
+        // Set repeating buffer(s); if the queue is empty on a dequeue call, the
+        // queue copies the contents of the stream slot into the queue, and then
+        // dequeues the first new entry. The metadata buffers passed in are
+        // copied.
+        status_t setStreamSlot(camera_metadata_t *buf);
+        status_t setStreamSlot(const List<camera_metadata_t*> &bufs);
+
+        status_t dump(int fd, const Vector<String16>& args);
+
+      private:
+        status_t signalConsumerLocked();
+        status_t freeBuffers(List<camera_metadata_t*>::iterator start,
+                List<camera_metadata_t*>::iterator end);
+
+        camera2_device_t *mDevice;
+
+        Mutex mMutex;
+        Condition notEmpty;
+
+        int mFrameCount;
+
+        int mCount;
+        List<camera_metadata_t*> mEntries;
+        int mStreamSlotCount;
+        List<camera_metadata_t*> mStreamSlot;
+
+        bool mSignalConsumer;
+
+        static MetadataQueue* getInstance(
+            const camera2_frame_queue_dst_ops_t *q);
+        static MetadataQueue* getInstance(
+            const camera2_request_queue_src_ops_t *q);
+
+        static int consumer_buffer_count(
+            const camera2_request_queue_src_ops_t *q);
+
+        static int consumer_dequeue(const camera2_request_queue_src_ops_t *q,
+            camera_metadata_t **buffer);
+
+        static int consumer_free(const camera2_request_queue_src_ops_t *q,
+                camera_metadata_t *old_buffer);
+
+        static int producer_dequeue(const camera2_frame_queue_dst_ops_t *q,
+                size_t entries, size_t bytes,
+                camera_metadata_t **buffer);
+
+        static int producer_cancel(const camera2_frame_queue_dst_ops_t *q,
+            camera_metadata_t *old_buffer);
+
+        static int producer_enqueue(const camera2_frame_queue_dst_ops_t *q,
+                camera_metadata_t *filled_buffer);
+
+    }; // class MetadataQueue
+
+    MetadataQueue mRequestQueue;
+    MetadataQueue mFrameQueue;
+
+    /**
+     * Adapter from an ANativeWindow interface to camera2 device stream ops.
+     * Also takes care of allocating/deallocating stream in device interface
+     */
+    class StreamAdapter: public camera2_stream_ops, public virtual RefBase {
+      public:
+        StreamAdapter(camera2_device_t *d);
+
+        ~StreamAdapter();
+
+        /**
+         * Create a HAL device stream of the requested size and format.
+         *
+         * If format is CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, then the HAL device
+         * selects an appropriate format; it can be queried with getFormat.
+         *
+         * If format is HAL_PIXEL_FORMAT_COMPRESSED, the size parameter must
+         * be equal to the size in bytes of the buffers to allocate for the
+         * stream. For other formats, the size parameter is ignored.
+         */
+        status_t connectToDevice(sp<ANativeWindow> consumer,
+                uint32_t width, uint32_t height, int format, size_t size);
+
+        status_t release();
+
+        status_t setTransform(int transform);
+
+        // Get stream parameters.
+        // Only valid after a successful connectToDevice call.
+        int      getId() const     { return mId; }
+        uint32_t getWidth() const  { return mWidth; }
+        uint32_t getHeight() const { return mHeight; }
+        uint32_t getFormat() const { return mFormat; }
+
+        // Dump stream information
+        status_t dump(int fd, const Vector<String16>& args);
+
+      private:
+        enum {
+            ERROR = -1,
+            RELEASED = 0,
+            ALLOCATED,
+            CONNECTED,
+            ACTIVE
+        } mState;
+
+        sp<ANativeWindow> mConsumerInterface;
+        camera2_device_t *mDevice;
+
+        uint32_t mId;
+        uint32_t mWidth;
+        uint32_t mHeight;
+        uint32_t mFormat;
+        size_t   mSize;
+        uint32_t mUsage;
+        uint32_t mMaxProducerBuffers;
+        uint32_t mMaxConsumerBuffers;
+        uint32_t mTotalBuffers;
+        int mFormatRequested;
+
+        /** Debugging information */
+        uint32_t mActiveBuffers;
+        uint32_t mFrameCount;
+        int64_t  mLastTimestamp;
+
+        const camera2_stream_ops *getStreamOps();
+
+        static ANativeWindow* toANW(const camera2_stream_ops_t *w);
+
+        static int dequeue_buffer(const camera2_stream_ops_t *w,
+                buffer_handle_t** buffer);
+
+        static int enqueue_buffer(const camera2_stream_ops_t* w,
+                int64_t timestamp,
+                buffer_handle_t* buffer);
+
+        static int cancel_buffer(const camera2_stream_ops_t* w,
+                buffer_handle_t* buffer);
+
+        static int set_crop(const camera2_stream_ops_t* w,
+                int left, int top, int right, int bottom);
+    }; // class StreamAdapter
+
+    typedef List<sp<StreamAdapter> > StreamList;
+    StreamList mStreams;
+
+}; // class Camera2Device
+
+}; // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/CameraClient.cpp b/services/camera/libcameraservice/CameraClient.cpp
new file mode 100644
index 0000000..54829ef
--- /dev/null
+++ b/services/camera/libcameraservice/CameraClient.cpp
@@ -0,0 +1,958 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "CameraClient"
+//#define LOG_NDEBUG 0
+
+#include <cutils/properties.h>
+#include <gui/SurfaceTextureClient.h>
+#include <gui/Surface.h>
+
+#include "CameraClient.h"
+#include "CameraHardwareInterface.h"
+#include "CameraService.h"
+
+namespace android {
+
+#define LOG1(...) ALOGD_IF(gLogLevel >= 1, __VA_ARGS__);
+#define LOG2(...) ALOGD_IF(gLogLevel >= 2, __VA_ARGS__);
+
+static int getCallingPid() {
+    return IPCThreadState::self()->getCallingPid();
+}
+
+static int getCallingUid() {
+    return IPCThreadState::self()->getCallingUid();
+}
+
+CameraClient::CameraClient(const sp<CameraService>& cameraService,
+        const sp<ICameraClient>& cameraClient,
+        int cameraId, int cameraFacing, int clientPid):
+        Client(cameraService, cameraClient,
+                cameraId, cameraFacing, clientPid)
+{
+    int callingPid = getCallingPid();
+    LOG1("CameraClient::CameraClient E (pid %d, id %d)", callingPid, cameraId);
+
+    mHardware = NULL;
+    mMsgEnabled = 0;
+    mSurface = 0;
+    mPreviewWindow = 0;
+    mDestructionStarted = false;
+
+    // Callback is disabled by default
+    mPreviewCallbackFlag = CAMERA_FRAME_CALLBACK_FLAG_NOOP;
+    mOrientation = getOrientation(0, mCameraFacing == CAMERA_FACING_FRONT);
+    mPlayShutterSound = true;
+    LOG1("CameraClient::CameraClient X (pid %d, id %d)", callingPid, cameraId);
+}
+
+status_t CameraClient::initialize(camera_module_t *module) {
+    int callingPid = getCallingPid();
+    LOG1("CameraClient::initialize E (pid %d, id %d)", callingPid, mCameraId);
+
+    char camera_device_name[10];
+    status_t res;
+    snprintf(camera_device_name, sizeof(camera_device_name), "%d", mCameraId);
+
+    mHardware = new CameraHardwareInterface(camera_device_name);
+    res = mHardware->initialize(&module->common);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",
+                __FUNCTION__, mCameraId, strerror(-res), res);
+        return NO_INIT;
+    }
+
+    mHardware->setCallbacks(notifyCallback,
+            dataCallback,
+            dataCallbackTimestamp,
+            (void *)mCameraId);
+
+    // Enable zoom, error, focus, and metadata messages by default
+    enableMsgType(CAMERA_MSG_ERROR | CAMERA_MSG_ZOOM | CAMERA_MSG_FOCUS |
+                  CAMERA_MSG_PREVIEW_METADATA | CAMERA_MSG_FOCUS_MOVE);
+
+    LOG1("CameraClient::initialize X (pid %d, id %d)", callingPid, mCameraId);
+    return OK;
+}
+
+
+// tear down the client
+CameraClient::~CameraClient() {
+    // this lock should never be NULL
+    Mutex* lock = mCameraService->getClientLockById(mCameraId);
+    lock->lock();
+    mDestructionStarted = true;
+    // client will not be accessed from callback. should unlock to prevent dead-lock in disconnect
+    lock->unlock();
+    int callingPid = getCallingPid();
+    LOG1("CameraClient::~CameraClient E (pid %d, this %p)", callingPid, this);
+
+    // set mClientPid to let disconnet() tear down the hardware
+    mClientPid = callingPid;
+    disconnect();
+    LOG1("CameraClient::~CameraClient X (pid %d, this %p)", callingPid, this);
+}
+
+status_t CameraClient::dump(int fd, const Vector<String16>& args) {
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+
+    size_t len = snprintf(buffer, SIZE, "Client[%d] (%p) PID: %d\n",
+            mCameraId,
+            getCameraClient()->asBinder().get(),
+            mClientPid);
+    len = (len > SIZE - 1) ? SIZE - 1 : len;
+    write(fd, buffer, len);
+    return mHardware->dump(fd, args);
+}
+
+// ----------------------------------------------------------------------------
+
+status_t CameraClient::checkPid() const {
+    int callingPid = getCallingPid();
+    if (callingPid == mClientPid) return NO_ERROR;
+
+    ALOGW("attempt to use a locked camera from a different process"
+         " (old pid %d, new pid %d)", mClientPid, callingPid);
+    return EBUSY;
+}
+
+status_t CameraClient::checkPidAndHardware() const {
+    status_t result = checkPid();
+    if (result != NO_ERROR) return result;
+    if (mHardware == 0) {
+        ALOGE("attempt to use a camera after disconnect() (pid %d)", getCallingPid());
+        return INVALID_OPERATION;
+    }
+    return NO_ERROR;
+}
+
+status_t CameraClient::lock() {
+    int callingPid = getCallingPid();
+    LOG1("lock (pid %d)", callingPid);
+    Mutex::Autolock lock(mLock);
+
+    // lock camera to this client if the the camera is unlocked
+    if (mClientPid == 0) {
+        mClientPid = callingPid;
+        return NO_ERROR;
+    }
+
+    // returns NO_ERROR if the client already owns the camera, EBUSY otherwise
+    return checkPid();
+}
+
+status_t CameraClient::unlock() {
+    int callingPid = getCallingPid();
+    LOG1("unlock (pid %d)", callingPid);
+    Mutex::Autolock lock(mLock);
+
+    // allow anyone to use camera (after they lock the camera)
+    status_t result = checkPid();
+    if (result == NO_ERROR) {
+        if (mHardware->recordingEnabled()) {
+            ALOGE("Not allowed to unlock camera during recording.");
+            return INVALID_OPERATION;
+        }
+        mClientPid = 0;
+        LOG1("clear mCameraClient (pid %d)", callingPid);
+        // we need to remove the reference to ICameraClient so that when the app
+        // goes away, the reference count goes to 0.
+        mCameraClient.clear();
+    }
+    return result;
+}
+
+// connect a new client to the camera
+status_t CameraClient::connect(const sp<ICameraClient>& client) {
+    int callingPid = getCallingPid();
+    LOG1("connect E (pid %d)", callingPid);
+    Mutex::Autolock lock(mLock);
+
+    if (mClientPid != 0 && checkPid() != NO_ERROR) {
+        ALOGW("Tried to connect to a locked camera (old pid %d, new pid %d)",
+                mClientPid, callingPid);
+        return EBUSY;
+    }
+
+    if (mCameraClient != 0 && (client->asBinder() == mCameraClient->asBinder())) {
+        LOG1("Connect to the same client");
+        return NO_ERROR;
+    }
+
+    mPreviewCallbackFlag = CAMERA_FRAME_CALLBACK_FLAG_NOOP;
+    mClientPid = callingPid;
+    mCameraClient = client;
+
+    LOG1("connect X (pid %d)", callingPid);
+    return NO_ERROR;
+}
+
+static void disconnectWindow(const sp<ANativeWindow>& window) {
+    if (window != 0) {
+        status_t result = native_window_api_disconnect(window.get(),
+                NATIVE_WINDOW_API_CAMERA);
+        if (result != NO_ERROR) {
+            ALOGW("native_window_api_disconnect failed: %s (%d)", strerror(-result),
+                    result);
+        }
+    }
+}
+
+void CameraClient::disconnect() {
+    int callingPid = getCallingPid();
+    LOG1("disconnect E (pid %d)", callingPid);
+    Mutex::Autolock lock(mLock);
+
+    if (checkPid() != NO_ERROR) {
+        ALOGW("different client - don't disconnect");
+        return;
+    }
+
+    if (mClientPid <= 0) {
+        LOG1("camera is unlocked (mClientPid = %d), don't tear down hardware", mClientPid);
+        return;
+    }
+
+    // Make sure disconnect() is done once and once only, whether it is called
+    // from the user directly, or called by the destructor.
+    if (mHardware == 0) return;
+
+    LOG1("hardware teardown");
+    // Before destroying mHardware, we must make sure it's in the
+    // idle state.
+    // Turn off all messages.
+    disableMsgType(CAMERA_MSG_ALL_MSGS);
+    mHardware->stopPreview();
+    mHardware->cancelPicture();
+    // Release the hardware resources.
+    mHardware->release();
+
+    // Release the held ANativeWindow resources.
+    if (mPreviewWindow != 0) {
+        disconnectWindow(mPreviewWindow);
+        mPreviewWindow = 0;
+        mHardware->setPreviewWindow(mPreviewWindow);
+    }
+    mHardware.clear();
+
+    CameraService::Client::disconnect();
+
+    LOG1("disconnect X (pid %d)", callingPid);
+}
+
+// ----------------------------------------------------------------------------
+
+status_t CameraClient::setPreviewWindow(const sp<IBinder>& binder,
+        const sp<ANativeWindow>& window) {
+    Mutex::Autolock lock(mLock);
+    status_t result = checkPidAndHardware();
+    if (result != NO_ERROR) return result;
+
+    // return if no change in surface.
+    if (binder == mSurface) {
+        return NO_ERROR;
+    }
+
+    if (window != 0) {
+        result = native_window_api_connect(window.get(), NATIVE_WINDOW_API_CAMERA);
+        if (result != NO_ERROR) {
+            ALOGE("native_window_api_connect failed: %s (%d)", strerror(-result),
+                    result);
+            return result;
+        }
+    }
+
+    // If preview has been already started, register preview buffers now.
+    if (mHardware->previewEnabled()) {
+        if (window != 0) {
+            native_window_set_scaling_mode(window.get(),
+                    NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+            native_window_set_buffers_transform(window.get(), mOrientation);
+            result = mHardware->setPreviewWindow(window);
+        }
+    }
+
+    if (result == NO_ERROR) {
+        // Everything has succeeded.  Disconnect the old window and remember the
+        // new window.
+        disconnectWindow(mPreviewWindow);
+        mSurface = binder;
+        mPreviewWindow = window;
+    } else {
+        // Something went wrong after we connected to the new window, so
+        // disconnect here.
+        disconnectWindow(window);
+    }
+
+    return result;
+}
+
+// set the Surface that the preview will use
+status_t CameraClient::setPreviewDisplay(const sp<Surface>& surface) {
+    LOG1("setPreviewDisplay(%p) (pid %d)", surface.get(), getCallingPid());
+
+    sp<IBinder> binder(surface != 0 ? surface->asBinder() : 0);
+    sp<ANativeWindow> window(surface);
+    return setPreviewWindow(binder, window);
+}
+
+// set the SurfaceTexture that the preview will use
+status_t CameraClient::setPreviewTexture(
+        const sp<ISurfaceTexture>& surfaceTexture) {
+    LOG1("setPreviewTexture(%p) (pid %d)", surfaceTexture.get(),
+            getCallingPid());
+
+    sp<IBinder> binder;
+    sp<ANativeWindow> window;
+    if (surfaceTexture != 0) {
+        binder = surfaceTexture->asBinder();
+        window = new SurfaceTextureClient(surfaceTexture);
+    }
+    return setPreviewWindow(binder, window);
+}
+
+// set the preview callback flag to affect how the received frames from
+// preview are handled.
+void CameraClient::setPreviewCallbackFlag(int callback_flag) {
+    LOG1("setPreviewCallbackFlag(%d) (pid %d)", callback_flag, getCallingPid());
+    Mutex::Autolock lock(mLock);
+    if (checkPidAndHardware() != NO_ERROR) return;
+
+    mPreviewCallbackFlag = callback_flag;
+    if (mPreviewCallbackFlag & CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK) {
+        enableMsgType(CAMERA_MSG_PREVIEW_FRAME);
+    } else {
+        disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
+    }
+}
+
+// start preview mode
+status_t CameraClient::startPreview() {
+    LOG1("startPreview (pid %d)", getCallingPid());
+    return startCameraMode(CAMERA_PREVIEW_MODE);
+}
+
+// start recording mode
+status_t CameraClient::startRecording() {
+    LOG1("startRecording (pid %d)", getCallingPid());
+    return startCameraMode(CAMERA_RECORDING_MODE);
+}
+
+// start preview or recording
+status_t CameraClient::startCameraMode(camera_mode mode) {
+    LOG1("startCameraMode(%d)", mode);
+    Mutex::Autolock lock(mLock);
+    status_t result = checkPidAndHardware();
+    if (result != NO_ERROR) return result;
+
+    switch(mode) {
+        case CAMERA_PREVIEW_MODE:
+            if (mSurface == 0 && mPreviewWindow == 0) {
+                LOG1("mSurface is not set yet.");
+                // still able to start preview in this case.
+            }
+            return startPreviewMode();
+        case CAMERA_RECORDING_MODE:
+            if (mSurface == 0 && mPreviewWindow == 0) {
+                ALOGE("mSurface or mPreviewWindow must be set before startRecordingMode.");
+                return INVALID_OPERATION;
+            }
+            return startRecordingMode();
+        default:
+            return UNKNOWN_ERROR;
+    }
+}
+
+status_t CameraClient::startPreviewMode() {
+    LOG1("startPreviewMode");
+    status_t result = NO_ERROR;
+
+    // if preview has been enabled, nothing needs to be done
+    if (mHardware->previewEnabled()) {
+        return NO_ERROR;
+    }
+
+    if (mPreviewWindow != 0) {
+        native_window_set_scaling_mode(mPreviewWindow.get(),
+                NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+        native_window_set_buffers_transform(mPreviewWindow.get(),
+                mOrientation);
+    }
+    mHardware->setPreviewWindow(mPreviewWindow);
+    result = mHardware->startPreview();
+
+    return result;
+}
+
+status_t CameraClient::startRecordingMode() {
+    LOG1("startRecordingMode");
+    status_t result = NO_ERROR;
+
+    // if recording has been enabled, nothing needs to be done
+    if (mHardware->recordingEnabled()) {
+        return NO_ERROR;
+    }
+
+    // if preview has not been started, start preview first
+    if (!mHardware->previewEnabled()) {
+        result = startPreviewMode();
+        if (result != NO_ERROR) {
+            return result;
+        }
+    }
+
+    // start recording mode
+    enableMsgType(CAMERA_MSG_VIDEO_FRAME);
+    mCameraService->playSound(CameraService::SOUND_RECORDING);
+    result = mHardware->startRecording();
+    if (result != NO_ERROR) {
+        ALOGE("mHardware->startRecording() failed with status %d", result);
+    }
+    return result;
+}
+
+// stop preview mode
+void CameraClient::stopPreview() {
+    LOG1("stopPreview (pid %d)", getCallingPid());
+    Mutex::Autolock lock(mLock);
+    if (checkPidAndHardware() != NO_ERROR) return;
+
+
+    disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
+    mHardware->stopPreview();
+
+    mPreviewBuffer.clear();
+}
+
+// stop recording mode
+void CameraClient::stopRecording() {
+    LOG1("stopRecording (pid %d)", getCallingPid());
+    Mutex::Autolock lock(mLock);
+    if (checkPidAndHardware() != NO_ERROR) return;
+
+    disableMsgType(CAMERA_MSG_VIDEO_FRAME);
+    mHardware->stopRecording();
+    mCameraService->playSound(CameraService::SOUND_RECORDING);
+
+    mPreviewBuffer.clear();
+}
+
+// release a recording frame
+void CameraClient::releaseRecordingFrame(const sp<IMemory>& mem) {
+    Mutex::Autolock lock(mLock);
+    if (checkPidAndHardware() != NO_ERROR) return;
+    mHardware->releaseRecordingFrame(mem);
+}
+
+status_t CameraClient::storeMetaDataInBuffers(bool enabled)
+{
+    LOG1("storeMetaDataInBuffers: %s", enabled? "true": "false");
+    Mutex::Autolock lock(mLock);
+    if (checkPidAndHardware() != NO_ERROR) {
+        return UNKNOWN_ERROR;
+    }
+    return mHardware->storeMetaDataInBuffers(enabled);
+}
+
+bool CameraClient::previewEnabled() {
+    LOG1("previewEnabled (pid %d)", getCallingPid());
+
+    Mutex::Autolock lock(mLock);
+    if (checkPidAndHardware() != NO_ERROR) return false;
+    return mHardware->previewEnabled();
+}
+
+bool CameraClient::recordingEnabled() {
+    LOG1("recordingEnabled (pid %d)", getCallingPid());
+
+    Mutex::Autolock lock(mLock);
+    if (checkPidAndHardware() != NO_ERROR) return false;
+    return mHardware->recordingEnabled();
+}
+
+status_t CameraClient::autoFocus() {
+    LOG1("autoFocus (pid %d)", getCallingPid());
+
+    Mutex::Autolock lock(mLock);
+    status_t result = checkPidAndHardware();
+    if (result != NO_ERROR) return result;
+
+    return mHardware->autoFocus();
+}
+
+status_t CameraClient::cancelAutoFocus() {
+    LOG1("cancelAutoFocus (pid %d)", getCallingPid());
+
+    Mutex::Autolock lock(mLock);
+    status_t result = checkPidAndHardware();
+    if (result != NO_ERROR) return result;
+
+    return mHardware->cancelAutoFocus();
+}
+
+// take a picture - image is returned in callback
+status_t CameraClient::takePicture(int msgType) {
+    LOG1("takePicture (pid %d): 0x%x", getCallingPid(), msgType);
+
+    Mutex::Autolock lock(mLock);
+    status_t result = checkPidAndHardware();
+    if (result != NO_ERROR) return result;
+
+    if ((msgType & CAMERA_MSG_RAW_IMAGE) &&
+        (msgType & CAMERA_MSG_RAW_IMAGE_NOTIFY)) {
+        ALOGE("CAMERA_MSG_RAW_IMAGE and CAMERA_MSG_RAW_IMAGE_NOTIFY"
+                " cannot be both enabled");
+        return BAD_VALUE;
+    }
+
+    // We only accept picture related message types
+    // and ignore other types of messages for takePicture().
+    int picMsgType = msgType
+                        & (CAMERA_MSG_SHUTTER |
+                           CAMERA_MSG_POSTVIEW_FRAME |
+                           CAMERA_MSG_RAW_IMAGE |
+                           CAMERA_MSG_RAW_IMAGE_NOTIFY |
+                           CAMERA_MSG_COMPRESSED_IMAGE);
+
+    enableMsgType(picMsgType);
+
+    return mHardware->takePicture();
+}
+
+// set preview/capture parameters - key/value pairs
+status_t CameraClient::setParameters(const String8& params) {
+    LOG1("setParameters (pid %d) (%s)", getCallingPid(), params.string());
+
+    Mutex::Autolock lock(mLock);
+    status_t result = checkPidAndHardware();
+    if (result != NO_ERROR) return result;
+
+    CameraParameters p(params);
+    return mHardware->setParameters(p);
+}
+
+// get preview/capture parameters - key/value pairs
+String8 CameraClient::getParameters() const {
+    Mutex::Autolock lock(mLock);
+    if (checkPidAndHardware() != NO_ERROR) return String8();
+
+    String8 params(mHardware->getParameters().flatten());
+    LOG1("getParameters (pid %d) (%s)", getCallingPid(), params.string());
+    return params;
+}
+
+// enable shutter sound
+status_t CameraClient::enableShutterSound(bool enable) {
+    LOG1("enableShutterSound (pid %d)", getCallingPid());
+
+    status_t result = checkPidAndHardware();
+    if (result != NO_ERROR) return result;
+
+    if (enable) {
+        mPlayShutterSound = true;
+        return OK;
+    }
+
+    // Disabling shutter sound may not be allowed. In that case only
+    // allow the mediaserver process to disable the sound.
+    char value[PROPERTY_VALUE_MAX];
+    property_get("ro.camera.sound.forced", value, "0");
+    if (strcmp(value, "0") != 0) {
+        // Disabling shutter sound is not allowed. Deny if the current
+        // process is not mediaserver.
+        if (getCallingPid() != getpid()) {
+            ALOGE("Failed to disable shutter sound. Permission denied (pid %d)", getCallingPid());
+            return PERMISSION_DENIED;
+        }
+    }
+
+    mPlayShutterSound = false;
+    return OK;
+}
+
+status_t CameraClient::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) {
+    LOG1("sendCommand (pid %d)", getCallingPid());
+    int orientation;
+    Mutex::Autolock lock(mLock);
+    status_t result = checkPidAndHardware();
+    if (result != NO_ERROR) return result;
+
+    if (cmd == CAMERA_CMD_SET_DISPLAY_ORIENTATION) {
+        // Mirror the preview if the camera is front-facing.
+        orientation = getOrientation(arg1, mCameraFacing == CAMERA_FACING_FRONT);
+        if (orientation == -1) return BAD_VALUE;
+
+        if (mOrientation != orientation) {
+            mOrientation = orientation;
+            if (mPreviewWindow != 0) {
+                native_window_set_buffers_transform(mPreviewWindow.get(),
+                        mOrientation);
+            }
+        }
+        return OK;
+    } else if (cmd == CAMERA_CMD_ENABLE_SHUTTER_SOUND) {
+        switch (arg1) {
+            case 0:
+                enableShutterSound(false);
+                break;
+            case 1:
+                enableShutterSound(true);
+                break;
+            default:
+                return BAD_VALUE;
+        }
+        return OK;
+    } else if (cmd == CAMERA_CMD_PLAY_RECORDING_SOUND) {
+        mCameraService->playSound(CameraService::SOUND_RECORDING);
+    } else if (cmd == CAMERA_CMD_PING) {
+        // If mHardware is 0, checkPidAndHardware will return error.
+        return OK;
+    }
+
+    return mHardware->sendCommand(cmd, arg1, arg2);
+}
+
+// ----------------------------------------------------------------------------
+
+void CameraClient::enableMsgType(int32_t msgType) {
+    android_atomic_or(msgType, &mMsgEnabled);
+    mHardware->enableMsgType(msgType);
+}
+
+void CameraClient::disableMsgType(int32_t msgType) {
+    android_atomic_and(~msgType, &mMsgEnabled);
+    mHardware->disableMsgType(msgType);
+}
+
+#define CHECK_MESSAGE_INTERVAL 10 // 10ms
+bool CameraClient::lockIfMessageWanted(int32_t msgType) {
+    int sleepCount = 0;
+    while (mMsgEnabled & msgType) {
+        if (mLock.tryLock() == NO_ERROR) {
+            if (sleepCount > 0) {
+                LOG1("lockIfMessageWanted(%d): waited for %d ms",
+                    msgType, sleepCount * CHECK_MESSAGE_INTERVAL);
+            }
+            return true;
+        }
+        if (sleepCount++ == 0) {
+            LOG1("lockIfMessageWanted(%d): enter sleep", msgType);
+        }
+        usleep(CHECK_MESSAGE_INTERVAL * 1000);
+    }
+    ALOGW("lockIfMessageWanted(%d): dropped unwanted message", msgType);
+    return false;
+}
+
+// Callback messages can be dispatched to internal handlers or pass to our
+// client's callback functions, depending on the message type.
+//
+// notifyCallback:
+//      CAMERA_MSG_SHUTTER              handleShutter
+//      (others)                        c->notifyCallback
+// dataCallback:
+//      CAMERA_MSG_PREVIEW_FRAME        handlePreviewData
+//      CAMERA_MSG_POSTVIEW_FRAME       handlePostview
+//      CAMERA_MSG_RAW_IMAGE            handleRawPicture
+//      CAMERA_MSG_COMPRESSED_IMAGE     handleCompressedPicture
+//      (others)                        c->dataCallback
+// dataCallbackTimestamp
+//      (others)                        c->dataCallbackTimestamp
+//
+// NOTE: the *Callback functions grab mLock of the client before passing
+// control to handle* functions. So the handle* functions must release the
+// lock before calling the ICameraClient's callbacks, so those callbacks can
+// invoke methods in the Client class again (For example, the preview frame
+// callback may want to releaseRecordingFrame). The handle* functions must
+// release the lock after all accesses to member variables, so it must be
+// handled very carefully.
+
+void CameraClient::notifyCallback(int32_t msgType, int32_t ext1,
+        int32_t ext2, void* user) {
+    LOG2("notifyCallback(%d)", msgType);
+
+    Mutex* lock = getClientLockFromCookie(user);
+    if (lock == NULL) return;
+    Mutex::Autolock alock(*lock);
+
+    CameraClient* client =
+            static_cast<CameraClient*>(getClientFromCookie(user));
+    if (client == NULL) return;
+
+    if (!client->lockIfMessageWanted(msgType)) return;
+
+    switch (msgType) {
+        case CAMERA_MSG_SHUTTER:
+            // ext1 is the dimension of the yuv picture.
+            client->handleShutter();
+            break;
+        default:
+            client->handleGenericNotify(msgType, ext1, ext2);
+            break;
+    }
+}
+
+void CameraClient::dataCallback(int32_t msgType,
+        const sp<IMemory>& dataPtr, camera_frame_metadata_t *metadata, void* user) {
+    LOG2("dataCallback(%d)", msgType);
+
+    Mutex* lock = getClientLockFromCookie(user);
+    if (lock == NULL) return;
+    Mutex::Autolock alock(*lock);
+
+    CameraClient* client =
+            static_cast<CameraClient*>(getClientFromCookie(user));
+    if (client == NULL) return;
+
+    if (!client->lockIfMessageWanted(msgType)) return;
+    if (dataPtr == 0 && metadata == NULL) {
+        ALOGE("Null data returned in data callback");
+        client->handleGenericNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);
+        return;
+    }
+
+    switch (msgType & ~CAMERA_MSG_PREVIEW_METADATA) {
+        case CAMERA_MSG_PREVIEW_FRAME:
+            client->handlePreviewData(msgType, dataPtr, metadata);
+            break;
+        case CAMERA_MSG_POSTVIEW_FRAME:
+            client->handlePostview(dataPtr);
+            break;
+        case CAMERA_MSG_RAW_IMAGE:
+            client->handleRawPicture(dataPtr);
+            break;
+        case CAMERA_MSG_COMPRESSED_IMAGE:
+            client->handleCompressedPicture(dataPtr);
+            break;
+        default:
+            client->handleGenericData(msgType, dataPtr, metadata);
+            break;
+    }
+}
+
+void CameraClient::dataCallbackTimestamp(nsecs_t timestamp,
+        int32_t msgType, const sp<IMemory>& dataPtr, void* user) {
+    LOG2("dataCallbackTimestamp(%d)", msgType);
+
+    Mutex* lock = getClientLockFromCookie(user);
+    if (lock == NULL) return;
+    Mutex::Autolock alock(*lock);
+
+    CameraClient* client =
+            static_cast<CameraClient*>(getClientFromCookie(user));
+    if (client == NULL) return;
+
+    if (!client->lockIfMessageWanted(msgType)) return;
+
+    if (dataPtr == 0) {
+        ALOGE("Null data returned in data with timestamp callback");
+        client->handleGenericNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);
+        return;
+    }
+
+    client->handleGenericDataTimestamp(timestamp, msgType, dataPtr);
+}
+
+// snapshot taken callback
+void CameraClient::handleShutter(void) {
+    if (mPlayShutterSound) {
+        mCameraService->playSound(CameraService::SOUND_SHUTTER);
+    }
+
+    sp<ICameraClient> c = mCameraClient;
+    if (c != 0) {
+        mLock.unlock();
+        c->notifyCallback(CAMERA_MSG_SHUTTER, 0, 0);
+        if (!lockIfMessageWanted(CAMERA_MSG_SHUTTER)) return;
+    }
+    disableMsgType(CAMERA_MSG_SHUTTER);
+
+    mLock.unlock();
+}
+
+// preview callback - frame buffer update
+void CameraClient::handlePreviewData(int32_t msgType,
+                                              const sp<IMemory>& mem,
+                                              camera_frame_metadata_t *metadata) {
+    ssize_t offset;
+    size_t size;
+    sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+
+    // local copy of the callback flags
+    int flags = mPreviewCallbackFlag;
+
+    // is callback enabled?
+    if (!(flags & CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK)) {
+        // If the enable bit is off, the copy-out and one-shot bits are ignored
+        LOG2("frame callback is disabled");
+        mLock.unlock();
+        return;
+    }
+
+    // hold a strong pointer to the client
+    sp<ICameraClient> c = mCameraClient;
+
+    // clear callback flags if no client or one-shot mode
+    if (c == 0 || (mPreviewCallbackFlag & CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK)) {
+        LOG2("Disable preview callback");
+        mPreviewCallbackFlag &= ~(CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK |
+                                  CAMERA_FRAME_CALLBACK_FLAG_COPY_OUT_MASK |
+                                  CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK);
+        disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
+    }
+
+    if (c != 0) {
+        // Is the received frame copied out or not?
+        if (flags & CAMERA_FRAME_CALLBACK_FLAG_COPY_OUT_MASK) {
+            LOG2("frame is copied");
+            copyFrameAndPostCopiedFrame(msgType, c, heap, offset, size, metadata);
+        } else {
+            LOG2("frame is forwarded");
+            mLock.unlock();
+            c->dataCallback(msgType, mem, metadata);
+        }
+    } else {
+        mLock.unlock();
+    }
+}
+
+// picture callback - postview image ready
+void CameraClient::handlePostview(const sp<IMemory>& mem) {
+    disableMsgType(CAMERA_MSG_POSTVIEW_FRAME);
+
+    sp<ICameraClient> c = mCameraClient;
+    mLock.unlock();
+    if (c != 0) {
+        c->dataCallback(CAMERA_MSG_POSTVIEW_FRAME, mem, NULL);
+    }
+}
+
+// picture callback - raw image ready
+void CameraClient::handleRawPicture(const sp<IMemory>& mem) {
+    disableMsgType(CAMERA_MSG_RAW_IMAGE);
+
+    ssize_t offset;
+    size_t size;
+    sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+
+    sp<ICameraClient> c = mCameraClient;
+    mLock.unlock();
+    if (c != 0) {
+        c->dataCallback(CAMERA_MSG_RAW_IMAGE, mem, NULL);
+    }
+}
+
+// picture callback - compressed picture ready
+void CameraClient::handleCompressedPicture(const sp<IMemory>& mem) {
+    disableMsgType(CAMERA_MSG_COMPRESSED_IMAGE);
+
+    sp<ICameraClient> c = mCameraClient;
+    mLock.unlock();
+    if (c != 0) {
+        c->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE, mem, NULL);
+    }
+}
+
+
+void CameraClient::handleGenericNotify(int32_t msgType,
+    int32_t ext1, int32_t ext2) {
+    sp<ICameraClient> c = mCameraClient;
+    mLock.unlock();
+    if (c != 0) {
+        c->notifyCallback(msgType, ext1, ext2);
+    }
+}
+
+void CameraClient::handleGenericData(int32_t msgType,
+    const sp<IMemory>& dataPtr, camera_frame_metadata_t *metadata) {
+    sp<ICameraClient> c = mCameraClient;
+    mLock.unlock();
+    if (c != 0) {
+        c->dataCallback(msgType, dataPtr, metadata);
+    }
+}
+
+void CameraClient::handleGenericDataTimestamp(nsecs_t timestamp,
+    int32_t msgType, const sp<IMemory>& dataPtr) {
+    sp<ICameraClient> c = mCameraClient;
+    mLock.unlock();
+    if (c != 0) {
+        c->dataCallbackTimestamp(timestamp, msgType, dataPtr);
+    }
+}
+
+void CameraClient::copyFrameAndPostCopiedFrame(
+        int32_t msgType, const sp<ICameraClient>& client,
+        const sp<IMemoryHeap>& heap, size_t offset, size_t size,
+        camera_frame_metadata_t *metadata) {
+    LOG2("copyFrameAndPostCopiedFrame");
+    // It is necessary to copy out of pmem before sending this to
+    // the callback. For efficiency, reuse the same MemoryHeapBase
+    // provided it's big enough. Don't allocate the memory or
+    // perform the copy if there's no callback.
+    // hold the preview lock while we grab a reference to the preview buffer
+    sp<MemoryHeapBase> previewBuffer;
+
+    if (mPreviewBuffer == 0) {
+        mPreviewBuffer = new MemoryHeapBase(size, 0, NULL);
+    } else if (size > mPreviewBuffer->virtualSize()) {
+        mPreviewBuffer.clear();
+        mPreviewBuffer = new MemoryHeapBase(size, 0, NULL);
+    }
+    if (mPreviewBuffer == 0) {
+        ALOGE("failed to allocate space for preview buffer");
+        mLock.unlock();
+        return;
+    }
+    previewBuffer = mPreviewBuffer;
+
+    memcpy(previewBuffer->base(), (uint8_t *)heap->base() + offset, size);
+
+    sp<MemoryBase> frame = new MemoryBase(previewBuffer, 0, size);
+    if (frame == 0) {
+        ALOGE("failed to allocate space for frame callback");
+        mLock.unlock();
+        return;
+    }
+
+    mLock.unlock();
+    client->dataCallback(msgType, frame, metadata);
+}
+
+int CameraClient::getOrientation(int degrees, bool mirror) {
+    if (!mirror) {
+        if (degrees == 0) return 0;
+        else if (degrees == 90) return HAL_TRANSFORM_ROT_90;
+        else if (degrees == 180) return HAL_TRANSFORM_ROT_180;
+        else if (degrees == 270) return HAL_TRANSFORM_ROT_270;
+    } else {  // Do mirror (horizontal flip)
+        if (degrees == 0) {           // FLIP_H and ROT_0
+            return HAL_TRANSFORM_FLIP_H;
+        } else if (degrees == 90) {   // FLIP_H and ROT_90
+            return HAL_TRANSFORM_FLIP_H | HAL_TRANSFORM_ROT_90;
+        } else if (degrees == 180) {  // FLIP_H and ROT_180
+            return HAL_TRANSFORM_FLIP_V;
+        } else if (degrees == 270) {  // FLIP_H and ROT_270
+            return HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_ROT_90;
+        }
+    }
+    ALOGE("Invalid setDisplayOrientation degrees=%d", degrees);
+    return -1;
+}
+
+}; // namespace android
diff --git a/services/camera/libcameraservice/CameraClient.h b/services/camera/libcameraservice/CameraClient.h
new file mode 100644
index 0000000..256298d
--- /dev/null
+++ b/services/camera/libcameraservice/CameraClient.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SERVERS_CAMERA_CAMERACLIENT_H
+#define ANDROID_SERVERS_CAMERA_CAMERACLIENT_H
+
+#include "CameraService.h"
+
+namespace android {
+
+class MemoryHeapBase;
+class CameraHardwareInterface;
+
+class CameraClient : public CameraService::Client
+{
+public:
+    // ICamera interface (see ICamera for details)
+    virtual void            disconnect();
+    virtual status_t        connect(const sp<ICameraClient>& client);
+    virtual status_t        lock();
+    virtual status_t        unlock();
+    virtual status_t        setPreviewDisplay(const sp<Surface>& surface);
+    virtual status_t        setPreviewTexture(const sp<ISurfaceTexture>& surfaceTexture);
+    virtual void            setPreviewCallbackFlag(int flag);
+    virtual status_t        startPreview();
+    virtual void            stopPreview();
+    virtual bool            previewEnabled();
+    virtual status_t        storeMetaDataInBuffers(bool enabled);
+    virtual status_t        startRecording();
+    virtual void            stopRecording();
+    virtual bool            recordingEnabled();
+    virtual void            releaseRecordingFrame(const sp<IMemory>& mem);
+    virtual status_t        autoFocus();
+    virtual status_t        cancelAutoFocus();
+    virtual status_t        takePicture(int msgType);
+    virtual status_t        setParameters(const String8& params);
+    virtual String8         getParameters() const;
+    virtual status_t        sendCommand(int32_t cmd, int32_t arg1, int32_t arg2);
+
+    // Interface used by CameraService
+    CameraClient(const sp<CameraService>& cameraService,
+            const sp<ICameraClient>& cameraClient,
+            int cameraId,
+            int cameraFacing,
+            int clientPid);
+    ~CameraClient();
+
+    status_t initialize(camera_module_t *module);
+
+    status_t dump(int fd, const Vector<String16>& args);
+
+private:
+
+    // check whether the calling process matches mClientPid.
+    status_t                checkPid() const;
+    status_t                checkPidAndHardware() const;  // also check mHardware != 0
+
+    // these are internal functions used to set up preview buffers
+    status_t                registerPreviewBuffers();
+
+    // camera operation mode
+    enum camera_mode {
+        CAMERA_PREVIEW_MODE   = 0,  // frame automatically released
+        CAMERA_RECORDING_MODE = 1,  // frame has to be explicitly released by releaseRecordingFrame()
+    };
+    // these are internal functions used for preview/recording
+    status_t                startCameraMode(camera_mode mode);
+    status_t                startPreviewMode();
+    status_t                startRecordingMode();
+
+    // internal function used by sendCommand to enable/disable shutter sound.
+    status_t                enableShutterSound(bool enable);
+
+    // these are static callback functions
+    static void             notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2, void* user);
+    static void             dataCallback(int32_t msgType, const sp<IMemory>& dataPtr,
+            camera_frame_metadata_t *metadata, void* user);
+    static void             dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr, void* user);
+    // handlers for messages
+    void                    handleShutter(void);
+    void                    handlePreviewData(int32_t msgType, const sp<IMemory>& mem,
+            camera_frame_metadata_t *metadata);
+    void                    handlePostview(const sp<IMemory>& mem);
+    void                    handleRawPicture(const sp<IMemory>& mem);
+    void                    handleCompressedPicture(const sp<IMemory>& mem);
+    void                    handleGenericNotify(int32_t msgType, int32_t ext1, int32_t ext2);
+    void                    handleGenericData(int32_t msgType, const sp<IMemory>& dataPtr,
+            camera_frame_metadata_t *metadata);
+    void                    handleGenericDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr);
+
+    void                    copyFrameAndPostCopiedFrame(
+        int32_t msgType,
+        const sp<ICameraClient>& client,
+        const sp<IMemoryHeap>& heap,
+        size_t offset, size_t size,
+        camera_frame_metadata_t *metadata);
+
+    int                     getOrientation(int orientation, bool mirror);
+
+    status_t                setPreviewWindow(
+        const sp<IBinder>& binder,
+        const sp<ANativeWindow>& window);
+
+
+    // these are initialized in the constructor.
+    sp<CameraHardwareInterface>     mHardware;       // cleared after disconnect()
+    int                             mPreviewCallbackFlag;
+    int                             mOrientation;     // Current display orientation
+    bool                            mPlayShutterSound;
+
+    // Ensures atomicity among the public methods
+    mutable Mutex                   mLock;
+    // This is a binder of Surface or SurfaceTexture.
+    sp<IBinder>                     mSurface;
+    sp<ANativeWindow>               mPreviewWindow;
+
+    // If the user want us to return a copy of the preview frame (instead
+    // of the original one), we allocate mPreviewBuffer and reuse it if possible.
+    sp<MemoryHeapBase>              mPreviewBuffer;
+
+    // We need to avoid the deadlock when the incoming command thread and
+    // the CameraHardwareInterface callback thread both want to grab mLock.
+    // An extra flag is used to tell the callback thread that it should stop
+    // trying to deliver the callback messages if the client is not
+    // interested in it anymore. For example, if the client is calling
+    // stopPreview(), the preview frame messages do not need to be delivered
+    // anymore.
+
+    // This function takes the same parameter as the enableMsgType() and
+    // disableMsgType() functions in CameraHardwareInterface.
+    void                    enableMsgType(int32_t msgType);
+    void                    disableMsgType(int32_t msgType);
+    volatile int32_t        mMsgEnabled;
+
+    // This function keeps trying to grab mLock, or give up if the message
+    // is found to be disabled. It returns true if mLock is grabbed.
+    bool                    lockIfMessageWanted(int32_t msgType);
+};
+
+}
+
+#endif
diff --git a/services/camera/libcameraservice/CameraHardwareInterface.h b/services/camera/libcameraservice/CameraHardwareInterface.h
index 87a0802..05ac9fa 100644
--- a/services/camera/libcameraservice/CameraHardwareInterface.h
+++ b/services/camera/libcameraservice/CameraHardwareInterface.h
@@ -569,7 +569,7 @@
         int rc;
         ANativeWindow *a = anw(w);
         ANativeWindowBuffer* anb;
-        rc = a->dequeueBuffer(a, &anb);
+        rc = native_window_dequeue_buffer_and_wait(a, &anb);
         if (!rc) {
             *buffer = &anb->handle;
             *stride = anb->stride;
@@ -587,8 +587,7 @@
                       buffer_handle_t* buffer)
     {
         ANativeWindow *a = anw(w);
-        return a->lockBuffer(a,
-                  container_of(buffer, ANativeWindowBuffer, handle));
+        return 0;
     }
 
     static int __enqueue_buffer(struct preview_stream_ops* w,
@@ -596,7 +595,7 @@
     {
         ANativeWindow *a = anw(w);
         return a->queueBuffer(a,
-                  container_of(buffer, ANativeWindowBuffer, handle));
+                  container_of(buffer, ANativeWindowBuffer, handle), -1);
     }
 
     static int __cancel_buffer(struct preview_stream_ops* w,
@@ -604,7 +603,7 @@
     {
         ANativeWindow *a = anw(w);
         return a->cancelBuffer(a,
-                  container_of(buffer, ANativeWindowBuffer, handle));
+                  container_of(buffer, ANativeWindowBuffer, handle), -1);
     }
 
     static int __set_buffer_count(struct preview_stream_ops* w, int count)
diff --git a/services/camera/libcameraservice/CameraHardwareStub.cpp b/services/camera/libcameraservice/CameraHardwareStub.cpp
deleted file mode 100644
index cdfb2f5..0000000
--- a/services/camera/libcameraservice/CameraHardwareStub.cpp
+++ /dev/null
@@ -1,410 +0,0 @@
-/*
-**
-** Copyright 2008, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#define LOG_TAG "CameraHardwareStub"
-#include <utils/Log.h>
-
-#include "CameraHardwareStub.h"
-#include <utils/threads.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-
-#include "CannedJpeg.h"
-
-namespace android {
-
-CameraHardwareStub::CameraHardwareStub()
-                  : mParameters(),
-                    mPreviewHeap(0),
-                    mRawHeap(0),
-                    mFakeCamera(0),
-                    mPreviewFrameSize(0),
-                    mNotifyCb(0),
-                    mDataCb(0),
-                    mDataCbTimestamp(0),
-                    mCallbackCookie(0),
-                    mMsgEnabled(0),
-                    mCurrentPreviewFrame(0)
-{
-    initDefaultParameters();
-}
-
-void CameraHardwareStub::initDefaultParameters()
-{
-    CameraParameters p;
-
-    p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES, "320x240");
-    p.setPreviewSize(320, 240);
-    p.setPreviewFrameRate(15);
-    p.setPreviewFormat(CameraParameters::PIXEL_FORMAT_YUV420SP);
-
-    p.set(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES, "320x240");
-    p.setPictureSize(320, 240);
-    p.setPictureFormat(CameraParameters::PIXEL_FORMAT_JPEG);
-
-    if (setParameters(p) != NO_ERROR) {
-        ALOGE("Failed to set default parameters?!");
-    }
-}
-
-void CameraHardwareStub::initHeapLocked()
-{
-    // Create raw heap.
-    int picture_width, picture_height;
-    mParameters.getPictureSize(&picture_width, &picture_height);
-    mRawHeap = new MemoryHeapBase(picture_width * picture_height * 3 / 2);
-
-    int preview_width, preview_height;
-    mParameters.getPreviewSize(&preview_width, &preview_height);
-    ALOGD("initHeapLocked: preview size=%dx%d", preview_width, preview_height);
-
-    // Note that we enforce yuv420sp in setParameters().
-    int how_big = preview_width * preview_height * 3 / 2;
-
-    // If we are being reinitialized to the same size as before, no
-    // work needs to be done.
-    if (how_big == mPreviewFrameSize)
-        return;
-
-    mPreviewFrameSize = how_big;
-
-    // Make a new mmap'ed heap that can be shared across processes.
-    // use code below to test with pmem
-    mPreviewHeap = new MemoryHeapBase(mPreviewFrameSize * kBufferCount);
-    // Make an IMemory for each frame so that we can reuse them in callbacks.
-    for (int i = 0; i < kBufferCount; i++) {
-        mBuffers[i] = new MemoryBase(mPreviewHeap, i * mPreviewFrameSize, mPreviewFrameSize);
-    }
-
-    // Recreate the fake camera to reflect the current size.
-    delete mFakeCamera;
-    mFakeCamera = new FakeCamera(preview_width, preview_height);
-}
-
-CameraHardwareStub::~CameraHardwareStub()
-{
-    delete mFakeCamera;
-    mFakeCamera = 0; // paranoia
-}
-
-status_t CameraHardwareStub::setPreviewWindow(const sp<ANativeWindow>& buf)
-{
-    return NO_ERROR;
-}
-
-sp<IMemoryHeap> CameraHardwareStub::getRawHeap() const
-{
-    return mRawHeap;
-}
-
-void CameraHardwareStub::setCallbacks(notify_callback notify_cb,
-                                      data_callback data_cb,
-                                      data_callback_timestamp data_cb_timestamp,
-                                      void* user)
-{
-    Mutex::Autolock lock(mLock);
-    mNotifyCb = notify_cb;
-    mDataCb = data_cb;
-    mDataCbTimestamp = data_cb_timestamp;
-    mCallbackCookie = user;
-}
-
-void CameraHardwareStub::enableMsgType(int32_t msgType)
-{
-    Mutex::Autolock lock(mLock);
-    mMsgEnabled |= msgType;
-}
-
-void CameraHardwareStub::disableMsgType(int32_t msgType)
-{
-    Mutex::Autolock lock(mLock);
-    mMsgEnabled &= ~msgType;
-}
-
-bool CameraHardwareStub::msgTypeEnabled(int32_t msgType)
-{
-    Mutex::Autolock lock(mLock);
-    return (mMsgEnabled & msgType);
-}
-
-// ---------------------------------------------------------------------------
-
-int CameraHardwareStub::previewThread()
-{
-    mLock.lock();
-        // the attributes below can change under our feet...
-
-        int previewFrameRate = mParameters.getPreviewFrameRate();
-
-        // Find the offset within the heap of the current buffer.
-        ssize_t offset = mCurrentPreviewFrame * mPreviewFrameSize;
-
-        sp<MemoryHeapBase> heap = mPreviewHeap;
-
-        // this assumes the internal state of fake camera doesn't change
-        // (or is thread safe)
-        FakeCamera* fakeCamera = mFakeCamera;
-
-        sp<MemoryBase> buffer = mBuffers[mCurrentPreviewFrame];
-
-    mLock.unlock();
-
-    // TODO: here check all the conditions that could go wrong
-    if (buffer != 0) {
-        // Calculate how long to wait between frames.
-        int delay = (int)(1000000.0f / float(previewFrameRate));
-
-        // This is always valid, even if the client died -- the memory
-        // is still mapped in our process.
-        void *base = heap->base();
-
-        // Fill the current frame with the fake camera.
-        uint8_t *frame = ((uint8_t *)base) + offset;
-        fakeCamera->getNextFrameAsYuv420(frame);
-
-        //ALOGV("previewThread: generated frame to buffer %d", mCurrentPreviewFrame);
-
-        // Notify the client of a new frame.
-        if (mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME)
-            mDataCb(CAMERA_MSG_PREVIEW_FRAME, buffer, NULL, mCallbackCookie);
-
-        // Advance the buffer pointer.
-        mCurrentPreviewFrame = (mCurrentPreviewFrame + 1) % kBufferCount;
-
-        // Wait for it...
-        usleep(delay);
-    }
-
-    return NO_ERROR;
-}
-
-status_t CameraHardwareStub::startPreview()
-{
-    Mutex::Autolock lock(mLock);
-    if (mPreviewThread != 0) {
-        // already running
-        return INVALID_OPERATION;
-    }
-    mPreviewThread = new PreviewThread(this);
-    return NO_ERROR;
-}
-
-void CameraHardwareStub::stopPreview()
-{
-    sp<PreviewThread> previewThread;
-
-    { // scope for the lock
-        Mutex::Autolock lock(mLock);
-        previewThread = mPreviewThread;
-    }
-
-    // don't hold the lock while waiting for the thread to quit
-    if (previewThread != 0) {
-        previewThread->requestExitAndWait();
-    }
-
-    Mutex::Autolock lock(mLock);
-    mPreviewThread.clear();
-}
-
-bool CameraHardwareStub::previewEnabled() {
-    return mPreviewThread != 0;
-}
-
-status_t CameraHardwareStub::startRecording()
-{
-    return UNKNOWN_ERROR;
-}
-
-void CameraHardwareStub::stopRecording()
-{
-}
-
-bool CameraHardwareStub::recordingEnabled()
-{
-    return false;
-}
-
-void CameraHardwareStub::releaseRecordingFrame(const sp<IMemory>& mem)
-{
-}
-
-// ---------------------------------------------------------------------------
-
-int CameraHardwareStub::beginAutoFocusThread(void *cookie)
-{
-    CameraHardwareStub *c = (CameraHardwareStub *)cookie;
-    return c->autoFocusThread();
-}
-
-int CameraHardwareStub::autoFocusThread()
-{
-    if (mMsgEnabled & CAMERA_MSG_FOCUS)
-        mNotifyCb(CAMERA_MSG_FOCUS, true, 0, mCallbackCookie);
-    return NO_ERROR;
-}
-
-status_t CameraHardwareStub::autoFocus()
-{
-    Mutex::Autolock lock(mLock);
-    if (createThread(beginAutoFocusThread, this) == false)
-        return UNKNOWN_ERROR;
-    return NO_ERROR;
-}
-
-status_t CameraHardwareStub::cancelAutoFocus()
-{
-    return NO_ERROR;
-}
-
-/*static*/ int CameraHardwareStub::beginPictureThread(void *cookie)
-{
-    CameraHardwareStub *c = (CameraHardwareStub *)cookie;
-    return c->pictureThread();
-}
-
-int CameraHardwareStub::pictureThread()
-{
-    if (mMsgEnabled & CAMERA_MSG_SHUTTER)
-        mNotifyCb(CAMERA_MSG_SHUTTER, 0, 0, mCallbackCookie);
-
-    if (mMsgEnabled & CAMERA_MSG_RAW_IMAGE) {
-        //FIXME: use a canned YUV image!
-        // In the meantime just make another fake camera picture.
-        int w, h;
-        mParameters.getPictureSize(&w, &h);
-        sp<MemoryBase> mem = new MemoryBase(mRawHeap, 0, w * h * 3 / 2);
-        FakeCamera cam(w, h);
-        cam.getNextFrameAsYuv420((uint8_t *)mRawHeap->base());
-        mDataCb(CAMERA_MSG_RAW_IMAGE, mem, NULL, mCallbackCookie);
-    }
-
-    if (mMsgEnabled & CAMERA_MSG_COMPRESSED_IMAGE) {
-        sp<MemoryHeapBase> heap = new MemoryHeapBase(kCannedJpegSize);
-        sp<MemoryBase> mem = new MemoryBase(heap, 0, kCannedJpegSize);
-        memcpy(heap->base(), kCannedJpeg, kCannedJpegSize);
-        mDataCb(CAMERA_MSG_COMPRESSED_IMAGE, mem, NULL, mCallbackCookie);
-    }
-    return NO_ERROR;
-}
-
-status_t CameraHardwareStub::takePicture()
-{
-    stopPreview();
-    if (createThread(beginPictureThread, this) == false)
-        return UNKNOWN_ERROR;
-    return NO_ERROR;
-}
-
-status_t CameraHardwareStub::cancelPicture()
-{
-    return NO_ERROR;
-}
-
-status_t CameraHardwareStub::dump(int fd, const Vector<String16>& args) const
-{
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-    AutoMutex lock(&mLock);
-    if (mFakeCamera != 0) {
-        mFakeCamera->dump(fd);
-        mParameters.dump(fd, args);
-        snprintf(buffer, 255, " preview frame(%d), size (%d), running(%s)\n", mCurrentPreviewFrame, mPreviewFrameSize, mPreviewRunning?"true": "false");
-        result.append(buffer);
-    } else {
-        result.append("No camera client yet.\n");
-    }
-    write(fd, result.string(), result.size());
-    return NO_ERROR;
-}
-
-status_t CameraHardwareStub::setParameters(const CameraParameters& params)
-{
-    Mutex::Autolock lock(mLock);
-    // XXX verify params
-
-    if (strcmp(params.getPreviewFormat(),
-        CameraParameters::PIXEL_FORMAT_YUV420SP) != 0) {
-        ALOGE("Only yuv420sp preview is supported");
-        return -1;
-    }
-
-    if (strcmp(params.getPictureFormat(),
-        CameraParameters::PIXEL_FORMAT_JPEG) != 0) {
-        ALOGE("Only jpeg still pictures are supported");
-        return -1;
-    }
-
-    int w, h;
-    params.getPictureSize(&w, &h);
-    if (w != kCannedJpegWidth && h != kCannedJpegHeight) {
-        ALOGE("Still picture size must be size of canned JPEG (%dx%d)",
-             kCannedJpegWidth, kCannedJpegHeight);
-        return -1;
-    }
-
-    mParameters = params;
-    initHeapLocked();
-
-    return NO_ERROR;
-}
-
-CameraParameters CameraHardwareStub::getParameters() const
-{
-    Mutex::Autolock lock(mLock);
-    return mParameters;
-}
-
-status_t CameraHardwareStub::sendCommand(int32_t command, int32_t arg1,
-                                         int32_t arg2)
-{
-    return BAD_VALUE;
-}
-
-void CameraHardwareStub::release()
-{
-}
-
-sp<CameraHardwareInterface> CameraHardwareStub::createInstance()
-{
-    return new CameraHardwareStub();
-}
-
-static CameraInfo sCameraInfo[] = {
-    {
-        CAMERA_FACING_BACK,
-        90,  /* orientation */
-    }
-};
-
-extern "C" int HAL_getNumberOfCameras()
-{
-    return sizeof(sCameraInfo) / sizeof(sCameraInfo[0]);
-}
-
-extern "C" void HAL_getCameraInfo(int cameraId, struct CameraInfo* cameraInfo)
-{
-    memcpy(cameraInfo, &sCameraInfo[cameraId], sizeof(CameraInfo));
-}
-
-extern "C" sp<CameraHardwareInterface> HAL_openCameraHardware(int cameraId)
-{
-    return CameraHardwareStub::createInstance();
-}
-
-}; // namespace android
diff --git a/services/camera/libcameraservice/CameraHardwareStub.h b/services/camera/libcameraservice/CameraHardwareStub.h
deleted file mode 100644
index c6d8756..0000000
--- a/services/camera/libcameraservice/CameraHardwareStub.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
-**
-** Copyright 2008, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#ifndef ANDROID_HARDWARE_CAMERA_HARDWARE_STUB_H
-#define ANDROID_HARDWARE_CAMERA_HARDWARE_STUB_H
-
-#include "FakeCamera.h"
-#include <utils/threads.h>
-#include <camera/CameraHardwareInterface.h>
-#include <binder/MemoryBase.h>
-#include <binder/MemoryHeapBase.h>
-#include <utils/threads.h>
-
-namespace android {
-
-class CameraHardwareStub : public CameraHardwareInterface {
-public:
-    virtual status_t setPreviewWindow(const sp<ANativeWindow>& buf);
-    virtual sp<IMemoryHeap> getRawHeap() const;
-
-    virtual void        setCallbacks(notify_callback notify_cb,
-                                     data_callback data_cb,
-                                     data_callback_timestamp data_cb_timestamp,
-                                     void* user);
-
-    virtual void        enableMsgType(int32_t msgType);
-    virtual void        disableMsgType(int32_t msgType);
-    virtual bool        msgTypeEnabled(int32_t msgType);
-
-    virtual status_t    startPreview();
-    virtual void        stopPreview();
-    virtual bool        previewEnabled();
-
-    virtual status_t    startRecording();
-    virtual void        stopRecording();
-    virtual bool        recordingEnabled();
-    virtual void        releaseRecordingFrame(const sp<IMemory>& mem);
-
-    virtual status_t    autoFocus();
-    virtual status_t    cancelAutoFocus();
-    virtual status_t    takePicture();
-    virtual status_t    cancelPicture();
-    virtual status_t    dump(int fd, const Vector<String16>& args) const;
-    virtual status_t    setParameters(const CameraParameters& params);
-    virtual CameraParameters  getParameters() const;
-    virtual status_t    sendCommand(int32_t command, int32_t arg1,
-                                    int32_t arg2);
-    virtual void release();
-
-    static sp<CameraHardwareInterface> createInstance();
-
-private:
-                        CameraHardwareStub();
-    virtual             ~CameraHardwareStub();
-
-    static const int kBufferCount = 4;
-
-    class PreviewThread : public Thread {
-        CameraHardwareStub* mHardware;
-    public:
-        PreviewThread(CameraHardwareStub* hw) :
-                Thread(false), mHardware(hw) { }
-        virtual void onFirstRef() {
-            run("CameraPreviewThread", PRIORITY_URGENT_DISPLAY);
-        }
-        virtual bool threadLoop() {
-            mHardware->previewThread();
-            // loop until we need to quit
-            return true;
-        }
-    };
-
-    void initDefaultParameters();
-    void initHeapLocked();
-
-    int previewThread();
-
-    static int beginAutoFocusThread(void *cookie);
-    int autoFocusThread();
-
-    static int beginPictureThread(void *cookie);
-    int pictureThread();
-
-    mutable Mutex       mLock;
-
-    CameraParameters    mParameters;
-
-    sp<MemoryHeapBase>  mPreviewHeap;
-    sp<MemoryHeapBase>  mRawHeap;
-    sp<MemoryBase>      mBuffers[kBufferCount];
-
-    FakeCamera          *mFakeCamera;
-    bool                mPreviewRunning;
-    int                 mPreviewFrameSize;
-
-    // protected by mLock
-    sp<PreviewThread>   mPreviewThread;
-
-    notify_callback    mNotifyCb;
-    data_callback      mDataCb;
-    data_callback_timestamp mDataCbTimestamp;
-    void               *mCallbackCookie;
-
-    int32_t             mMsgEnabled;
-
-    // only used from PreviewThread
-    int                 mCurrentPreviewFrame;
-};
-
-}; // namespace android
-
-#endif
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 385be50..878afde 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -38,14 +38,15 @@
 #include <utils/String16.h>
 
 #include "CameraService.h"
-#include "CameraHardwareInterface.h"
+#include "CameraClient.h"
+#include "Camera2Client.h"
 
 namespace android {
 
 // ----------------------------------------------------------------------------
 // Logging support -- this is for debugging only
 // Use "adb shell dumpsys media.camera -v 1" to change it.
-static volatile int32_t gLogLevel = 0;
+volatile int32_t gLogLevel = 0;
 
 #define LOG1(...) ALOGD_IF(gLogLevel >= 1, __VA_ARGS__);
 #define LOG2(...) ALOGD_IF(gLogLevel >= 2, __VA_ARGS__);
@@ -133,7 +134,6 @@
 sp<ICamera> CameraService::connect(
         const sp<ICameraClient>& cameraClient, int cameraId) {
     int callingPid = getCallingPid();
-    sp<CameraHardwareInterface> hardware = NULL;
 
     LOG1("CameraService::connect E (pid %d, id %d)", callingPid, cameraId);
 
@@ -186,16 +186,31 @@
         return NULL;
     }
 
-    char camera_device_name[10];
-    snprintf(camera_device_name, sizeof(camera_device_name), "%d", cameraId);
+    int deviceVersion;
+    if (mModule->common.module_api_version == CAMERA_MODULE_API_VERSION_2_0) {
+        deviceVersion = info.device_version;
+    } else {
+        deviceVersion = CAMERA_DEVICE_API_VERSION_1_0;
+    }
 
-    hardware = new CameraHardwareInterface(camera_device_name);
-    if (hardware->initialize(&mModule->common) != OK) {
-        hardware.clear();
+    switch(deviceVersion) {
+      case CAMERA_DEVICE_API_VERSION_1_0:
+        client = new CameraClient(this, cameraClient, cameraId,
+                info.facing, callingPid);
+        break;
+      case CAMERA_DEVICE_API_VERSION_2_0:
+        client = new Camera2Client(this, cameraClient, cameraId,
+                info.facing, callingPid);
+        break;
+      default:
+        ALOGE("Unknown camera device HAL version: %d", deviceVersion);
         return NULL;
     }
 
-    client = new Client(this, cameraClient, hardware, cameraId, info.facing, callingPid);
+    if (client->initialize(mModule) != OK) {
+        return NULL;
+    }
+
     mClient[cameraId] = client;
     LOG1("CameraService::connect X (id %d)", cameraId);
     return client;
@@ -335,34 +350,17 @@
 
 CameraService::Client::Client(const sp<CameraService>& cameraService,
         const sp<ICameraClient>& cameraClient,
-        const sp<CameraHardwareInterface>& hardware,
         int cameraId, int cameraFacing, int clientPid) {
     int callingPid = getCallingPid();
     LOG1("Client::Client E (pid %d, id %d)", callingPid, cameraId);
 
     mCameraService = cameraService;
     mCameraClient = cameraClient;
-    mHardware = hardware;
     mCameraId = cameraId;
     mCameraFacing = cameraFacing;
     mClientPid = clientPid;
-    mMsgEnabled = 0;
-    mSurface = 0;
-    mPreviewWindow = 0;
     mDestructionStarted = false;
-    mHardware->setCallbacks(notifyCallback,
-                            dataCallback,
-                            dataCallbackTimestamp,
-                            (void *)cameraId);
 
-    // Enable zoom, error, focus, and metadata messages by default
-    enableMsgType(CAMERA_MSG_ERROR | CAMERA_MSG_ZOOM | CAMERA_MSG_FOCUS |
-                  CAMERA_MSG_PREVIEW_METADATA | CAMERA_MSG_FOCUS_MOVE);
-
-    // Callback is disabled by default
-    mPreviewCallbackFlag = CAMERA_FRAME_CALLBACK_FLAG_NOOP;
-    mOrientation = getOrientation(0, mCameraFacing == CAMERA_FACING_FRONT);
-    mPlayShutterSound = true;
     cameraService->setCameraBusy(cameraId);
     cameraService->loadSound();
     LOG1("Client::Client X (pid %d, id %d)", callingPid, cameraId);
@@ -370,582 +368,7 @@
 
 // tear down the client
 CameraService::Client::~Client() {
-    // this lock should never be NULL
-    Mutex* lock = mCameraService->getClientLockById(mCameraId);
-    lock->lock();
-    mDestructionStarted = true;
-    // client will not be accessed from callback. should unlock to prevent dead-lock in disconnect
-    lock->unlock();
-    int callingPid = getCallingPid();
-    LOG1("Client::~Client E (pid %d, this %p)", callingPid, this);
-
-    // set mClientPid to let disconnet() tear down the hardware
-    mClientPid = callingPid;
-    disconnect();
     mCameraService->releaseSound();
-    LOG1("Client::~Client X (pid %d, this %p)", callingPid, this);
-}
-
-// ----------------------------------------------------------------------------
-
-status_t CameraService::Client::checkPid() const {
-    int callingPid = getCallingPid();
-    if (callingPid == mClientPid) return NO_ERROR;
-
-    ALOGW("attempt to use a locked camera from a different process"
-         " (old pid %d, new pid %d)", mClientPid, callingPid);
-    return EBUSY;
-}
-
-status_t CameraService::Client::checkPidAndHardware() const {
-    status_t result = checkPid();
-    if (result != NO_ERROR) return result;
-    if (mHardware == 0) {
-        ALOGE("attempt to use a camera after disconnect() (pid %d)", getCallingPid());
-        return INVALID_OPERATION;
-    }
-    return NO_ERROR;
-}
-
-status_t CameraService::Client::lock() {
-    int callingPid = getCallingPid();
-    LOG1("lock (pid %d)", callingPid);
-    Mutex::Autolock ilock(mICameraLock);
-    Mutex::Autolock lock(mLock);
-
-    // lock camera to this client if the the camera is unlocked
-    if (mClientPid == 0) {
-        mClientPid = callingPid;
-        return NO_ERROR;
-    }
-
-    // returns NO_ERROR if the client already owns the camera, EBUSY otherwise
-    return checkPid();
-}
-
-status_t CameraService::Client::unlock() {
-    int callingPid = getCallingPid();
-    LOG1("unlock (pid %d)", callingPid);
-    Mutex::Autolock iLock(mICameraLock);
-    Mutex::Autolock lock(mLock);
-
-    // allow anyone to use camera (after they lock the camera)
-    status_t result = checkPid();
-    if (result == NO_ERROR) {
-        if (mHardware->recordingEnabled()) {
-            ALOGE("Not allowed to unlock camera during recording.");
-            return INVALID_OPERATION;
-        }
-        mClientPid = 0;
-        LOG1("clear mCameraClient (pid %d)", callingPid);
-        // we need to remove the reference to ICameraClient so that when the app
-        // goes away, the reference count goes to 0.
-        mCameraClient.clear();
-    }
-    return result;
-}
-
-// connect a new client to the camera
-status_t CameraService::Client::connect(const sp<ICameraClient>& client) {
-    int callingPid = getCallingPid();
-    LOG1("connect E (pid %d)", callingPid);
-    Mutex::Autolock iLock(mICameraLock);
-    Mutex::Autolock lock(mLock);
-
-    if (mClientPid != 0 && checkPid() != NO_ERROR) {
-        ALOGW("Tried to connect to a locked camera (old pid %d, new pid %d)",
-                mClientPid, callingPid);
-        return EBUSY;
-    }
-
-    if (mCameraClient != 0 && (client->asBinder() == mCameraClient->asBinder())) {
-        LOG1("Connect to the same client");
-        return NO_ERROR;
-    }
-
-    mPreviewCallbackFlag = CAMERA_FRAME_CALLBACK_FLAG_NOOP;
-    mClientPid = callingPid;
-    mCameraClient = client;
-
-    LOG1("connect X (pid %d)", callingPid);
-    return NO_ERROR;
-}
-
-static void disconnectWindow(const sp<ANativeWindow>& window) {
-    if (window != 0) {
-        status_t result = native_window_api_disconnect(window.get(),
-                NATIVE_WINDOW_API_CAMERA);
-        if (result != NO_ERROR) {
-            ALOGW("native_window_api_disconnect failed: %s (%d)", strerror(-result),
-                    result);
-        }
-    }
-}
-
-void CameraService::Client::disconnect() {
-    int callingPid = getCallingPid();
-    LOG1("disconnect E (pid %d)", callingPid);
-    Mutex::Autolock iLock(mICameraLock);
-    Mutex::Autolock lock(mLock);
-
-    if (checkPid() != NO_ERROR) {
-        ALOGW("different client - don't disconnect");
-        return;
-    }
-
-    if (mClientPid <= 0) {
-        LOG1("camera is unlocked (mClientPid = %d), don't tear down hardware", mClientPid);
-        return;
-    }
-
-    // Make sure disconnect() is done once and once only, whether it is called
-    // from the user directly, or called by the destructor.
-    if (mHardware == 0) return;
-
-    LOG1("hardware teardown");
-    // Before destroying mHardware, we must make sure it's in the
-    // idle state.
-    // Turn off all messages.
-    disableMsgType(CAMERA_MSG_ALL_MSGS);
-    mHardware->stopPreview();
-    mHardware->cancelPicture();
-    // Release the hardware resources.
-    mHardware->release();
-
-    // Release the held ANativeWindow resources.
-    if (mPreviewWindow != 0) {
-        disconnectWindow(mPreviewWindow);
-        mPreviewWindow = 0;
-        mHardware->setPreviewWindow(mPreviewWindow);
-    }
-    mHardware.clear();
-
-    mCameraService->removeClient(mCameraClient);
-    mCameraService->setCameraFree(mCameraId);
-
-    LOG1("disconnect X (pid %d)", callingPid);
-}
-
-// ----------------------------------------------------------------------------
-
-status_t CameraService::Client::setPreviewWindow(const sp<IBinder>& binder,
-        const sp<ANativeWindow>& window) {
-    Mutex::Autolock iLock(mICameraLock);
-    Mutex::Autolock lock(mLock);
-    status_t result = checkPidAndHardware();
-    if (result != NO_ERROR) return result;
-
-    // return if no change in surface.
-    if (binder == mSurface) {
-        return NO_ERROR;
-    }
-
-    if (window != 0) {
-        result = native_window_api_connect(window.get(), NATIVE_WINDOW_API_CAMERA);
-        if (result != NO_ERROR) {
-            ALOGE("native_window_api_connect failed: %s (%d)", strerror(-result),
-                    result);
-            return result;
-        }
-    }
-
-    // If preview has been already started, register preview buffers now.
-    if (mHardware->previewEnabled()) {
-        if (window != 0) {
-            native_window_set_scaling_mode(window.get(),
-                    NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
-            native_window_set_buffers_transform(window.get(), mOrientation);
-            result = mHardware->setPreviewWindow(window);
-        }
-    }
-
-    if (result == NO_ERROR) {
-        // Everything has succeeded.  Disconnect the old window and remember the
-        // new window.
-        disconnectWindow(mPreviewWindow);
-        mSurface = binder;
-        mPreviewWindow = window;
-    } else {
-        // Something went wrong after we connected to the new window, so
-        // disconnect here.
-        disconnectWindow(window);
-    }
-
-    return result;
-}
-
-// set the Surface that the preview will use
-status_t CameraService::Client::setPreviewDisplay(const sp<Surface>& surface) {
-    LOG1("setPreviewDisplay(%p) (pid %d)", surface.get(), getCallingPid());
-
-    sp<IBinder> binder(surface != 0 ? surface->asBinder() : 0);
-    sp<ANativeWindow> window(surface);
-    return setPreviewWindow(binder, window);
-}
-
-// set the SurfaceTexture that the preview will use
-status_t CameraService::Client::setPreviewTexture(
-        const sp<ISurfaceTexture>& surfaceTexture) {
-    LOG1("setPreviewTexture(%p) (pid %d)", surfaceTexture.get(),
-            getCallingPid());
-
-    sp<IBinder> binder;
-    sp<ANativeWindow> window;
-    if (surfaceTexture != 0) {
-        binder = surfaceTexture->asBinder();
-        window = new SurfaceTextureClient(surfaceTexture);
-    }
-    return setPreviewWindow(binder, window);
-}
-
-// set the preview callback flag to affect how the received frames from
-// preview are handled.
-void CameraService::Client::setPreviewCallbackFlag(int callback_flag) {
-    LOG1("setPreviewCallbackFlag(%d) (pid %d)", callback_flag, getCallingPid());
-    Mutex::Autolock iLock(mICameraLock);
-    Mutex::Autolock lock(mLock);
-    if (checkPidAndHardware() != NO_ERROR) return;
-
-    mPreviewCallbackFlag = callback_flag;
-    if (mPreviewCallbackFlag & CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK) {
-        enableMsgType(CAMERA_MSG_PREVIEW_FRAME);
-    } else {
-        disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
-    }
-}
-
-// start preview mode
-status_t CameraService::Client::startPreview() {
-    LOG1("startPreview (pid %d)", getCallingPid());
-    return startCameraMode(CAMERA_PREVIEW_MODE);
-}
-
-// start recording mode
-status_t CameraService::Client::startRecording() {
-    LOG1("startRecording (pid %d)", getCallingPid());
-    return startCameraMode(CAMERA_RECORDING_MODE);
-}
-
-// start preview or recording
-status_t CameraService::Client::startCameraMode(camera_mode mode) {
-    LOG1("startCameraMode(%d)", mode);
-    Mutex::Autolock iLock(mICameraLock);
-    Mutex::Autolock lock(mLock);
-    status_t result = checkPidAndHardware();
-    if (result != NO_ERROR) return result;
-
-    switch(mode) {
-        case CAMERA_PREVIEW_MODE:
-            if (mSurface == 0 && mPreviewWindow == 0) {
-                LOG1("mSurface is not set yet.");
-                // still able to start preview in this case.
-            }
-            return startPreviewMode();
-        case CAMERA_RECORDING_MODE:
-            if (mSurface == 0 && mPreviewWindow == 0) {
-                ALOGE("mSurface or mPreviewWindow must be set before startRecordingMode.");
-                return INVALID_OPERATION;
-            }
-            return startRecordingMode();
-        default:
-            return UNKNOWN_ERROR;
-    }
-}
-
-status_t CameraService::Client::startPreviewMode() {
-    LOG1("startPreviewMode");
-    status_t result = NO_ERROR;
-
-    // if preview has been enabled, nothing needs to be done
-    if (mHardware->previewEnabled()) {
-        return NO_ERROR;
-    }
-
-    if (mPreviewWindow != 0) {
-        native_window_set_scaling_mode(mPreviewWindow.get(),
-                NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
-        native_window_set_buffers_transform(mPreviewWindow.get(),
-                mOrientation);
-    }
-    mHardware->setPreviewWindow(mPreviewWindow);
-    result = mHardware->startPreview();
-
-    return result;
-}
-
-status_t CameraService::Client::startRecordingMode() {
-    LOG1("startRecordingMode");
-    status_t result = NO_ERROR;
-
-    // if recording has been enabled, nothing needs to be done
-    if (mHardware->recordingEnabled()) {
-        return NO_ERROR;
-    }
-
-    // if preview has not been started, start preview first
-    if (!mHardware->previewEnabled()) {
-        result = startPreviewMode();
-        if (result != NO_ERROR) {
-            return result;
-        }
-    }
-
-    // start recording mode
-    enableMsgType(CAMERA_MSG_VIDEO_FRAME);
-    mCameraService->playSound(SOUND_RECORDING);
-    result = mHardware->startRecording();
-    if (result != NO_ERROR) {
-        ALOGE("mHardware->startRecording() failed with status %d", result);
-    }
-    return result;
-}
-
-// stop preview mode
-void CameraService::Client::stopPreview() {
-    LOG1("stopPreview (pid %d)", getCallingPid());
-    Mutex::Autolock iLock(mICameraLock);
-    Mutex::Autolock lock(mLock);
-    if (checkPidAndHardware() != NO_ERROR) return;
-
-
-    disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
-    mHardware->stopPreview();
-
-    mPreviewBuffer.clear();
-}
-
-// stop recording mode
-void CameraService::Client::stopRecording() {
-    LOG1("stopRecording (pid %d)", getCallingPid());
-    Mutex::Autolock iLock(mICameraLock);
-    Mutex::Autolock lock(mLock);
-    if (checkPidAndHardware() != NO_ERROR) return;
-
-    disableMsgType(CAMERA_MSG_VIDEO_FRAME);
-    mHardware->stopRecording();
-    mCameraService->playSound(SOUND_RECORDING);
-
-    mPreviewBuffer.clear();
-}
-
-// release a recording frame
-void CameraService::Client::releaseRecordingFrame(const sp<IMemory>& mem) {
-    Mutex::Autolock iLock(mICameraLock);
-    Mutex::Autolock lock(mLock);
-    if (checkPidAndHardware() != NO_ERROR) return;
-    mHardware->releaseRecordingFrame(mem);
-}
-
-status_t CameraService::Client::storeMetaDataInBuffers(bool enabled)
-{
-    LOG1("storeMetaDataInBuffers: %s", enabled? "true": "false");
-    Mutex::Autolock iLock(mICameraLock);
-    Mutex::Autolock lock(mLock);
-    if (checkPidAndHardware() != NO_ERROR) {
-        return UNKNOWN_ERROR;
-    }
-    return mHardware->storeMetaDataInBuffers(enabled);
-}
-
-bool CameraService::Client::previewEnabled() {
-    LOG1("previewEnabled (pid %d)", getCallingPid());
-
-    Mutex::Autolock iLock(mICameraLock);
-    Mutex::Autolock lock(mLock);
-    if (checkPidAndHardware() != NO_ERROR) return false;
-    return mHardware->previewEnabled();
-}
-
-bool CameraService::Client::recordingEnabled() {
-    LOG1("recordingEnabled (pid %d)", getCallingPid());
-
-    Mutex::Autolock iLock(mICameraLock);
-    Mutex::Autolock lock(mLock);
-    if (checkPidAndHardware() != NO_ERROR) return false;
-    return mHardware->recordingEnabled();
-}
-
-status_t CameraService::Client::autoFocus() {
-    LOG1("autoFocus (pid %d)", getCallingPid());
-
-    Mutex::Autolock iLock(mICameraLock);
-    Mutex::Autolock lock(mLock);
-    status_t result = checkPidAndHardware();
-    if (result != NO_ERROR) return result;
-
-    return mHardware->autoFocus();
-}
-
-status_t CameraService::Client::cancelAutoFocus() {
-    LOG1("cancelAutoFocus (pid %d)", getCallingPid());
-
-    Mutex::Autolock iLock(mICameraLock);
-    Mutex::Autolock lock(mLock);
-    status_t result = checkPidAndHardware();
-    if (result != NO_ERROR) return result;
-
-    return mHardware->cancelAutoFocus();
-}
-
-// take a picture - image is returned in callback
-status_t CameraService::Client::takePicture(int msgType) {
-    LOG1("takePicture (pid %d): 0x%x", getCallingPid(), msgType);
-
-    Mutex::Autolock iLock(mICameraLock);
-    int picMsgType = 0;
-    { // scope for lock
-        Mutex::Autolock lock(mLock);
-        status_t result = checkPidAndHardware();
-        if (result != NO_ERROR) return result;
-
-        if ((msgType & CAMERA_MSG_RAW_IMAGE) &&
-                (msgType & CAMERA_MSG_RAW_IMAGE_NOTIFY)) {
-            ALOGE("CAMERA_MSG_RAW_IMAGE and CAMERA_MSG_RAW_IMAGE_NOTIFY"
-                    " cannot be both enabled");
-            return BAD_VALUE;
-        }
-
-        // We only accept picture related message types
-        // and ignore other types of messages for takePicture().
-        picMsgType = msgType
-                & (CAMERA_MSG_SHUTTER |
-                        CAMERA_MSG_POSTVIEW_FRAME |
-                        CAMERA_MSG_RAW_IMAGE |
-                        CAMERA_MSG_RAW_IMAGE_NOTIFY |
-                        CAMERA_MSG_COMPRESSED_IMAGE);
-
-    }
-    enableMsgType(picMsgType);
-
-    return mHardware->takePicture();
-}
-
-// set preview/capture parameters - key/value pairs
-status_t CameraService::Client::setParameters(const String8& params) {
-    LOG1("setParameters (pid %d) (%s)", getCallingPid(), params.string());
-
-    Mutex::Autolock iLock(mICameraLock);
-    Mutex::Autolock lock(mLock);
-    status_t result = checkPidAndHardware();
-    if (result != NO_ERROR) return result;
-
-    CameraParameters p(params);
-    return mHardware->setParameters(p);
-}
-
-// get preview/capture parameters - key/value pairs
-String8 CameraService::Client::getParameters() const {
-    Mutex::Autolock iLock(mICameraLock);
-    Mutex::Autolock lock(mLock);
-    if (checkPidAndHardware() != NO_ERROR) return String8();
-
-    String8 params(mHardware->getParameters().flatten());
-    LOG1("getParameters (pid %d) (%s)", getCallingPid(), params.string());
-    return params;
-}
-
-// enable shutter sound
-status_t CameraService::Client::enableShutterSound(bool enable) {
-    LOG1("enableShutterSound (pid %d)", getCallingPid());
-
-    status_t result = checkPidAndHardware();
-    if (result != NO_ERROR) return result;
-
-    if (enable) {
-        mPlayShutterSound = true;
-        return OK;
-    }
-
-    // Disabling shutter sound may not be allowed. In that case only
-    // allow the mediaserver process to disable the sound.
-    char value[PROPERTY_VALUE_MAX];
-    property_get("ro.camera.sound.forced", value, "0");
-    if (strcmp(value, "0") != 0) {
-        // Disabling shutter sound is not allowed. Deny if the current
-        // process is not mediaserver.
-        if (getCallingPid() != getpid()) {
-            ALOGE("Failed to disable shutter sound. Permission denied (pid %d)", getCallingPid());
-            return PERMISSION_DENIED;
-        }
-    }
-
-    mPlayShutterSound = false;
-    return OK;
-}
-
-status_t CameraService::Client::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) {
-    LOG1("sendCommand (pid %d)", getCallingPid());
-    int orientation;
-    Mutex::Autolock iLock(mICameraLock);
-    Mutex::Autolock lock(mLock);
-    status_t result = checkPidAndHardware();
-    if (result != NO_ERROR) return result;
-
-    if (cmd == CAMERA_CMD_SET_DISPLAY_ORIENTATION) {
-        // Mirror the preview if the camera is front-facing.
-        orientation = getOrientation(arg1, mCameraFacing == CAMERA_FACING_FRONT);
-        if (orientation == -1) return BAD_VALUE;
-
-        if (mOrientation != orientation) {
-            mOrientation = orientation;
-            if (mPreviewWindow != 0) {
-                native_window_set_buffers_transform(mPreviewWindow.get(),
-                        mOrientation);
-            }
-        }
-        return OK;
-    } else if (cmd == CAMERA_CMD_ENABLE_SHUTTER_SOUND) {
-        switch (arg1) {
-            case 0:
-                enableShutterSound(false);
-                break;
-            case 1:
-                enableShutterSound(true);
-                break;
-            default:
-                return BAD_VALUE;
-        }
-        return OK;
-    } else if (cmd == CAMERA_CMD_PLAY_RECORDING_SOUND) {
-        mCameraService->playSound(SOUND_RECORDING);
-    } else if (cmd == CAMERA_CMD_PING) {
-        // If mHardware is 0, checkPidAndHardware will return error.
-        return OK;
-    }
-
-    return mHardware->sendCommand(cmd, arg1, arg2);
-}
-
-// ----------------------------------------------------------------------------
-
-void CameraService::Client::enableMsgType(int32_t msgType) {
-    android_atomic_or(msgType, &mMsgEnabled);
-    mHardware->enableMsgType(msgType);
-}
-
-void CameraService::Client::disableMsgType(int32_t msgType) {
-    android_atomic_and(~msgType, &mMsgEnabled);
-    mHardware->disableMsgType(msgType);
-}
-
-#define CHECK_MESSAGE_INTERVAL 10 // 10ms
-bool CameraService::Client::lockIfMessageWanted(int32_t msgType) {
-    int sleepCount = 0;
-    while (mMsgEnabled & msgType) {
-        if (mLock.tryLock() == NO_ERROR) {
-            if (sleepCount > 0) {
-                LOG1("lockIfMessageWanted(%d): waited for %d ms",
-                    msgType, sleepCount * CHECK_MESSAGE_INTERVAL);
-            }
-            return true;
-        }
-        if (sleepCount++ == 0) {
-            LOG1("lockIfMessageWanted(%d): enter sleep", msgType);
-        }
-        usleep(CHECK_MESSAGE_INTERVAL * 1000);
-    }
-    ALOGW("lockIfMessageWanted(%d): dropped unwanted message", msgType);
-    return false;
 }
 
 // ----------------------------------------------------------------------------
@@ -967,311 +390,12 @@
     // destruction already started, so should not be accessed
     if (client->mDestructionStarted) return NULL;
 
-    // The checks below are not necessary and are for debugging only.
-    if (client->mCameraService.get() != gCameraService) {
-        ALOGE("mismatch service!");
-        return NULL;
-    }
-
-    if (client->mHardware == 0) {
-        ALOGE("mHardware == 0: callback after disconnect()?");
-        return NULL;
-    }
-
     return client;
 }
 
-// Callback messages can be dispatched to internal handlers or pass to our
-// client's callback functions, depending on the message type.
-//
-// notifyCallback:
-//      CAMERA_MSG_SHUTTER              handleShutter
-//      (others)                        c->notifyCallback
-// dataCallback:
-//      CAMERA_MSG_PREVIEW_FRAME        handlePreviewData
-//      CAMERA_MSG_POSTVIEW_FRAME       handlePostview
-//      CAMERA_MSG_RAW_IMAGE            handleRawPicture
-//      CAMERA_MSG_COMPRESSED_IMAGE     handleCompressedPicture
-//      (others)                        c->dataCallback
-// dataCallbackTimestamp
-//      (others)                        c->dataCallbackTimestamp
-//
-// NOTE: the *Callback functions grab mLock of the client before passing
-// control to handle* functions. So the handle* functions must release the
-// lock before calling the ICameraClient's callbacks, so those callbacks can
-// invoke methods in the Client class again (For example, the preview frame
-// callback may want to releaseRecordingFrame). The handle* functions must
-// release the lock after all accesses to member variables, so it must be
-// handled very carefully.
-
-void CameraService::Client::notifyCallback(int32_t msgType, int32_t ext1,
-        int32_t ext2, void* user) {
-    LOG2("notifyCallback(%d)", msgType);
-
-    Mutex* lock = getClientLockFromCookie(user);
-    if (lock == NULL) return;
-    Mutex::Autolock alock(*lock);
-
-    Client* client = getClientFromCookie(user);
-    if (client == NULL) return;
-
-    if (!client->lockIfMessageWanted(msgType)) return;
-
-    switch (msgType) {
-        case CAMERA_MSG_SHUTTER:
-            // ext1 is the dimension of the yuv picture.
-            client->handleShutter();
-            break;
-        default:
-            client->handleGenericNotify(msgType, ext1, ext2);
-            break;
-    }
-}
-
-void CameraService::Client::dataCallback(int32_t msgType,
-        const sp<IMemory>& dataPtr, camera_frame_metadata_t *metadata, void* user) {
-    LOG2("dataCallback(%d)", msgType);
-
-    Mutex* lock = getClientLockFromCookie(user);
-    if (lock == NULL) return;
-    Mutex::Autolock alock(*lock);
-
-    Client* client = getClientFromCookie(user);
-    if (client == NULL) return;
-
-    if (!client->lockIfMessageWanted(msgType)) return;
-    if (dataPtr == 0 && metadata == NULL) {
-        ALOGE("Null data returned in data callback");
-        client->handleGenericNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);
-        return;
-    }
-
-    switch (msgType & ~CAMERA_MSG_PREVIEW_METADATA) {
-        case CAMERA_MSG_PREVIEW_FRAME:
-            client->handlePreviewData(msgType, dataPtr, metadata);
-            break;
-        case CAMERA_MSG_POSTVIEW_FRAME:
-            client->handlePostview(dataPtr);
-            break;
-        case CAMERA_MSG_RAW_IMAGE:
-            client->handleRawPicture(dataPtr);
-            break;
-        case CAMERA_MSG_COMPRESSED_IMAGE:
-            client->handleCompressedPicture(dataPtr);
-            break;
-        default:
-            client->handleGenericData(msgType, dataPtr, metadata);
-            break;
-    }
-}
-
-void CameraService::Client::dataCallbackTimestamp(nsecs_t timestamp,
-        int32_t msgType, const sp<IMemory>& dataPtr, void* user) {
-    LOG2("dataCallbackTimestamp(%d)", msgType);
-
-    Mutex* lock = getClientLockFromCookie(user);
-    if (lock == NULL) return;
-    Mutex::Autolock alock(*lock);
-
-    Client* client = getClientFromCookie(user);
-    if (client == NULL) return;
-
-    if (!client->lockIfMessageWanted(msgType)) return;
-
-    if (dataPtr == 0) {
-        ALOGE("Null data returned in data with timestamp callback");
-        client->handleGenericNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);
-        return;
-    }
-
-    client->handleGenericDataTimestamp(timestamp, msgType, dataPtr);
-}
-
-// snapshot taken callback
-void CameraService::Client::handleShutter(void) {
-    if (mPlayShutterSound) {
-        mCameraService->playSound(SOUND_SHUTTER);
-    }
-
-    sp<ICameraClient> c = mCameraClient;
-    if (c != 0) {
-        mLock.unlock();
-        c->notifyCallback(CAMERA_MSG_SHUTTER, 0, 0);
-        if (!lockIfMessageWanted(CAMERA_MSG_SHUTTER)) return;
-    }
-    disableMsgType(CAMERA_MSG_SHUTTER);
-
-    mLock.unlock();
-}
-
-// preview callback - frame buffer update
-void CameraService::Client::handlePreviewData(int32_t msgType,
-                                              const sp<IMemory>& mem,
-                                              camera_frame_metadata_t *metadata) {
-    ssize_t offset;
-    size_t size;
-    sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
-
-    // local copy of the callback flags
-    int flags = mPreviewCallbackFlag;
-
-    // is callback enabled?
-    if (!(flags & CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK)) {
-        // If the enable bit is off, the copy-out and one-shot bits are ignored
-        LOG2("frame callback is disabled");
-        mLock.unlock();
-        return;
-    }
-
-    // hold a strong pointer to the client
-    sp<ICameraClient> c = mCameraClient;
-
-    // clear callback flags if no client or one-shot mode
-    if (c == 0 || (mPreviewCallbackFlag & CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK)) {
-        LOG2("Disable preview callback");
-        mPreviewCallbackFlag &= ~(CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK |
-                                  CAMERA_FRAME_CALLBACK_FLAG_COPY_OUT_MASK |
-                                  CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK);
-        disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
-    }
-
-    if (c != 0) {
-        // Is the received frame copied out or not?
-        if (flags & CAMERA_FRAME_CALLBACK_FLAG_COPY_OUT_MASK) {
-            LOG2("frame is copied");
-            copyFrameAndPostCopiedFrame(msgType, c, heap, offset, size, metadata);
-        } else {
-            LOG2("frame is forwarded");
-            mLock.unlock();
-            c->dataCallback(msgType, mem, metadata);
-        }
-    } else {
-        mLock.unlock();
-    }
-}
-
-// picture callback - postview image ready
-void CameraService::Client::handlePostview(const sp<IMemory>& mem) {
-    disableMsgType(CAMERA_MSG_POSTVIEW_FRAME);
-
-    sp<ICameraClient> c = mCameraClient;
-    mLock.unlock();
-    if (c != 0) {
-        c->dataCallback(CAMERA_MSG_POSTVIEW_FRAME, mem, NULL);
-    }
-}
-
-// picture callback - raw image ready
-void CameraService::Client::handleRawPicture(const sp<IMemory>& mem) {
-    disableMsgType(CAMERA_MSG_RAW_IMAGE);
-
-    ssize_t offset;
-    size_t size;
-    sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
-
-    sp<ICameraClient> c = mCameraClient;
-    mLock.unlock();
-    if (c != 0) {
-        c->dataCallback(CAMERA_MSG_RAW_IMAGE, mem, NULL);
-    }
-}
-
-// picture callback - compressed picture ready
-void CameraService::Client::handleCompressedPicture(const sp<IMemory>& mem) {
-    disableMsgType(CAMERA_MSG_COMPRESSED_IMAGE);
-
-    sp<ICameraClient> c = mCameraClient;
-    mLock.unlock();
-    if (c != 0) {
-        c->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE, mem, NULL);
-    }
-}
-
-
-void CameraService::Client::handleGenericNotify(int32_t msgType,
-    int32_t ext1, int32_t ext2) {
-    sp<ICameraClient> c = mCameraClient;
-    mLock.unlock();
-    if (c != 0) {
-        c->notifyCallback(msgType, ext1, ext2);
-    }
-}
-
-void CameraService::Client::handleGenericData(int32_t msgType,
-    const sp<IMemory>& dataPtr, camera_frame_metadata_t *metadata) {
-    sp<ICameraClient> c = mCameraClient;
-    mLock.unlock();
-    if (c != 0) {
-        c->dataCallback(msgType, dataPtr, metadata);
-    }
-}
-
-void CameraService::Client::handleGenericDataTimestamp(nsecs_t timestamp,
-    int32_t msgType, const sp<IMemory>& dataPtr) {
-    sp<ICameraClient> c = mCameraClient;
-    mLock.unlock();
-    if (c != 0) {
-        c->dataCallbackTimestamp(timestamp, msgType, dataPtr);
-    }
-}
-
-void CameraService::Client::copyFrameAndPostCopiedFrame(
-        int32_t msgType, const sp<ICameraClient>& client,
-        const sp<IMemoryHeap>& heap, size_t offset, size_t size,
-        camera_frame_metadata_t *metadata) {
-    LOG2("copyFrameAndPostCopiedFrame");
-    // It is necessary to copy out of pmem before sending this to
-    // the callback. For efficiency, reuse the same MemoryHeapBase
-    // provided it's big enough. Don't allocate the memory or
-    // perform the copy if there's no callback.
-    // hold the preview lock while we grab a reference to the preview buffer
-    sp<MemoryHeapBase> previewBuffer;
-
-    if (mPreviewBuffer == 0) {
-        mPreviewBuffer = new MemoryHeapBase(size, 0, NULL);
-    } else if (size > mPreviewBuffer->virtualSize()) {
-        mPreviewBuffer.clear();
-        mPreviewBuffer = new MemoryHeapBase(size, 0, NULL);
-    }
-    if (mPreviewBuffer == 0) {
-        ALOGE("failed to allocate space for preview buffer");
-        mLock.unlock();
-        return;
-    }
-    previewBuffer = mPreviewBuffer;
-
-    memcpy(previewBuffer->base(), (uint8_t *)heap->base() + offset, size);
-
-    sp<MemoryBase> frame = new MemoryBase(previewBuffer, 0, size);
-    if (frame == 0) {
-        ALOGE("failed to allocate space for frame callback");
-        mLock.unlock();
-        return;
-    }
-
-    mLock.unlock();
-    client->dataCallback(msgType, frame, metadata);
-}
-
-int CameraService::Client::getOrientation(int degrees, bool mirror) {
-    if (!mirror) {
-        if (degrees == 0) return 0;
-        else if (degrees == 90) return HAL_TRANSFORM_ROT_90;
-        else if (degrees == 180) return HAL_TRANSFORM_ROT_180;
-        else if (degrees == 270) return HAL_TRANSFORM_ROT_270;
-    } else {  // Do mirror (horizontal flip)
-        if (degrees == 0) {           // FLIP_H and ROT_0
-            return HAL_TRANSFORM_FLIP_H;
-        } else if (degrees == 90) {   // FLIP_H and ROT_90
-            return HAL_TRANSFORM_FLIP_H | HAL_TRANSFORM_ROT_90;
-        } else if (degrees == 180) {  // FLIP_H and ROT_180
-            return HAL_TRANSFORM_FLIP_V;
-        } else if (degrees == 270) {  // FLIP_H and ROT_270
-            return HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_ROT_90;
-        }
-    }
-    ALOGE("Invalid setDisplayOrientation degrees=%d", degrees);
-    return -1;
+void CameraService::Client::disconnect() {
+    mCameraService->removeClient(mCameraClient);
+    mCameraService->setCameraFree(mCameraId);
 }
 
 // ----------------------------------------------------------------------------
@@ -1293,41 +417,81 @@
 }
 
 status_t CameraService::dump(int fd, const Vector<String16>& args) {
-    static const char* kDeadlockedString = "CameraService may be deadlocked\n";
-
-    const size_t SIZE = 256;
-    char buffer[SIZE];
     String8 result;
     if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
-        snprintf(buffer, SIZE, "Permission Denial: "
+        result.appendFormat("Permission Denial: "
                 "can't dump CameraService from pid=%d, uid=%d\n",
                 getCallingPid(),
                 getCallingUid());
-        result.append(buffer);
         write(fd, result.string(), result.size());
     } else {
         bool locked = tryLock(mServiceLock);
         // failed to lock - CameraService is probably deadlocked
         if (!locked) {
-            String8 result(kDeadlockedString);
+            result.append("CameraService may be deadlocked\n");
             write(fd, result.string(), result.size());
         }
 
         bool hasClient = false;
-        for (int i = 0; i < mNumberOfCameras; i++) {
-            sp<Client> client = mClient[i].promote();
-            if (client == 0) continue;
-            hasClient = true;
-            sprintf(buffer, "Client[%d] (%p) PID: %d\n",
-                    i,
-                    client->getCameraClient()->asBinder().get(),
-                    client->mClientPid);
-            result.append(buffer);
+        if (!mModule) {
+            result = String8::format("No camera module available!\n");
             write(fd, result.string(), result.size());
-            client->mHardware->dump(fd, args);
+            return NO_ERROR;
+        }
+
+        result = String8::format("Camera module HAL API version: 0x%x\n",
+                mModule->common.hal_api_version);
+        result.appendFormat("Camera module API version: 0x%x\n",
+                mModule->common.module_api_version);
+        result.appendFormat("Camera module name: %s\n",
+                mModule->common.name);
+        result.appendFormat("Camera module author: %s\n",
+                mModule->common.author);
+        result.appendFormat("Number of camera devices: %d\n\n", mNumberOfCameras);
+        write(fd, result.string(), result.size());
+        for (int i = 0; i < mNumberOfCameras; i++) {
+            result = String8::format("Camera %d static information:\n", i);
+            camera_info info;
+
+            status_t rc = mModule->get_camera_info(i, &info);
+            if (rc != OK) {
+                result.appendFormat("  Error reading static information!\n");
+                write(fd, result.string(), result.size());
+            } else {
+                result.appendFormat("  Facing: %s\n",
+                        info.facing == CAMERA_FACING_BACK ? "BACK" : "FRONT");
+                result.appendFormat("  Orientation: %d\n", info.orientation);
+                int deviceVersion;
+                if (mModule->common.module_api_version <
+                        CAMERA_MODULE_API_VERSION_2_0) {
+                    deviceVersion = CAMERA_DEVICE_API_VERSION_1_0;
+                } else {
+                    deviceVersion = info.device_version;
+                }
+                result.appendFormat("  Device version: 0x%x\n", deviceVersion);
+                if (deviceVersion >= CAMERA_DEVICE_API_VERSION_2_0) {
+                    result.appendFormat("  Device static metadata:\n");
+                    write(fd, result.string(), result.size());
+                    dump_indented_camera_metadata(info.static_camera_characteristics,
+                            fd, 2, 4);
+                } else {
+                    write(fd, result.string(), result.size());
+                }
+            }
+
+            sp<Client> client = mClient[i].promote();
+            if (client == 0) {
+                result = String8::format("  Device is closed, no client instance\n");
+                write(fd, result.string(), result.size());
+                continue;
+            }
+            hasClient = true;
+            result = String8::format("  Device is open. Client instance dump:\n");
+            write(fd, result.string(), result.size());
+            client->dump(fd, args);
         }
         if (!hasClient) {
-            result.append("No camera client yet.\n");
+            result = String8::format("\nNo active camera clients yet.\n");
             write(fd, result.string(), result.size());
         }
 
@@ -1336,14 +500,16 @@
         // change logging level
         int n = args.size();
         for (int i = 0; i + 1 < n; i++) {
-            if (args[i] == String16("-v")) {
+            String16 verboseOption("-v");
+            if (args[i] == verboseOption) {
                 String8 levelStr(args[i+1]);
                 int level = atoi(levelStr.string());
-                sprintf(buffer, "Set Log Level to %d", level);
-                result.append(buffer);
+                result = String8::format("\nSetting log level to %d.\n", level);
                 setLogLevel(level);
+                write(fd, result.string(), result.size());
             }
         }
+
     }
     return NO_ERROR;
 }
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 95ac197..630fca7 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -27,17 +27,18 @@
 
 namespace android {
 
+extern volatile int32_t gLogLevel;
+
 class MemoryHeapBase;
 class MediaPlayer;
-class CameraHardwareInterface;
 
 class CameraService :
     public BinderService<CameraService>,
     public BnCameraService
 {
-    class Client;
     friend class BinderService<CameraService>;
 public:
+    class Client;
     static char const* getServiceName() { return "media.camera"; }
 
                         CameraService();
@@ -68,6 +69,68 @@
     void                playSound(sound_kind kind);
     void                releaseSound();
 
+    class Client : public BnCamera
+    {
+    public:
+        // ICamera interface (see ICamera for details)
+        virtual void          disconnect();
+        virtual status_t      connect(const sp<ICameraClient>& client) = 0;
+        virtual status_t      lock() = 0;
+        virtual status_t      unlock() = 0;
+        virtual status_t      setPreviewDisplay(const sp<Surface>& surface) = 0;
+        virtual status_t      setPreviewTexture(const sp<ISurfaceTexture>& surfaceTexture) = 0;
+        virtual void          setPreviewCallbackFlag(int flag) = 0;
+        virtual status_t      startPreview() = 0;
+        virtual void          stopPreview() = 0;
+        virtual bool          previewEnabled() = 0;
+        virtual status_t      storeMetaDataInBuffers(bool enabled) = 0;
+        virtual status_t      startRecording() = 0;
+        virtual void          stopRecording() = 0;
+        virtual bool          recordingEnabled() = 0;
+        virtual void          releaseRecordingFrame(const sp<IMemory>& mem) = 0;
+        virtual status_t      autoFocus() = 0;
+        virtual status_t      cancelAutoFocus() = 0;
+        virtual status_t      takePicture(int msgType) = 0;
+        virtual status_t      setParameters(const String8& params) = 0;
+        virtual String8       getParameters() const = 0;
+        virtual status_t      sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) = 0;
+
+        // Interface used by CameraService
+        Client(const sp<CameraService>& cameraService,
+                const sp<ICameraClient>& cameraClient,
+                int cameraId,
+                int cameraFacing,
+                int clientPid);
+        ~Client();
+
+        // return our camera client
+        const sp<ICameraClient>&    getCameraClient() {
+            return mCameraClient;
+        }
+
+        virtual status_t initialize(camera_module_t *module) = 0;
+
+        virtual status_t dump(int fd, const Vector<String16>& args) = 0;
+
+    protected:
+        static Mutex*        getClientLockFromCookie(void* user);
+        // convert client from cookie. Client lock should be acquired before getting Client.
+        static Client*       getClientFromCookie(void* user);
+
+        // the instance is in the middle of destruction. When this is set,
+        // the instance should not be accessed from callback.
+        // CameraService's mClientLock should be acquired to access this.
+        bool                            mDestructionStarted;
+
+        // these are initialized in the constructor.
+        sp<CameraService>               mCameraService;  // immutable after constructor
+        sp<ICameraClient>               mCameraClient;
+        int                             mCameraId;       // immutable after constructor
+        int                             mCameraFacing;   // immutable after constructor
+        pid_t                           mClientPid;
+
+    };
+
 private:
     Mutex               mServiceLock;
     wp<Client>          mClient[MAX_CAMERAS];  // protected by mServiceLock
@@ -86,147 +149,6 @@
     sp<MediaPlayer>     mSoundPlayer[NUM_SOUNDS];
     int                 mSoundRef;  // reference count (release all MediaPlayer when 0)
 
-    class Client : public BnCamera
-    {
-    public:
-        // ICamera interface (see ICamera for details)
-        virtual void            disconnect();
-        virtual status_t        connect(const sp<ICameraClient>& client);
-        virtual status_t        lock();
-        virtual status_t        unlock();
-        virtual status_t        setPreviewDisplay(const sp<Surface>& surface);
-        virtual status_t        setPreviewTexture(const sp<ISurfaceTexture>& surfaceTexture);
-        virtual void            setPreviewCallbackFlag(int flag);
-        virtual status_t        startPreview();
-        virtual void            stopPreview();
-        virtual bool            previewEnabled();
-        virtual status_t        storeMetaDataInBuffers(bool enabled);
-        virtual status_t        startRecording();
-        virtual void            stopRecording();
-        virtual bool            recordingEnabled();
-        virtual void            releaseRecordingFrame(const sp<IMemory>& mem);
-        virtual status_t        autoFocus();
-        virtual status_t        cancelAutoFocus();
-        virtual status_t        takePicture(int msgType);
-        virtual status_t        setParameters(const String8& params);
-        virtual String8         getParameters() const;
-        virtual status_t        sendCommand(int32_t cmd, int32_t arg1, int32_t arg2);
-    private:
-        friend class CameraService;
-                                Client(const sp<CameraService>& cameraService,
-                                       const sp<ICameraClient>& cameraClient,
-                                       const sp<CameraHardwareInterface>& hardware,
-                                       int cameraId,
-                                       int cameraFacing,
-                                       int clientPid);
-                                ~Client();
-
-        // return our camera client
-        const sp<ICameraClient>&    getCameraClient() { return mCameraClient; }
-
-        // check whether the calling process matches mClientPid.
-        status_t                checkPid() const;
-        status_t                checkPidAndHardware() const;  // also check mHardware != 0
-
-        // these are internal functions used to set up preview buffers
-        status_t                registerPreviewBuffers();
-
-        // camera operation mode
-        enum camera_mode {
-            CAMERA_PREVIEW_MODE   = 0,  // frame automatically released
-            CAMERA_RECORDING_MODE = 1,  // frame has to be explicitly released by releaseRecordingFrame()
-        };
-        // these are internal functions used for preview/recording
-        status_t                startCameraMode(camera_mode mode);
-        status_t                startPreviewMode();
-        status_t                startRecordingMode();
-
-        // internal function used by sendCommand to enable/disable shutter sound.
-        status_t                enableShutterSound(bool enable);
-
-        // these are static callback functions
-        static void             notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2, void* user);
-        static void             dataCallback(int32_t msgType, const sp<IMemory>& dataPtr,
-                                             camera_frame_metadata_t *metadata, void* user);
-        static void             dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr, void* user);
-        static Mutex*        getClientLockFromCookie(void* user);
-        // convert client from cookie. Client lock should be acquired before getting Client.
-        static Client*       getClientFromCookie(void* user);
-        // handlers for messages
-        void                    handleShutter(void);
-        void                    handlePreviewData(int32_t msgType, const sp<IMemory>& mem,
-                                                  camera_frame_metadata_t *metadata);
-        void                    handlePostview(const sp<IMemory>& mem);
-        void                    handleRawPicture(const sp<IMemory>& mem);
-        void                    handleCompressedPicture(const sp<IMemory>& mem);
-        void                    handleGenericNotify(int32_t msgType, int32_t ext1, int32_t ext2);
-        void                    handleGenericData(int32_t msgType, const sp<IMemory>& dataPtr,
-                                                  camera_frame_metadata_t *metadata);
-        void                    handleGenericDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr);
-
-        void                    copyFrameAndPostCopiedFrame(
-                                    int32_t msgType,
-                                    const sp<ICameraClient>& client,
-                                    const sp<IMemoryHeap>& heap,
-                                    size_t offset, size_t size,
-                                    camera_frame_metadata_t *metadata);
-
-        int                     getOrientation(int orientation, bool mirror);
-
-        status_t                setPreviewWindow(
-                                    const sp<IBinder>& binder,
-                                    const sp<ANativeWindow>& window);
-
-        // these are initialized in the constructor.
-        sp<CameraService>               mCameraService;  // immutable after constructor
-        sp<ICameraClient>               mCameraClient;
-        int                             mCameraId;       // immutable after constructor
-        int                             mCameraFacing;   // immutable after constructor
-        pid_t                           mClientPid;
-        sp<CameraHardwareInterface>     mHardware;       // cleared after disconnect()
-        int                             mPreviewCallbackFlag;
-        int                             mOrientation;     // Current display orientation
-        bool                            mPlayShutterSound;
-
-        // Ensures atomicity among the public methods
-        mutable Mutex                   mLock;
-        // A lock to synchronize access through the ICamera binder
-        // interface. The entire binder call should be done with mICameraLock
-        // locked, to serialize ICamera access, even when mLock is disabled for
-        // calls to the HAL.
-        mutable Mutex                   mICameraLock;
-        // This is a binder of Surface or SurfaceTexture.
-        sp<IBinder>                     mSurface;
-        sp<ANativeWindow>               mPreviewWindow;
-
-        // If the user want us to return a copy of the preview frame (instead
-        // of the original one), we allocate mPreviewBuffer and reuse it if possible.
-        sp<MemoryHeapBase>              mPreviewBuffer;
-
-        // the instance is in the middle of destruction. When this is set,
-        // the instance should not be accessed from callback.
-        // CameraService's mClientLock should be acquired to access this.
-        bool                            mDestructionStarted;
-
-        // We need to avoid the deadlock when the incoming command thread and
-        // the CameraHardwareInterface callback thread both want to grab mLock.
-        // An extra flag is used to tell the callback thread that it should stop
-        // trying to deliver the callback messages if the client is not
-        // interested in it anymore. For example, if the client is calling
-        // stopPreview(), the preview frame messages do not need to be delivered
-        // anymore.
-
-        // This function takes the same parameter as the enableMsgType() and
-        // disableMsgType() functions in CameraHardwareInterface.
-        void                    enableMsgType(int32_t msgType);
-        void                    disableMsgType(int32_t msgType);
-        volatile int32_t        mMsgEnabled;
-
-        // This function keeps trying to grab mLock, or give up if the message
-        // is found to be disabled. It returns true if mLock is grabbed.
-        bool                    lockIfMessageWanted(int32_t msgType);
-    };
-
     camera_module_t *mModule;
 };
 
diff --git a/services/camera/libcameraservice/CannedJpeg.h b/services/camera/libcameraservice/CannedJpeg.h
deleted file mode 100644
index 6dd99c1..0000000
--- a/services/camera/libcameraservice/CannedJpeg.h
+++ /dev/null
@@ -1,750 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-const int kCannedJpegWidth = 320;
-const int kCannedJpegHeight = 240;
-const int kCannedJpegSize = 8733;
-
-const char kCannedJpeg[] = {
-  0xff,  0xd8,  0xff,  0xe0,  0x00,  0x10,  0x4a,  0x46,  0x49,  0x46,  0x00,  0x01,
-  0x01,  0x01,  0x00,  0x60,  0x00,  0x60,  0x00,  0x00,  0xff,  0xe1,  0x00,  0x66,
-  0x45,  0x78,  0x69,  0x66,  0x00,  0x00,  0x49,  0x49,  0x2a,  0x00,  0x08,  0x00,
-  0x00,  0x00,  0x04,  0x00,  0x1a,  0x01,  0x05,  0x00,  0x01,  0x00,  0x00,  0x00,
-  0x3e,  0x00,  0x00,  0x00,  0x1b,  0x01,  0x05,  0x00,  0x01,  0x00,  0x00,  0x00,
-  0x46,  0x00,  0x00,  0x00,  0x28,  0x01,  0x03,  0x00,  0x01,  0x00,  0x00,  0x00,
-  0x02,  0x00,  0x00,  0x00,  0x31,  0x01,  0x02,  0x00,  0x10,  0x00,  0x00,  0x00,
-  0x4e,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x60,  0x00,  0x00,  0x00,
-  0x01,  0x00,  0x00,  0x00,  0x60,  0x00,  0x00,  0x00,  0x01,  0x00,  0x00,  0x00,
-  0x50,  0x61,  0x69,  0x6e,  0x74,  0x2e,  0x4e,  0x45,  0x54,  0x20,  0x76,  0x33,
-  0x2e,  0x33,  0x36,  0x00,  0xff,  0xdb,  0x00,  0x43,  0x00,  0x03,  0x02,  0x02,
-  0x03,  0x02,  0x02,  0x03,  0x03,  0x03,  0x03,  0x04,  0x03,  0x03,  0x04,  0x05,
-  0x08,  0x05,  0x05,  0x04,  0x04,  0x05,  0x0a,  0x07,  0x07,  0x06,  0x08,  0x0c,
-  0x0a,  0x0c,  0x0c,  0x0b,  0x0a,  0x0b,  0x0b,  0x0d,  0x0e,  0x12,  0x10,  0x0d,
-  0x0e,  0x11,  0x0e,  0x0b,  0x0b,  0x10,  0x16,  0x10,  0x11,  0x13,  0x14,  0x15,
-  0x15,  0x15,  0x0c,  0x0f,  0x17,  0x18,  0x16,  0x14,  0x18,  0x12,  0x14,  0x15,
-  0x14,  0xff,  0xdb,  0x00,  0x43,  0x01,  0x03,  0x04,  0x04,  0x05,  0x04,  0x05,
-  0x09,  0x05,  0x05,  0x09,  0x14,  0x0d,  0x0b,  0x0d,  0x14,  0x14,  0x14,  0x14,
-  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,
-  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,
-  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,
-  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0x14,  0xff,  0xc0,
-  0x00,  0x11,  0x08,  0x00,  0xf0,  0x01,  0x40,  0x03,  0x01,  0x22,  0x00,  0x02,
-  0x11,  0x01,  0x03,  0x11,  0x01,  0xff,  0xc4,  0x00,  0x1f,  0x00,  0x00,  0x01,
-  0x05,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x01,  0x02,  0x03,  0x04,  0x05,  0x06,  0x07,  0x08,  0x09,
-  0x0a,  0x0b,  0xff,  0xc4,  0x00,  0xb5,  0x10,  0x00,  0x02,  0x01,  0x03,  0x03,
-  0x02,  0x04,  0x03,  0x05,  0x05,  0x04,  0x04,  0x00,  0x00,  0x01,  0x7d,  0x01,
-  0x02,  0x03,  0x00,  0x04,  0x11,  0x05,  0x12,  0x21,  0x31,  0x41,  0x06,  0x13,
-  0x51,  0x61,  0x07,  0x22,  0x71,  0x14,  0x32,  0x81,  0x91,  0xa1,  0x08,  0x23,
-  0x42,  0xb1,  0xc1,  0x15,  0x52,  0xd1,  0xf0,  0x24,  0x33,  0x62,  0x72,  0x82,
-  0x09,  0x0a,  0x16,  0x17,  0x18,  0x19,  0x1a,  0x25,  0x26,  0x27,  0x28,  0x29,
-  0x2a,  0x34,  0x35,  0x36,  0x37,  0x38,  0x39,  0x3a,  0x43,  0x44,  0x45,  0x46,
-  0x47,  0x48,  0x49,  0x4a,  0x53,  0x54,  0x55,  0x56,  0x57,  0x58,  0x59,  0x5a,
-  0x63,  0x64,  0x65,  0x66,  0x67,  0x68,  0x69,  0x6a,  0x73,  0x74,  0x75,  0x76,
-  0x77,  0x78,  0x79,  0x7a,  0x83,  0x84,  0x85,  0x86,  0x87,  0x88,  0x89,  0x8a,
-  0x92,  0x93,  0x94,  0x95,  0x96,  0x97,  0x98,  0x99,  0x9a,  0xa2,  0xa3,  0xa4,
-  0xa5,  0xa6,  0xa7,  0xa8,  0xa9,  0xaa,  0xb2,  0xb3,  0xb4,  0xb5,  0xb6,  0xb7,
-  0xb8,  0xb9,  0xba,  0xc2,  0xc3,  0xc4,  0xc5,  0xc6,  0xc7,  0xc8,  0xc9,  0xca,
-  0xd2,  0xd3,  0xd4,  0xd5,  0xd6,  0xd7,  0xd8,  0xd9,  0xda,  0xe1,  0xe2,  0xe3,
-  0xe4,  0xe5,  0xe6,  0xe7,  0xe8,  0xe9,  0xea,  0xf1,  0xf2,  0xf3,  0xf4,  0xf5,
-  0xf6,  0xf7,  0xf8,  0xf9,  0xfa,  0xff,  0xc4,  0x00,  0x1f,  0x01,  0x00,  0x03,
-  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x01,  0x02,  0x03,  0x04,  0x05,  0x06,  0x07,  0x08,  0x09,
-  0x0a,  0x0b,  0xff,  0xc4,  0x00,  0xb5,  0x11,  0x00,  0x02,  0x01,  0x02,  0x04,
-  0x04,  0x03,  0x04,  0x07,  0x05,  0x04,  0x04,  0x00,  0x01,  0x02,  0x77,  0x00,
-  0x01,  0x02,  0x03,  0x11,  0x04,  0x05,  0x21,  0x31,  0x06,  0x12,  0x41,  0x51,
-  0x07,  0x61,  0x71,  0x13,  0x22,  0x32,  0x81,  0x08,  0x14,  0x42,  0x91,  0xa1,
-  0xb1,  0xc1,  0x09,  0x23,  0x33,  0x52,  0xf0,  0x15,  0x62,  0x72,  0xd1,  0x0a,
-  0x16,  0x24,  0x34,  0xe1,  0x25,  0xf1,  0x17,  0x18,  0x19,  0x1a,  0x26,  0x27,
-  0x28,  0x29,  0x2a,  0x35,  0x36,  0x37,  0x38,  0x39,  0x3a,  0x43,  0x44,  0x45,
-  0x46,  0x47,  0x48,  0x49,  0x4a,  0x53,  0x54,  0x55,  0x56,  0x57,  0x58,  0x59,
-  0x5a,  0x63,  0x64,  0x65,  0x66,  0x67,  0x68,  0x69,  0x6a,  0x73,  0x74,  0x75,
-  0x76,  0x77,  0x78,  0x79,  0x7a,  0x82,  0x83,  0x84,  0x85,  0x86,  0x87,  0x88,
-  0x89,  0x8a,  0x92,  0x93,  0x94,  0x95,  0x96,  0x97,  0x98,  0x99,  0x9a,  0xa2,
-  0xa3,  0xa4,  0xa5,  0xa6,  0xa7,  0xa8,  0xa9,  0xaa,  0xb2,  0xb3,  0xb4,  0xb5,
-  0xb6,  0xb7,  0xb8,  0xb9,  0xba,  0xc2,  0xc3,  0xc4,  0xc5,  0xc6,  0xc7,  0xc8,
-  0xc9,  0xca,  0xd2,  0xd3,  0xd4,  0xd5,  0xd6,  0xd7,  0xd8,  0xd9,  0xda,  0xe2,
-  0xe3,  0xe4,  0xe5,  0xe6,  0xe7,  0xe8,  0xe9,  0xea,  0xf2,  0xf3,  0xf4,  0xf5,
-  0xf6,  0xf7,  0xf8,  0xf9,  0xfa,  0xff,  0xda,  0x00,  0x0c,  0x03,  0x01,  0x00,
-  0x02,  0x11,  0x03,  0x11,  0x00,  0x3f,  0x00,  0xf9,  0xd2,  0xa3,  0x95,  0xbb,
-  0x54,  0x84,  0xe0,  0x66,  0xa0,  0x27,  0x27,  0x35,  0xed,  0x9e,  0x50,  0x95,
-  0x2c,  0x4b,  0xc6,  0x6a,  0x35,  0x1b,  0x8e,  0x2a,  0x70,  0x30,  0x28,  0x00,
-  0xa8,  0xe5,  0x6e,  0x71,  0x52,  0x31,  0xda,  0x33,  0x50,  0x13,  0x93,  0x40,
-  0x09,  0x52,  0xc6,  0xb8,  0x19,  0xf5,  0xa6,  0x2a,  0xee,  0x6c,  0x54,  0xd4,
-  0x00,  0x54,  0x52,  0x36,  0x5b,  0x1e,  0x95,  0x23,  0xb6,  0xd5,  0xcd,  0x41,
-  0x40,  0x05,  0x4c,  0x8b,  0xb5,  0x7d,  0xea,  0x34,  0x5d,  0xcd,  0xed,  0x53,
-  0x50,  0x01,  0x50,  0xbb,  0x6e,  0x6f,  0x6a,  0x91,  0xdb,  0x6a,  0xfb,  0xd4,
-  0x34,  0x00,  0x54,  0xe8,  0xbb,  0x57,  0x15,  0x1c,  0x6b,  0x96,  0xcf,  0xa5,
-  0x4b,  0x40,  0x05,  0x42,  0xcd,  0xb9,  0xb3,  0x4f,  0x91,  0xb0,  0x31,  0xeb,
-  0x51,  0x50,  0x02,  0x81,  0x93,  0x53,  0xa8,  0xda,  0x31,  0x51,  0xc4,  0xbc,
-  0xe6,  0xa4,  0xa0,  0x00,  0x9c,  0x0a,  0x81,  0x8e,  0xe3,  0x9a,  0x92,  0x56,
-  0xe3,  0x15,  0x15,  0x00,  0x28,  0x19,  0x38,  0xa9,  0xc0,  0xc0,  0xc5,  0x47,
-  0x12,  0xf7,  0xa9,  0x28,  0x00,  0x27,  0x00,  0x9a,  0x80,  0x9c,  0x9c,  0xd3,
-  0xe5,  0x6e,  0xd5,  0x1d,  0x00,  0x2a,  0x8d,  0xc7,  0x15,  0x3d,  0x32,  0x35,
-  0xc0,  0xcf,  0xad,  0x3e,  0x80,  0x11,  0x8e,  0xd1,  0x9a,  0x82,  0x9f,  0x23,
-  0x64,  0xe3,  0xd2,  0x99,  0x40,  0x0e,  0x45,  0xdc,  0xde,  0xd5,  0x35,  0x36,
-  0x35,  0xc2,  0xfb,  0x9a,  0x75,  0x00,  0x35,  0xdb,  0x6a,  0xfb,  0xd4,  0x34,
-  0xe9,  0x1b,  0x73,  0x7b,  0x0a,  0x6d,  0x00,  0x3e,  0x35,  0xcb,  0x7b,  0x0a,
-  0x96,  0x91,  0x17,  0x6a,  0xd2,  0xd0,  0x03,  0x64,  0x6c,  0x2f,  0xb9,  0xa8,
-  0x69,  0xce,  0xdb,  0x9a,  0x9b,  0xd6,  0x80,  0x1f,  0x12,  0xe4,  0xe7,  0xd2,
-  0xa5,  0xa4,  0x51,  0xb4,  0x62,  0x97,  0xa5,  0x00,  0x67,  0xc9,  0xad,  0xd8,
-  0x91,  0x81,  0x72,  0x9f,  0x9d,  0x47,  0xfd,  0xb3,  0x65,  0xff,  0x00,  0x3f,
-  0x29,  0x5f,  0xa0,  0x1f,  0xf0,  0xe9,  0x6f,  0x09,  0x7f,  0xd0,  0xfb,  0xad,
-  0x7f,  0xe0,  0x24,  0x34,  0x7f,  0xc3,  0xa5,  0xbc,  0x25,  0xff,  0x00,  0x43,
-  0xee,  0xb5,  0xff,  0x00,  0x80,  0x90,  0xd7,  0x3f,  0xb7,  0x87,  0x73,  0x6f,
-  0x63,  0x33,  0xe0,  0x28,  0xf5,  0x9b,  0x11,  0xc9,  0xb9,  0x4c,  0xfd,  0x69,
-  0xff,  0x00,  0xdb,  0x96,  0x1f,  0xf3,  0xf5,  0x1f,  0xe7,  0x5f,  0x7d,  0x7f,
-  0xc3,  0xa5,  0xbc,  0x25,  0xff,  0x00,  0x43,  0xee,  0xb5,  0xff,  0x00,  0x80,
-  0x90,  0xd1,  0xff,  0x00,  0x0e,  0x96,  0xf0,  0x97,  0xfd,  0x0f,  0xba,  0xd7,
-  0xfe,  0x02,  0x43,  0x47,  0xb7,  0x87,  0x70,  0xf6,  0x33,  0x3e,  0x02,  0x93,
-  0x5b,  0xb1,  0x3c,  0x0b,  0x94,  0xc7,  0xd6,  0x99,  0xfd,  0xb3,  0x65,  0xff,
-  0x00,  0x3f,  0x29,  0xf9,  0xd7,  0xe8,  0x07,  0xfc,  0x3a,  0x5b,  0xc2,  0x5f,
-  0xf4,  0x3e,  0xeb,  0x5f,  0xf8,  0x09,  0x0d,  0x1f,  0xf0,  0xe9,  0x6f,  0x09,
-  0x7f,  0xd0,  0xfb,  0xad,  0x7f,  0xe0,  0x24,  0x34,  0xbd,  0xbc,  0x03,  0xd8,
-  0xcc,  0xf8,  0x0e,  0x3d,  0x6a,  0xc1,  0x47,  0x37,  0x29,  0x9f,  0xad,  0x3b,
-  0xfb,  0x72,  0xc3,  0xfe,  0x7e,  0xa3,  0xfc,  0xeb,  0xef,  0xaf,  0xf8,  0x74,
-  0xb7,  0x84,  0xbf,  0xe8,  0x7d,  0xd6,  0xbf,  0xf0,  0x12,  0x1a,  0x3f,  0xe1,
-  0xd2,  0xde,  0x12,  0xff,  0x00,  0xa1,  0xf7,  0x5a,  0xff,  0x00,  0xc0,  0x48,
-  0x69,  0xfb,  0x78,  0x77,  0x0f,  0x63,  0x33,  0xe0,  0x19,  0x35,  0xbb,  0x26,
-  0x3c,  0x5c,  0xa6,  0x3e,  0xb4,  0xdf,  0xed,  0x9b,  0x2f,  0xf9,  0xf9,  0x4a,
-  0xfd,  0x00,  0xff,  0x00,  0x87,  0x4b,  0x78,  0x4b,  0xfe,  0x87,  0xdd,  0x6b,
-  0xff,  0x00,  0x01,  0x21,  0xa3,  0xfe,  0x1d,  0x2d,  0xe1,  0x2f,  0xfa,  0x1f,
-  0x75,  0xaf,  0xfc,  0x04,  0x86,  0x97,  0xb7,  0x80,  0x7b,  0x19,  0x9f,  0x01,
-  0xa6,  0xb5,  0x60,  0xab,  0xff,  0x00,  0x1f,  0x51,  0xe7,  0xeb,  0x4e,  0xfe,
-  0xdc,  0xb0,  0xff,  0x00,  0x9f,  0xa8,  0xff,  0x00,  0x3a,  0xfb,  0xeb,  0xfe,
-  0x1d,  0x2d,  0xe1,  0x2f,  0xfa,  0x1f,  0x75,  0xaf,  0xfc,  0x04,  0x86,  0x8f,
-  0xf8,  0x74,  0xb7,  0x84,  0xbf,  0xe8,  0x7d,  0xd6,  0xbf,  0xf0,  0x12,  0x1a,
-  0x3d,  0xbc,  0x03,  0xd8,  0xcc,  0xf8,  0x05,  0xf5,  0xab,  0x26,  0x6f,  0xf8,
-  0xf9,  0x4c,  0x7d,  0x69,  0xbf,  0xdb,  0x36,  0x5f,  0xf3,  0xf2,  0x9f,  0x9d,
-  0x7e,  0x80,  0x7f,  0xc3,  0xa5,  0xbc,  0x25,  0xff,  0x00,  0x43,  0xee,  0xb5,
-  0xff,  0x00,  0x80,  0x90,  0xd1,  0xff,  0x00,  0x0e,  0x96,  0xf0,  0x97,  0xfd,
-  0x0f,  0xba,  0xd7,  0xfe,  0x02,  0x43,  0x47,  0xb7,  0x80,  0x7b,  0x19,  0x9f,
-  0x02,  0x26,  0xb5,  0x60,  0xab,  0x8f,  0xb5,  0x47,  0xf9,  0xd2,  0xff,  0x00,
-  0x6e,  0x58,  0x7f,  0xcf,  0xd4,  0x7f,  0x9d,  0x7d,  0xf5,  0xff,  0x00,  0x0e,
-  0x96,  0xf0,  0x97,  0xfd,  0x0f,  0xba,  0xd7,  0xfe,  0x02,  0x43,  0x47,  0xfc,
-  0x3a,  0x5b,  0xc2,  0x5f,  0xf4,  0x3e,  0xeb,  0x5f,  0xf8,  0x09,  0x0d,  0x1e,
-  0xde,  0x01,  0xec,  0x66,  0x7c,  0x00,  0xda,  0xd5,  0x93,  0x1c,  0xfd,  0xa5,
-  0x3f,  0x3a,  0x4f,  0xed,  0x8b,  0x2f,  0xf9,  0xf9,  0x4f,  0xce,  0xbf,  0x40,
-  0x3f,  0xe1,  0xd2,  0xde,  0x12,  0xff,  0x00,  0xa1,  0xf7,  0x5a,  0xff,  0x00,
-  0xc0,  0x48,  0x68,  0xff,  0x00,  0x87,  0x4b,  0x78,  0x4b,  0xfe,  0x87,  0xdd,
-  0x6b,  0xff,  0x00,  0x01,  0x21,  0xa7,  0xed,  0xe1,  0xdc,  0x3d,  0x8c,  0xcf,
-  0x81,  0x57,  0x5a,  0xb0,  0x51,  0x8f,  0xb5,  0x47,  0xf9,  0xd1,  0xfd,  0xb9,
-  0x61,  0xff,  0x00,  0x3f,  0x49,  0xf9,  0xd7,  0xdf,  0x5f,  0xf0,  0xe9,  0x6f,
-  0x09,  0x7f,  0xd0,  0xfb,  0xad,  0x7f,  0xe0,  0x24,  0x34,  0x7f,  0xc3,  0xa5,
-  0xbc,  0x25,  0xff,  0x00,  0x43,  0xee,  0xb5,  0xff,  0x00,  0x80,  0x90,  0xd2,
-  0xf6,  0xf0,  0x0f,  0x63,  0x33,  0xe0,  0x06,  0xd6,  0xac,  0x98,  0xe7,  0xed,
-  0x29,  0xf9,  0xd2,  0x0d,  0x62,  0xcb,  0xfe,  0x7e,  0x53,  0xf3,  0xaf,  0xd0,
-  0x0f,  0xf8,  0x74,  0xb7,  0x84,  0xbf,  0xe8,  0x7d,  0xd6,  0xbf,  0xf0,  0x12,
-  0x1a,  0x3f,  0xe1,  0xd2,  0xde,  0x12,  0xff,  0x00,  0xa1,  0xf7,  0x5a,  0xff,
-  0x00,  0xc0,  0x48,  0x69,  0xfb,  0x78,  0x77,  0x0f,  0x63,  0x33,  0xe0,  0x51,
-  0xad,  0xd8,  0x01,  0x8f,  0xb5,  0x47,  0xf9,  0xd0,  0x75,  0xcb,  0x0c,  0x7f,
-  0xc7,  0xca,  0x7e,  0x75,  0xf7,  0xd7,  0xfc,  0x3a,  0x5b,  0xc2,  0x5f,  0xf4,
-  0x3e,  0xeb,  0x5f,  0xf8,  0x09,  0x0d,  0x1f,  0xf0,  0xe9,  0x6f,  0x09,  0x7f,
-  0xd0,  0xfb,  0xad,  0x7f,  0xe0,  0x24,  0x34,  0x7b,  0x78,  0x77,  0x0f,  0x63,
-  0x33,  0xf3,  0xfc,  0xeb,  0x36,  0x44,  0xff,  0x00,  0xc7,  0xca,  0x7e,  0x74,
-  0xa3,  0x58,  0xb1,  0x24,  0x66,  0xe5,  0x31,  0xf5,  0xaf,  0xbf,  0xff,  0x00,
-  0xe1,  0xd2,  0xde,  0x12,  0xff,  0x00,  0xa1,  0xf7,  0x5a,  0xff,  0x00,  0xc0,
-  0x48,  0x68,  0xff,  0x00,  0x87,  0x4b,  0x78,  0x4b,  0xfe,  0x87,  0xdd,  0x6b,
-  0xff,  0x00,  0x01,  0x21,  0xa3,  0xdb,  0xc3,  0xb8,  0x7b,  0x19,  0x9f,  0x02,
-  0xff,  0x00,  0x6d,  0xd8,  0x7f,  0xcf,  0xd4,  0x7f,  0x9d,  0x07,  0x5c,  0xb1,
-  0x03,  0x8b,  0x94,  0xcf,  0xd6,  0xbe,  0xfa,  0xff,  0x00,  0x87,  0x4b,  0x78,
-  0x4b,  0xfe,  0x87,  0xdd,  0x6b,  0xff,  0x00,  0x01,  0x21,  0xa3,  0xfe,  0x1d,
-  0x2d,  0xe1,  0x2f,  0xfa,  0x1f,  0x75,  0xaf,  0xfc,  0x04,  0x86,  0x8f,  0x6f,
-  0x0e,  0xe1,  0xec,  0x66,  0x7e,  0x7f,  0xff,  0x00,  0x6c,  0xd9,  0x7f,  0xcf,
-  0xca,  0x7e,  0x74,  0xab,  0xac,  0x58,  0xe7,  0x9b,  0x94,  0xc7,  0xd6,  0xbe,
-  0xff,  0x00,  0xff,  0x00,  0x87,  0x4b,  0x78,  0x4b,  0xfe,  0x87,  0xdd,  0x6b,
-  0xff,  0x00,  0x01,  0x21,  0xa3,  0xfe,  0x1d,  0x2d,  0xe1,  0x2f,  0xfa,  0x1f,
-  0x75,  0xaf,  0xfc,  0x04,  0x86,  0x8f,  0x6f,  0x0e,  0xe1,  0xec,  0x66,  0x7c,
-  0x0b,  0xfd,  0xb9,  0x61,  0xff,  0x00,  0x3f,  0x51,  0xfe,  0x74,  0x8d,  0xae,
-  0x58,  0xed,  0x38,  0xb9,  0x4c,  0xfd,  0x6b,  0xef,  0xbf,  0xf8,  0x74,  0xb7,
-  0x84,  0xbf,  0xe8,  0x7d,  0xd6,  0xbf,  0xf0,  0x12,  0x1a,  0x3f,  0xe1,  0xd2,
-  0xde,  0x12,  0xff,  0x00,  0xa1,  0xf7,  0x5a,  0xff,  0x00,  0xc0,  0x48,  0x68,
-  0xf6,  0xf0,  0xee,  0x1e,  0xc6,  0x67,  0xe7,  0xff,  0x00,  0xf6,  0xc5,  0x97,
-  0xfc,  0xfc,  0xa7,  0xe7,  0x4e,  0x4d,  0x62,  0xc7,  0x77,  0x37,  0x29,  0xf9,
-  0xd7,  0xdf,  0xdf,  0xf0,  0xe9,  0x6f,  0x09,  0x7f,  0xd0,  0xfb,  0xad,  0x7f,
-  0xe0,  0x24,  0x34,  0x7f,  0xc3,  0xa5,  0xbc,  0x25,  0xff,  0x00,  0x43,  0xee,
-  0xb5,  0xff,  0x00,  0x80,  0x90,  0xd1,  0xed,  0xe1,  0xdc,  0x3d,  0x8c,  0xcf,
-  0x81,  0x7f,  0xb7,  0x2c,  0x3f,  0xe7,  0xea,  0x3f,  0xce,  0x91,  0xf5,  0xcb,
-  0x1c,  0x71,  0x72,  0x9f,  0x9d,  0x7d,  0xf7,  0xff,  0x00,  0x0e,  0x96,  0xf0,
-  0x97,  0xfd,  0x0f,  0xba,  0xd7,  0xfe,  0x02,  0x43,  0x47,  0xfc,  0x3a,  0x5b,
-  0xc2,  0x5f,  0xf4,  0x3e,  0xeb,  0x5f,  0xf8,  0x09,  0x0d,  0x1e,  0xde,  0x1d,
-  0xc3,  0xd8,  0xcc,  0xfc,  0xff,  0x00,  0xfe,  0xd9,  0xb2,  0xff,  0x00,  0x9f,
-  0x94,  0xfc,  0xe9,  0xd1,  0xeb,  0x36,  0x20,  0xe4,  0xdc,  0xa7,  0xe7,  0x5f,
-  0x7f,  0x7f,  0xc3,  0xa5,  0xbc,  0x25,  0xff,  0x00,  0x43,  0xee,  0xb5,  0xff,
-  0x00,  0x80,  0x90,  0xd1,  0xff,  0x00,  0x0e,  0x96,  0xf0,  0x97,  0xfd,  0x0f,
-  0xba,  0xd7,  0xfe,  0x02,  0x43,  0x47,  0xb7,  0x87,  0x70,  0xf6,  0x33,  0x3e,
-  0x05,  0xfe,  0xdc,  0xb0,  0xff,  0x00,  0x9f,  0xa8,  0xff,  0x00,  0x3a,  0x6c,
-  0x9a,  0xdd,  0x89,  0x18,  0x17,  0x29,  0xf9,  0xd7,  0xdf,  0x9f,  0xf0,  0xe9,
-  0x6f,  0x09,  0x7f,  0xd0,  0xfb,  0xad,  0x7f,  0xe0,  0x24,  0x34,  0x7f,  0xc3,
-  0xa5,  0xbc,  0x25,  0xff,  0x00,  0x43,  0xee,  0xb5,  0xff,  0x00,  0x80,  0x90,
-  0xd1,  0xed,  0xe1,  0xdc,  0x3d,  0x8c,  0xcf,  0xbc,  0xa8,  0xa2,  0x8a,  0xf3,
-  0x0e,  0xf0,  0xa2,  0x8a,  0x28,  0x00,  0xa2,  0x8a,  0x28,  0x00,  0xa2,  0x8a,
-  0x28,  0x00,  0xa2,  0x8a,  0x28,  0x00,  0xa2,  0x8a,  0x28,  0x00,  0xa2,  0x8a,
-  0x28,  0x00,  0xa2,  0x8a,  0x28,  0x00,  0xa2,  0xa0,  0xbb,  0xbd,  0xb7,  0xb0,
-  0x88,  0x49,  0x73,  0x3c,  0x56,  0xf1,  0x96,  0x0a,  0x1e,  0x57,  0x0a,  0x09,
-  0x3d,  0x06,  0x4f,  0x7a,  0x9e,  0x95,  0xd3,  0x76,  0xea,  0x01,  0x45,  0x14,
-  0x53,  0x00,  0xa2,  0x8a,  0x28,  0x00,  0xa2,  0x8a,  0x82,  0xda,  0xf6,  0xde,
-  0xf0,  0xca,  0x2d,  0xe7,  0x8a,  0x73,  0x13,  0x98,  0xe4,  0xf2,  0xdc,  0x36,
-  0xc6,  0x1d,  0x54,  0xe3,  0xa1,  0xf6,  0xa4,  0xda,  0x4e,  0xcc,  0x09,  0xe8,
-  0xa2,  0x8a,  0x60,  0x14,  0x51,  0x45,  0x00,  0x14,  0x51,  0x45,  0x00,  0x14,
-  0x51,  0x45,  0x00,  0x14,  0x51,  0x45,  0x00,  0x14,  0x51,  0x45,  0x00,  0x14,
-  0x51,  0x45,  0x00,  0x14,  0x51,  0x45,  0x00,  0x14,  0x51,  0x45,  0x02,  0xb8,
-  0x51,  0x45,  0x14,  0x05,  0xc2,  0x8a,  0x28,  0xa0,  0x2e,  0x14,  0x51,  0x45,
-  0x01,  0x70,  0xa2,  0x8a,  0x28,  0x18,  0x51,  0x45,  0x14,  0x0a,  0xe1,  0x45,
-  0x14,  0x50,  0x17,  0x0a,  0x28,  0xa2,  0x80,  0xb9,  0xca,  0xfc,  0x4a,  0xf0,
-  0x52,  0x78,  0xef,  0xc2,  0xb7,  0x1a,  0x76,  0xef,  0x2e,  0xe5,  0x4f,  0x9d,
-  0x6c,  0xe4,  0xe0,  0x09,  0x00,  0x38,  0xcf,  0xb1,  0xc9,  0x1f,  0x8e,  0x7b,
-  0x57,  0x3d,  0xf0,  0x5b,  0xc7,  0x53,  0x6b,  0xba,  0x6c,  0xda,  0x16,  0xaa,
-  0x5a,  0x3d,  0x73,  0x4a,  0xfd,  0xd4,  0x8b,  0x2f,  0xdf,  0x91,  0x01,  0xc0,
-  0x27,  0xdc,  0x1e,  0x0f,  0xe0,  0x7b,  0xd7,  0xa3,  0x5c,  0xdc,  0xc5,  0x67,
-  0x04,  0x93,  0xcf,  0x2a,  0x43,  0x0c,  0x60,  0xb3,  0xc9,  0x23,  0x05,  0x55,
-  0x1e,  0xa4,  0x9e,  0x95,  0xf3,  0x47,  0xc4,  0x8f,  0x1f,  0xe9,  0x36,  0xdf,
-  0x10,  0xed,  0x3c,  0x41,  0xe1,  0x39,  0x99,  0xaf,  0xa1,  0xe2,  0xea,  0x42,
-  0x98,  0x82,  0x72,  0x38,  0xe3,  0x90,  0x4e,  0x46,  0x41,  0xe9,  0x9c,  0x0c,
-  0x7a,  0xd7,  0xc4,  0x67,  0x98,  0x9a,  0x59,  0x3e,  0x26,  0x9e,  0x64,  0xa6,
-  0x93,  0x7e,  0xec,  0xe3,  0x7d,  0x65,  0x1e,  0xe9,  0x77,  0x8b,  0xd7,  0xd3,
-  0x4b,  0x99,  0x4d,  0xa8,  0xbe,  0x63,  0xe9,  0xca,  0x2b,  0xe4,  0x3d,  0x73,
-  0xe3,  0x3f,  0x8b,  0xb5,  0xc6,  0x6d,  0xfa,  0xb4,  0x96,  0x71,  0x9e,  0x91,
-  0x59,  0x0f,  0x28,  0x0f,  0xc4,  0x7c,  0xdf,  0x99,  0xae,  0x56,  0xe7,  0x5a,
-  0xd4,  0x6f,  0x18,  0xb5,  0xc5,  0xfd,  0xd4,  0xec,  0x7b,  0xc9,  0x33,  0x31,
-  0xfd,  0x4d,  0x78,  0x75,  0xf8,  0xfb,  0x0b,  0x07,  0x6a,  0x14,  0x65,  0x25,
-  0xe6,  0xd2,  0xff,  0x00,  0x32,  0x1d,  0x75,  0xd1,  0x1f,  0x73,  0x51,  0x5f,
-  0x0b,  0xdb,  0xea,  0xf7,  0xf6,  0xad,  0xba,  0x0b,  0xdb,  0x88,  0x58,  0x77,
-  0x8e,  0x56,  0x53,  0xfa,  0x1a,  0xe9,  0xf4,  0x5f,  0x8b,  0xfe,  0x2e,  0xd0,
-  0xd9,  0x7c,  0xad,  0x66,  0x7b,  0x84,  0x1f,  0xf2,  0xce,  0xec,  0xf9,  0xc0,
-  0xff,  0x00,  0xdf,  0x59,  0x23,  0xf0,  0x34,  0xa8,  0x71,  0xf6,  0x1a,  0x4e,
-  0xd5,  0xa8,  0x4a,  0x2b,  0xc9,  0xa7,  0xfe,  0x40,  0xab,  0xae,  0xa8,  0xfa,
-  0x13,  0xe2,  0xff,  0x00,  0x8f,  0xcf,  0x82,  0xfc,  0x3e,  0x21,  0xb3,  0x6d,
-  0xda,  0xcd,  0xfe,  0x62,  0xb5,  0x45,  0xe5,  0x97,  0xb1,  0x7c,  0x7b,  0x67,
-  0x8f,  0x72,  0x3d,  0xea,  0x5f,  0x84,  0x7e,  0x05,  0x6f,  0x04,  0x78,  0x60,
-  0x2d,  0xd1,  0x2d,  0xa9,  0xde,  0xb0,  0x9e,  0xe8,  0x93,  0x9d,  0xad,  0x8e,
-  0x17,  0xf0,  0x1d,  0x4f,  0xa9,  0x35,  0xe2,  0x5e,  0x13,  0xf8,  0x89,  0x61,
-  0xac,  0xfc,  0x49,  0x8f,  0xc4,  0x3e,  0x30,  0x76,  0xcc,  0x68,  0x16,  0xd8,
-  0x43,  0x19,  0x68,  0x61,  0x61,  0xd0,  0x91,  0x92,  0x40,  0x1c,  0x9e,  0x33,
-  0xc9,  0xcd,  0x7d,  0x3b,  0x63,  0x7f,  0x6d,  0xaa,  0x5a,  0x45,  0x75,  0x69,
-  0x3c,  0x77,  0x36,  0xd2,  0x8d,  0xc9,  0x2c,  0x4c,  0x19,  0x58,  0x7b,  0x11,
-  0x5e,  0xde,  0x4d,  0x8b,  0xa3,  0x9d,  0xe3,  0x2a,  0x66,  0x1c,  0xe9,  0xf2,
-  0x5e,  0x30,  0x8f,  0x58,  0xae,  0xb2,  0x6b,  0xbc,  0xbf,  0x05,  0xa1,  0x50,
-  0x6a,  0x6f,  0x98,  0xb1,  0x45,  0x14,  0x57,  0xdc,  0x9b,  0x5c,  0x28,  0xa2,
-  0x8a,  0x02,  0xe1,  0x45,  0x14,  0x50,  0x17,  0x0a,  0x28,  0xa2,  0x80,  0xb8,
-  0x51,  0x45,  0x14,  0x05,  0xc2,  0x8a,  0x28,  0xa0,  0x2e,  0x14,  0x51,  0x45,
-  0x01,  0x70,  0xa2,  0x8a,  0x28,  0x0b,  0x8d,  0xcd,  0x19,  0xa6,  0xe4,  0x51,
-  0x91,  0x55,  0x62,  0x47,  0x66,  0x8c,  0xd3,  0x72,  0x28,  0xc8,  0xa2,  0xc0,
-  0x3b,  0x34,  0x66,  0x9b,  0x91,  0x46,  0x45,  0x16,  0x01,  0xd9,  0xa3,  0x34,
-  0xdc,  0x8a,  0x32,  0x28,  0xb0,  0x0e,  0xcd,  0x19,  0xa6,  0xe4,  0x52,  0xe4,
-  0x51,  0x60,  0xb8,  0xb9,  0xa3,  0x34,  0xdc,  0x8a,  0x32,  0x28,  0xb0,  0x0e,
-  0xdd,  0x46,  0x69,  0xb9,  0x14,  0x64,  0x51,  0x60,  0x1d,  0x9a,  0xa7,  0xac,
-  0x6b,  0x16,  0x9a,  0x0e,  0x9b,  0x71,  0xa8,  0x5f,  0x4c,  0x20,  0xb5,  0x81,
-  0x37,  0xbb,  0x9e,  0xc3,  0xd0,  0x7a,  0x93,  0xd0,  0x0a,  0xb5,  0x91,  0x5f,
-  0x39,  0xfe,  0xd1,  0x1e,  0x37,  0x7d,  0x4b,  0x5a,  0x4f,  0x0f,  0x5b,  0x48,
-  0x45,  0xa5,  0x96,  0x1e,  0x70,  0xa7,  0xef,  0xca,  0x46,  0x40,  0x3f,  0xee,
-  0x83,  0xf9,  0x93,  0xe9,  0x5e,  0x06,  0x79,  0x9a,  0xc3,  0x27,  0xc1,  0x4b,
-  0x12,  0xd5,  0xe5,  0xb4,  0x57,  0x76,  0xff,  0x00,  0xab,  0xbf,  0x24,  0x44,
-  0xe5,  0xca,  0xae,  0x72,  0xbf,  0x12,  0xbe,  0x2a,  0xea,  0x3e,  0x3e,  0xbd,
-  0x78,  0xd5,  0x9e,  0xd3,  0x48,  0x46,  0xfd,  0xd5,  0xa2,  0x9f,  0xbd,  0xe8,
-  0xcf,  0xea,  0x7f,  0x41,  0xdb,  0xd4,  0xc3,  0xe0,  0x5f,  0x85,  0x1a,  0xd7,
-  0x8f,  0xed,  0xe6,  0xb9,  0xb1,  0xf2,  0x2d,  0xed,  0x22,  0x6d,  0x86,  0x7b,
-  0x96,  0x21,  0x59,  0xb1,  0x9c,  0x0c,  0x02,  0x4f,  0x51,  0xf9,  0xd7,  0x19,
-  0x5e,  0xcd,  0xf0,  0x73,  0xe3,  0x16,  0x97,  0xe1,  0x0d,  0x06,  0x4d,  0x23,
-  0x57,  0x49,  0x63,  0x44,  0x95,  0xa5,  0x86,  0x78,  0x53,  0x78,  0x21,  0xba,
-  0xab,  0x0e,  0xb9,  0xcf,  0x7f,  0x7f,  0x6a,  0xfc,  0x1b,  0x2e,  0xa9,  0x87,
-  0xcd,  0xb3,  0x2f,  0x69,  0x9c,  0xd5,  0x6a,  0x2e,  0xfa,  0xde,  0xda,  0xf4,
-  0x57,  0xe8,  0xbf,  0xe1,  0x8e,  0x48,  0xda,  0x52,  0xf7,  0x8f,  0x30,  0xf1,
-  0x57,  0x85,  0x75,  0x0f,  0x06,  0xeb,  0x12,  0x69,  0xba,  0x94,  0x42,  0x3b,
-  0x84,  0x01,  0x83,  0x21,  0xca,  0xba,  0x9e,  0x8c,  0xa7,  0xb8,  0xac,  0x8a,
-  0xed,  0x3e,  0x2c,  0xf8,  0xee,  0x1f,  0x1f,  0xf8,  0x9c,  0x5e,  0xda,  0xc2,
-  0xf0,  0xda,  0x41,  0x08,  0x82,  0x2f,  0x33,  0x01,  0xd8,  0x02,  0x49,  0x63,
-  0xe9,  0xc9,  0x3c,  0x57,  0x17,  0x5e,  0x26,  0x3e,  0x9e,  0x1e,  0x96,  0x2a,
-  0xa4,  0x30,  0xb2,  0xe6,  0xa6,  0x9b,  0xb3,  0xee,  0x88,  0x76,  0xbe,  0x81,
-  0x5a,  0x1a,  0x06,  0x83,  0x7b,  0xe2,  0x7d,  0x5e,  0xdf,  0x4d,  0xd3,  0xe2,
-  0xf3,  0xae,  0xa7,  0x38,  0x55,  0xce,  0x00,  0x00,  0x64,  0x92,  0x7b,  0x00,
-  0x39,  0xac,  0xfa,  0xea,  0x3e,  0x1b,  0x78,  0xc1,  0x7c,  0x0d,  0xe2,  0xcb,
-  0x5d,  0x52,  0x58,  0x4c,  0xf6,  0xe1,  0x5a,  0x39,  0x51,  0x3e,  0xf6,  0xd6,
-  0x18,  0x24,  0x7b,  0x8e,  0x0d,  0x67,  0x83,  0x85,  0x1a,  0x98,  0x8a,  0x70,
-  0xc4,  0x4b,  0x96,  0x0d,  0xae,  0x67,  0xd9,  0x5f,  0x50,  0x56,  0xbe,  0xa6,
-  0x97,  0x8d,  0x7e,  0x0e,  0xeb,  0xde,  0x06,  0xd3,  0x17,  0x50,  0xbb,  0x36,
-  0xf7,  0x56,  0x99,  0x0b,  0x24,  0x96,  0xae,  0x4f,  0x96,  0x4f,  0x4d,  0xc0,
-  0x81,  0xc1,  0x3c,  0x66,  0xa9,  0xfc,  0x3e,  0xf8,  0x93,  0xaa,  0x78,  0x03,
-  0x50,  0x0f,  0x6c,  0xe6,  0x7b,  0x07,  0x6f,  0xdf,  0xd9,  0x3b,  0x7c,  0x8e,
-  0x3d,  0x47,  0xa3,  0x7b,  0xfe,  0x79,  0xaf,  0x45,  0xf8,  0xad,  0xf1,  0xb3,
-  0x47,  0xf1,  0x27,  0x85,  0x26,  0xd2,  0x34,  0x84,  0x9a,  0x67,  0xbb,  0x2b,
-  0xe6,  0xcb,  0x34,  0x7b,  0x04,  0x6a,  0x18,  0x36,  0x07,  0xa9,  0xc8,  0x1e,
-  0xd5,  0xe1,  0x95,  0xf4,  0x39,  0xab,  0xc2,  0x65,  0x79,  0x84,  0x67,  0x93,
-  0x55,  0x6d,  0x24,  0x9d,  0xd3,  0xbd,  0x9f,  0x55,  0x7e,  0xaa,  0xd6,  0xbe,
-  0xfb,  0xd8,  0xb9,  0x5a,  0x32,  0xf7,  0x59,  0xf6,  0xef,  0x86,  0xbc,  0x49,
-  0x63,  0xe2,  0xbd,  0x1a,  0xdf,  0x53,  0xd3,  0xe5,  0xf3,  0x2d,  0xe6,  0x1d,
-  0xfe,  0xf2,  0x1e,  0xea,  0xc3,  0xb1,  0x15,  0xa9,  0x9a,  0xf9,  0x7b,  0xe0,
-  0x27,  0x8d,  0xe4,  0xf0,  0xef,  0x8a,  0x53,  0x4a,  0x9e,  0x43,  0xfd,  0x9f,
-  0xa9,  0x30,  0x8f,  0x69,  0x3c,  0x24,  0xdf,  0xc0,  0xc3,  0xeb,  0xf7,  0x7f,
-  0x11,  0xe9,  0x5f,  0x4f,  0xe4,  0x57,  0xee,  0x3c,  0x3f,  0x9b,  0xc7,  0x39,
-  0xc1,  0x2a,  0xed,  0x5a,  0x6b,  0x49,  0x2f,  0x3f,  0xf2,  0x7b,  0xfe,  0x1d,
-  0x0e,  0xb8,  0x4f,  0x99,  0x5c,  0x76,  0x4d,  0x19,  0xa6,  0xe4,  0x51,  0x91,
-  0x5f,  0x4b,  0x62,  0xc7,  0x64,  0xd1,  0x9a,  0x6e,  0x45,  0x19,  0x14,  0x58,
-  0x2e,  0x3b,  0x34,  0x66,  0x9b,  0x91,  0x46,  0x45,  0x16,  0x0b,  0x8e,  0xcd,
-  0x19,  0xa6,  0xe4,  0x51,  0x91,  0x45,  0x80,  0x76,  0x68,  0xcd,  0x37,  0x34,
-  0x64,  0x51,  0x60,  0xb8,  0xec,  0xd1,  0x9a,  0x6e,  0x45,  0x19,  0x14,  0x58,
-  0x07,  0x64,  0xd1,  0x9a,  0x6e,  0x45,  0x19,  0x14,  0x58,  0x06,  0x6e,  0xa3,
-  0x75,  0x37,  0x34,  0x66,  0xae,  0xc4,  0x5c,  0x76,  0xea,  0x37,  0x53,  0x73,
-  0x46,  0x68,  0xb0,  0x5c,  0x76,  0xea,  0x37,  0x53,  0x73,  0x46,  0x68,  0xb0,
-  0x5c,  0x76,  0xea,  0x37,  0x53,  0x72,  0x28,  0xcd,  0x16,  0x0b,  0x8e,  0xdd,
-  0x46,  0xea,  0x6e,  0x68,  0xcd,  0x16,  0x0b,  0x8e,  0xdd,  0x46,  0xea,  0x6e,
-  0x68,  0xcd,  0x16,  0x0b,  0x8e,  0xdd,  0x46,  0xea,  0xc4,  0xf1,  0x57,  0x8c,
-  0x34,  0xaf,  0x06,  0x69,  0xff,  0x00,  0x6b,  0xd5,  0x2e,  0x44,  0x28,  0xc7,
-  0x08,  0x8a,  0x37,  0x3c,  0x87,  0xd1,  0x47,  0x7f,  0xe5,  0x5c,  0x0d,  0x9f,
-  0xed,  0x1f,  0xe1,  0xcb,  0x8b,  0xc1,  0x14,  0xd6,  0x97,  0xf6,  0xb0,  0x93,
-  0x81,  0x3b,  0xa2,  0xb0,  0x1e,  0xe4,  0x06,  0x27,  0xf2,  0xcd,  0x78,  0xf8,
-  0xac,  0xdf,  0x2f,  0xc0,  0xd4,  0x54,  0x71,  0x35,  0xa3,  0x19,  0x3e,  0x8d,
-  0xfe,  0x7d,  0xbe,  0x64,  0xb9,  0x25,  0xb9,  0xeb,  0x05,  0xf6,  0x82,  0x4f,
-  0x41,  0x5f,  0x10,  0xeb,  0x7a,  0x93,  0xeb,  0x3a,  0xcd,  0xf5,  0xfc,  0x84,
-  0x97,  0xb9,  0x9d,  0xe6,  0x39,  0xff,  0x00,  0x69,  0x89,  0xfe,  0xb5,  0xf6,
-  0xad,  0x8e,  0xa1,  0x6b,  0xab,  0x58,  0xc5,  0x75,  0x69,  0x34,  0x77,  0x36,
-  0xb3,  0x2e,  0xe4,  0x91,  0x0e,  0x55,  0x85,  0x78,  0x5f,  0xfc,  0x2d,  0x5f,
-  0x87,  0x3f,  0xf4,  0x25,  0x27,  0xfe,  0x00,  0xdb,  0xff,  0x00,  0x8d,  0x7c,
-  0x67,  0x18,  0xe1,  0xa8,  0x63,  0x61,  0x87,  0x55,  0x31,  0x31,  0xa7,  0x1f,
-  0x79,  0xab,  0xdd,  0xf3,  0x7c,  0x3a,  0xab,  0x76,  0xfd,  0x4c,  0xea,  0x59,
-  0xdb,  0x53,  0xc4,  0x68,  0xaf,  0x6e,  0xff,  0x00,  0x85,  0xab,  0xf0,  0xe7,
-  0xfe,  0x84,  0xa4,  0xff,  0x00,  0xc0,  0x1b,  0x7f,  0xf1,  0xa3,  0xfe,  0x16,
-  0xaf,  0xc3,  0x9f,  0xfa,  0x12,  0x93,  0xff,  0x00,  0x00,  0x6d,  0xff,  0x00,
-  0xc6,  0xbf,  0x33,  0xfe,  0xc5,  0xc0,  0xff,  0x00,  0xd0,  0x7c,  0x3e,  0xe9,
-  0x7f,  0x91,  0x8f,  0x2a,  0xee,  0x78,  0x8d,  0x15,  0xed,  0xdf,  0xf0,  0xb5,
-  0x7e,  0x1c,  0xff,  0x00,  0xd0,  0x94,  0x9f,  0xf8,  0x03,  0x6f,  0xfe,  0x34,
-  0x7f,  0xc2,  0xd5,  0xf8,  0x73,  0xff,  0x00,  0x42,  0x52,  0x7f,  0xe0,  0x0d,
-  0xbf,  0xf8,  0xd1,  0xfd,  0x8b,  0x81,  0xff,  0x00,  0xa0,  0xf8,  0x7d,  0xd2,
-  0xff,  0x00,  0x20,  0xe5,  0x5d,  0xcf,  0x11,  0xa2,  0xbd,  0xbb,  0xfe,  0x16,
-  0xaf,  0xc3,  0x9f,  0xfa,  0x12,  0x93,  0xff,  0x00,  0x00,  0x6d,  0xff,  0x00,
-  0xc6,  0x8f,  0xf8,  0x5a,  0xbf,  0x0e,  0x7f,  0xe8,  0x4a,  0x4f,  0xfc,  0x01,
-  0xb7,  0xff,  0x00,  0x1a,  0x3f,  0xb1,  0x70,  0x3f,  0xf4,  0x1f,  0x0f,  0xba,
-  0x5f,  0xe4,  0x1c,  0xab,  0xb9,  0xe2,  0x34,  0x57,  0xb7,  0x7f,  0xc2,  0xd5,
-  0xf8,  0x73,  0xff,  0x00,  0x42,  0x52,  0x7f,  0xe0,  0x0d,  0xbf,  0xf8,  0xd1,
-  0xff,  0x00,  0x0b,  0x57,  0xe1,  0xcf,  0xfd,  0x09,  0x49,  0xff,  0x00,  0x80,
-  0x36,  0xff,  0x00,  0xe3,  0x47,  0xf6,  0x2e,  0x07,  0xfe,  0x83,  0xe1,  0xf7,
-  0x4b,  0xfc,  0x83,  0x95,  0x77,  0x3c,  0x52,  0x09,  0xde,  0xda,  0x78,  0xe6,
-  0x89,  0x8a,  0x49,  0x1b,  0x07,  0x56,  0x1d,  0x41,  0x07,  0x20,  0xd7,  0xdb,
-  0xfa,  0x5d,  0xf0,  0xd4,  0x74,  0xdb,  0x4b,  0xb0,  0x30,  0x27,  0x85,  0x25,
-  0x03,  0xfd,  0xe5,  0x07,  0xfa,  0xd7,  0x85,  0xff,  0x00,  0xc2,  0xd5,  0xf8,
-  0x73,  0xff,  0x00,  0x42,  0x52,  0x7f,  0xe0,  0x0d,  0xbf,  0xf8,  0xd7,  0xb6,
-  0x69,  0x1a,  0x95,  0xa5,  0xc7,  0x87,  0xec,  0xaf,  0xe1,  0x55,  0xb3,  0xb1,
-  0x7b,  0x54,  0x99,  0x11,  0xf0,  0x82,  0x28,  0xca,  0x02,  0x01,  0xec,  0x30,
-  0x3f,  0x0e,  0x2b,  0xf4,  0x7e,  0x0e,  0xc2,  0xd0,  0xc1,  0xce,  0xbc,  0x69,
-  0x62,  0x63,  0x51,  0x34,  0x9b,  0x4a,  0xfa,  0x5a,  0xfa,  0xeb,  0xea,  0x6d,
-  0x4e,  0xca,  0xfa,  0x9a,  0x5b,  0xa8,  0xdd,  0x5e,  0x57,  0xab,  0xfe,  0xd1,
-  0x3e,  0x1b,  0xd3,  0xaf,  0x1a,  0x0b,  0x68,  0x6e,  0xf5,  0x15,  0x53,  0x83,
-  0x34,  0x28,  0xaa,  0x87,  0xe9,  0xb8,  0x82,  0x7f,  0x2a,  0xeb,  0xbc,  0x1b,
-  0xf1,  0x07,  0x45,  0xf1,  0xcd,  0xbb,  0xbe,  0x99,  0x70,  0x7c,  0xe8,  0xc6,
-  0x64,  0xb6,  0x98,  0x6d,  0x91,  0x07,  0xa9,  0x1d,  0xc7,  0xb8,  0xc8,  0xaf,
-  0xb7,  0xc3,  0xe7,  0x19,  0x76,  0x2a,  0xb7,  0xd5,  0xe8,  0x56,  0x8c,  0xa7,
-  0xd9,  0x3f,  0xcb,  0xbf,  0xc8,  0xd1,  0x49,  0x3d,  0x2e,  0x74,  0xdb,  0xa8,
-  0xcd,  0x37,  0x34,  0x64,  0x57,  0xb2,  0x55,  0xc7,  0x6e,  0xa3,  0x75,  0x37,
-  0x34,  0x66,  0x8b,  0x05,  0xc7,  0x6e,  0xa3,  0x75,  0x37,  0x34,  0x66,  0x8b,
-  0x05,  0xc7,  0x6e,  0xa3,  0x75,  0x37,  0x34,  0x66,  0x8b,  0x05,  0xc7,  0x6e,
-  0xa3,  0x75,  0x37,  0x34,  0x64,  0x51,  0x60,  0xb8,  0xed,  0xd4,  0x6e,  0xa6,
-  0xe4,  0x51,  0x9a,  0x2c,  0x17,  0x1b,  0x9a,  0x33,  0x51,  0xee,  0xa3,  0x75,
-  0x55,  0x88,  0xb9,  0x26,  0x68,  0xcd,  0x47,  0xba,  0x8d,  0xd4,  0x58,  0x2e,
-  0x49,  0x9a,  0x33,  0x51,  0xee,  0xa3,  0x75,  0x16,  0x15,  0xc9,  0x32,  0x28,
-  0xa8,  0xf7,  0x51,  0xba,  0x8b,  0x0e,  0xe4,  0x99,  0xa3,  0x35,  0x1e,  0xea,
-  0x37,  0x51,  0x60,  0xb9,  0x26,  0x68,  0xcd,  0x47,  0xba,  0x8c,  0xd3,  0xb0,
-  0x5c,  0xf9,  0x7b,  0xe3,  0xb6,  0xaf,  0x3e,  0xa5,  0xf1,  0x0e,  0xf2,  0xde,
-  0x47,  0x26,  0x1b,  0x24,  0x48,  0x62,  0x4e,  0xc0,  0x15,  0x0c,  0x4f,  0xe2,
-  0x58,  0xfe,  0x95,  0xe7,  0x95,  0xda,  0x7c,  0x64,  0xff,  0x00,  0x92,  0x97,
-  0xad,  0xff,  0x00,  0xbf,  0x1f,  0xfe,  0x8a,  0x4a,  0xe2,  0xeb,  0xf9,  0x47,
-  0x3a,  0x9c,  0xaa,  0x66,  0x78,  0x99,  0x49,  0xdd,  0xf3,  0xcb,  0xf0,  0x6d,
-  0x23,  0x92,  0x5b,  0x9e,  0xf7,  0xfb,  0x34,  0xeb,  0x13,  0xcd,  0x67,  0xac,
-  0xe9,  0xb2,  0x39,  0x6b,  0x78,  0x1a,  0x39,  0xa2,  0x04,  0xfd,  0xd2,  0xdb,
-  0x83,  0x0f,  0xc7,  0x68,  0xfd,  0x6b,  0xc1,  0x2b,  0xda,  0xff,  0x00,  0x66,
-  0x73,  0x8b,  0xed,  0x7f,  0xfe,  0xb9,  0xc3,  0xfc,  0xde,  0xbc,  0x52,  0xbd,
-  0x8c,  0xd2,  0x72,  0x9e,  0x4b,  0x97,  0x39,  0x3b,  0xdb,  0xda,  0xaf,  0x92,
-  0x92,  0xb1,  0x4f,  0xe1,  0x41,  0x45,  0x14,  0x57,  0xc6,  0x90,  0x14,  0x51,
-  0x45,  0x00,  0x14,  0x51,  0x45,  0x00,  0x14,  0x51,  0x45,  0x00,  0x15,  0xef,
-  0x7f,  0x13,  0xf5,  0x89,  0xf4,  0xef,  0x82,  0xbe,  0x19,  0xb6,  0x81,  0xca,
-  0x0b,  0xc8,  0x2d,  0x62,  0x94,  0x83,  0xd5,  0x04,  0x3b,  0x88,  0xfc,  0x48,
-  0x15,  0xe0,  0x95,  0xed,  0x7f,  0x17,  0x0f,  0xfc,  0x5a,  0x5f,  0x05,  0xff,
-  0x00,  0xd7,  0x38,  0x3f,  0xf4,  0x45,  0x7d,  0x96,  0x47,  0x39,  0x43,  0x03,
-  0x98,  0x4a,  0x2e,  0xcf,  0x91,  0x7e,  0x32,  0xb3,  0xfc,  0x0a,  0x8e,  0xcc,
-  0xf1,  0x4a,  0xe9,  0xbe,  0x1a,  0x6a,  0xf3,  0xe8,  0xbe,  0x3a,  0xd1,  0x67,
-  0x81,  0xca,  0x99,  0x2e,  0x52,  0x07,  0x00,  0xfd,  0xe4,  0x76,  0x0a,  0xc0,
-  0xfe,  0x07,  0xf4,  0xae,  0x66,  0xb6,  0x3c,  0x1b,  0xff,  0x00,  0x23,  0x7e,
-  0x87,  0xff,  0x00,  0x5f,  0xd0,  0x7f,  0xe8,  0xc5,  0xaf,  0x9b,  0xc0,  0xce,
-  0x54,  0xf1,  0x54,  0xa7,  0x07,  0x66,  0xa4,  0xbf,  0x31,  0x2d,  0xcf,  0xb4,
-  0x33,  0x46,  0x6a,  0x3d,  0xd4,  0x6e,  0xaf,  0xeb,  0x9b,  0x1d,  0x57,  0x24,
-  0xcd,  0x19,  0xa8,  0xf7,  0x51,  0xba,  0x8b,  0x0e,  0xe4,  0x99,  0xa3,  0x35,
-  0x1e,  0xea,  0x37,  0x51,  0x60,  0xb9,  0x26,  0x68,  0xcd,  0x47,  0xba,  0x8d,
-  0xd4,  0x58,  0x2e,  0x49,  0x9a,  0x33,  0x51,  0xee,  0xa3,  0x75,  0x16,  0x15,
-  0xc9,  0x33,  0x46,  0x6a,  0x3d,  0xd4,  0x6e,  0xa2,  0xc3,  0xb8,  0xdd,  0xd4,
-  0x9b,  0xa9,  0xbb,  0xa8,  0xdd,  0x5a,  0x19,  0xdc,  0x7e,  0xea,  0x4d,  0xd4,
-  0xdd,  0xd4,  0x6e,  0xa0,  0x57,  0x1f,  0xba,  0x8d,  0xd4,  0xcd,  0xd4,  0x6e,
-  0xa0,  0x77,  0x1f,  0xba,  0x8d,  0xd4,  0xcd,  0xd4,  0x6e,  0xa4,  0x2b,  0x8f,
-  0xdd,  0x49,  0xba,  0x9b,  0xba,  0x8d,  0xd4,  0xc2,  0xe3,  0xb7,  0x52,  0xee,
-  0xa6,  0x6e,  0xa3,  0x75,  0x20,  0xb9,  0xf2,  0x9f,  0xc6,  0x3f,  0xf9,  0x29,
-  0x5a,  0xdf,  0xfb,  0xf1,  0xff,  0x00,  0xe8,  0xb4,  0xae,  0x32,  0xbb,  0x2f,
-  0x8c,  0x5c,  0xfc,  0x49,  0xd6,  0xff,  0x00,  0xdf,  0x8f,  0xff,  0x00,  0x45,
-  0xa5,  0x71,  0xb5,  0xfc,  0x99,  0x9c,  0x7f,  0xc8,  0xcb,  0x13,  0xfe,  0x39,
-  0xff,  0x00,  0xe9,  0x4c,  0xc1,  0xee,  0x7b,  0x57,  0xec,  0xd2,  0x71,  0x7d,
-  0xaf,  0x7f,  0xd7,  0x38,  0x7f,  0x9b,  0xd7,  0x8a,  0xd7,  0xb4,  0x7e,  0xcd,
-  0x67,  0x17,  0xda,  0xf7,  0xfd,  0x73,  0x87,  0xf9,  0xbd,  0x78,  0xbd,  0x7b,
-  0x19,  0x97,  0xfc,  0x89,  0x32,  0xef,  0xfb,  0x8b,  0xff,  0x00,  0xa5,  0x21,
-  0xbd,  0x90,  0x51,  0x45,  0x15,  0xf2,  0x02,  0x0a,  0x28,  0xa2,  0x80,  0x0a,
-  0x28,  0xa2,  0x80,  0x0a,  0x28,  0xa2,  0x80,  0x0a,  0xf6,  0xaf,  0x8b,  0x47,
-  0x3f,  0x09,  0x7c,  0x17,  0xff,  0x00,  0x5c,  0xe0,  0xff,  0x00,  0xd1,  0x15,
-  0xe2,  0xb5,  0xed,  0x1f,  0x16,  0x4f,  0xfc,  0x5a,  0x6f,  0x06,  0x7f,  0xd7,
-  0x38,  0x3f,  0xf4,  0x45,  0x7d,  0x7e,  0x4d,  0xff,  0x00,  0x22,  0xfc,  0xc3,
-  0xfc,  0x11,  0xff,  0x00,  0xd2,  0x90,  0xd6,  0xcc,  0xf1,  0x7a,  0xd8,  0xf0,
-  0x67,  0xfc,  0x8e,  0x1a,  0x17,  0xfd,  0x7f,  0xc1,  0xff,  0x00,  0xa3,  0x16,
-  0xb1,  0xeb,  0x63,  0xc1,  0xdf,  0xf2,  0x37,  0x68,  0x7f,  0xf5,  0xfd,  0x07,
-  0xfe,  0x8c,  0x5a,  0xf9,  0xbc,  0x27,  0xfb,  0xcd,  0x3f,  0xf1,  0x2f,  0xcc,
-  0x48,  0xfb,  0x2b,  0x75,  0x1b,  0xa9,  0x9b,  0xa8,  0xdd,  0x5f,  0xd8,  0x16,
-  0x37,  0xb8,  0xfd,  0xd4,  0x6e,  0xa6,  0x6e,  0xa3,  0x75,  0x20,  0xb8,  0xed,
-  0xd4,  0xbb,  0xa9,  0x9b,  0xa8,  0xdd,  0x4c,  0x2e,  0x3f,  0x75,  0x26,  0xea,
-  0x6e,  0xea,  0x37,  0x52,  0x0b,  0x8f,  0xdd,  0x49,  0xba,  0x9b,  0xba,  0x8d,
-  0xd4,  0xec,  0x3b,  0x8f,  0xdd,  0x49,  0xba,  0x9b,  0xba,  0x8d,  0xd4,  0x0a,
-  0xe4,  0x74,  0x53,  0x33,  0x4b,  0x93,  0x57,  0x63,  0x3b,  0x8e,  0xa2,  0x9b,
-  0x9a,  0x4c,  0xd1,  0x60,  0xb8,  0xfa,  0x29,  0x99,  0xa3,  0x34,  0x58,  0x2e,
-  0x3f,  0x34,  0x53,  0x33,  0x4b,  0x93,  0x45,  0x82,  0xe3,  0xa8,  0xcd,  0x33,
-  0x34,  0x66,  0x8b,  0x05,  0xc7,  0xd1,  0x4d,  0xc9,  0xa3,  0x26,  0x8b,  0x05,
-  0xcf,  0x96,  0x3e,  0x30,  0x7f,  0xc9,  0x48,  0xd6,  0xbf,  0xdf,  0x8f,  0xff,
-  0x00,  0x45,  0xa5,  0x71,  0xb5,  0xdd,  0xfc,  0x6c,  0xd3,  0xa6,  0xb1,  0xf8,
-  0x85,  0x7f,  0x2c,  0x8a,  0x44,  0x77,  0x4b,  0x1c,  0xd1,  0xb7,  0x66,  0x1b,
-  0x02,  0x9f,  0xd5,  0x4d,  0x70,  0x95,  0xfc,  0x97,  0x9d,  0x42,  0x50,  0xcc,
-  0xf1,  0x31,  0x92,  0xb7,  0xbf,  0x2f,  0xfd,  0x29,  0x90,  0x7b,  0x3f,  0xec,
-  0xdb,  0xff,  0x00,  0x1f,  0xba,  0xef,  0xfd,  0x73,  0x87,  0xf9,  0xbd,  0x78,
-  0xc5,  0x7b,  0x87,  0xec,  0xe3,  0xa7,  0x4d,  0x1c,  0x3a,  0xd5,  0xf3,  0x29,
-  0x58,  0x24,  0x31,  0xc2,  0x8d,  0xfd,  0xe2,  0x37,  0x16,  0xfc,  0xb2,  0x3f,
-  0x3a,  0xf0,  0xfa,  0xf6,  0x73,  0x58,  0x4a,  0x19,  0x26,  0x5b,  0xcc,  0xad,
-  0x7f,  0x6a,  0xff,  0x00,  0xf2,  0x64,  0x01,  0x45,  0x14,  0x57,  0xc6,  0x00,
-  0x51,  0x45,  0x14,  0x00,  0x51,  0x45,  0x14,  0x00,  0x51,  0x45,  0x14,  0x00,
-  0x57,  0xb3,  0xfc,  0x57,  0xff,  0x00,  0x92,  0x51,  0xe0,  0xdf,  0xfa,  0xe7,
-  0x07,  0xfe,  0x88,  0xaf,  0x18,  0xaf,  0x70,  0xf8,  0x9b,  0xa7,  0x4d,  0x79,
-  0xf0,  0x77,  0xc3,  0x37,  0x11,  0x29,  0x74,  0xb5,  0x8a,  0xd9,  0xe4,  0xc7,
-  0x65,  0x30,  0xed,  0xcf,  0xe6,  0x40,  0xfc,  0x6b,  0xec,  0xf2,  0x38,  0x4a,
-  0x78,  0x0c,  0xc1,  0x45,  0x5f,  0xdc,  0x5f,  0x84,  0xae,  0xc0,  0xf0,  0xfa,
-  0xd8,  0xf0,  0x6f,  0xfc,  0x8d,  0xfa,  0x1f,  0xfd,  0x7f,  0x41,  0xff,  0x00,
-  0xa3,  0x16,  0xb1,  0xeb,  0xa2,  0xf8,  0x79,  0xa7,  0x4d,  0xaa,  0x78,  0xdf,
-  0x45,  0x86,  0x15,  0x2c,  0xcb,  0x75,  0x1c,  0xad,  0x8e,  0xca,  0x8c,  0x18,
-  0x9f,  0xc8,  0x57,  0xcd,  0x60,  0x61,  0x29,  0xe2,  0xe9,  0x46,  0x2a,  0xed,
-  0xca,  0x3f,  0x9a,  0x03,  0xeb,  0x9c,  0xd1,  0x4c,  0xcd,  0x2e,  0x4d,  0x7f,
-  0x60,  0x58,  0xbb,  0x8e,  0xa2,  0x99,  0x9a,  0x33,  0x45,  0x82,  0xe3,  0xe8,
-  0xa6,  0x66,  0x8c,  0xd1,  0x60,  0xb8,  0xfa,  0x29,  0x99,  0xa5,  0xc9,  0xa2,
-  0xc1,  0x71,  0xd9,  0xa2,  0x9b,  0x93,  0x49,  0x9a,  0x2c,  0x17,  0x1f,  0x45,
-  0x33,  0x34,  0x66,  0x8b,  0x05,  0xc6,  0x6e,  0xa3,  0x75,  0x30,  0x90,  0x3a,
-  0x9c,  0x51,  0x9a,  0xd2,  0xc6,  0x57,  0x1f,  0xba,  0x8d,  0xd4,  0xda,  0x4c,
-  0xd1,  0x60,  0xb8,  0xfd,  0xd4,  0x6e,  0xa6,  0x02,  0x0f,  0x43,  0x9a,  0x37,
-  0x01,  0xdf,  0x14,  0x58,  0x2e,  0x3f,  0x75,  0x1b,  0xa9,  0xb4,  0x94,  0x58,
-  0x2e,  0x3f,  0x75,  0x1b,  0xa9,  0xb4,  0x80,  0x83,  0xd0,  0xe6,  0x8b,  0x05,
-  0xc7,  0xee,  0xa3,  0x75,  0x30,  0x90,  0x3a,  0x9c,  0x51,  0x9a,  0x2c,  0x17,
-  0x31,  0x3c,  0x5d,  0xe0,  0xcd,  0x2f,  0xc6,  0xb6,  0x2b,  0x6f,  0xa8,  0xc4,
-  0x4b,  0x26,  0x4c,  0x53,  0xc6,  0x71,  0x24,  0x64,  0xf5,  0xc1,  0xfe,  0x87,
-  0x8a,  0xe0,  0x6d,  0x3f,  0x67,  0x7d,  0x32,  0x2b,  0xb0,  0xf7,  0x1a,  0xad,
-  0xcc,  0xf6,  0xe0,  0xe7,  0xca,  0x58,  0xd5,  0x09,  0x1e,  0x85,  0xb2,  0x7f,
-  0x95,  0x7a,  0xd5,  0x25,  0x78,  0x38,  0xcc,  0x87,  0x2c,  0xcc,  0x2b,  0x2a,
-  0xf8,  0x9a,  0x2a,  0x52,  0xef,  0xaa,  0xfb,  0xec,  0xd5,  0xfe,  0x77,  0x0b,
-  0x95,  0xf4,  0xad,  0x32,  0xd3,  0x44,  0xb0,  0x86,  0xca,  0xc6,  0x05,  0xb7,
-  0xb6,  0x88,  0x61,  0x23,  0x4e,  0x83,  0xfc,  0x4f,  0xbd,  0x7c,  0x6b,  0x5f,
-  0x69,  0x57,  0xc5,  0xb5,  0xf9,  0x8f,  0x88,  0xb0,  0x8d,  0x38,  0xe0,  0xe1,
-  0x05,  0x64,  0xb9,  0xec,  0x97,  0xfd,  0xb8,  0x34,  0x14,  0x51,  0x45,  0x7e,
-  0x32,  0x30,  0xa2,  0x8a,  0x28,  0x00,  0xa2,  0x8a,  0x28,  0x00,  0xa2,  0x8a,
-  0x28,  0x00,  0xaf,  0xad,  0xfc,  0x2b,  0x04,  0x57,  0x9e,  0x06,  0xd1,  0xad,
-  0xe7,  0x8d,  0x66,  0x86,  0x4d,  0x3a,  0x04,  0x78,  0xdc,  0x65,  0x58,  0x18,
-  0xd7,  0x20,  0x8a,  0xf9,  0x22,  0xbe,  0xba,  0xf0,  0x67,  0xfc,  0x89,  0xfa,
-  0x17,  0xfd,  0x78,  0x41,  0xff,  0x00,  0xa2,  0xd6,  0xbf,  0x5c,  0xf0,  0xee,
-  0x2a,  0x58,  0x9c,  0x42,  0x7b,  0x72,  0xaf,  0xcc,  0x47,  0x05,  0xab,  0x7e,
-  0xcf,  0x7a,  0x4d,  0xdd,  0xdb,  0x4b,  0x65,  0xa8,  0x4f,  0x63,  0x13,  0x1c,
-  0xf9,  0x25,  0x04,  0x80,  0x7b,  0x02,  0x48,  0x3f,  0x9e,  0x6b,  0xaf,  0xf0,
-  0x57,  0xc3,  0xcd,  0x27,  0xc0,  0xd1,  0xb9,  0xb3,  0x47,  0x9a,  0xee,  0x41,
-  0xb6,  0x4b,  0xa9,  0xb0,  0x5c,  0x8f,  0x41,  0xe8,  0x3d,  0x87,  0xe3,  0x5d,
-  0x36,  0x69,  0x6b,  0xf5,  0x7c,  0x37,  0x0f,  0xe5,  0x78,  0x3a,  0xff,  0x00,
-  0x59,  0xa1,  0x41,  0x46,  0x7d,  0xf5,  0xd3,  0xd1,  0x6c,  0xbe,  0x49,  0x0a,
-  0xe3,  0xb7,  0x51,  0xba,  0x99,  0x9a,  0x03,  0x03,  0xde,  0xbd,  0xfb,  0x05,
-  0xc7,  0xee,  0xa3,  0x75,  0x30,  0x90,  0x06,  0x4f,  0x14,  0x51,  0x60,  0xb8,
-  0xfd,  0xd4,  0x6e,  0xa6,  0xd1,  0x45,  0x82,  0xe3,  0xb7,  0x51,  0xba,  0x98,
-  0x08,  0x3d,  0x0e,  0x68,  0x24,  0x0e,  0xf4,  0x58,  0x2e,  0x3f,  0x75,  0x1b,
-  0xa9,  0x94,  0xb4,  0x58,  0x2e,  0x3b,  0x75,  0x1b,  0xa9,  0x99,  0xa0,  0x10,
-  0x7a,  0x1a,  0x2c,  0x17,  0x31,  0x62,  0xbd,  0x91,  0x46,  0xf7,  0x90,  0x3e,
-  0xd3,  0xf7,  0x1b,  0xa9,  0xad,  0x58,  0xa5,  0x13,  0x46,  0xae,  0xbd,  0x08,
-  0xac,  0x3f,  0x38,  0xff,  0x00,  0x71,  0x3f,  0xef,  0x91,  0x56,  0x52,  0xf1,
-  0xe3,  0x48,  0x55,  0x42,  0x80,  0x7a,  0x80,  0x3d,  0xeb,  0xb2,  0x70,  0xbe,
-  0xc7,  0x9d,  0x4e,  0xaf,  0x2e,  0xec,  0xd6,  0xcd,  0x36,  0x59,  0x44,  0x31,
-  0xb3,  0xb7,  0x41,  0x49,  0xba,  0xb3,  0x1e,  0xf2,  0x49,  0x12,  0x65,  0x60,
-  0x08,  0x1d,  0x01,  0x1e,  0xf5,  0x84,  0x61,  0xcc,  0x75,  0x4e,  0xa7,  0x22,
-  0x1b,  0x2d,  0xec,  0x8c,  0x0b,  0xa4,  0x81,  0x37,  0x1f,  0xb8,  0xbd,  0x7e,
-  0xb4,  0xb1,  0x5e,  0xc8,  0xa0,  0x3b,  0xb8,  0x7d,  0xa7,  0xee,  0x37,  0x5f,
-  0xad,  0x57,  0xf3,  0x8f,  0xf7,  0x13,  0xfe,  0xf9,  0x14,  0x79,  0xc7,  0xfb,
-  0x89,  0xff,  0x00,  0x7c,  0x8a,  0xeb,  0xe5,  0x56,  0xb5,  0x8e,  0x0e,  0x77,
-  0x7b,  0xdc,  0xdd,  0x8e,  0x41,  0x2a,  0x2b,  0xaf,  0x42,  0x33,  0x4e,  0xac,
-  0xa8,  0xef,  0x1d,  0x3c,  0x85,  0x00,  0x05,  0x3d,  0x40,  0x1e,  0xe6,  0xb4,
-  0x77,  0x57,  0x24,  0xa3,  0xca,  0x77,  0xc2,  0x7c,  0xe8,  0x74,  0x92,  0x08,
-  0xd1,  0x99,  0x8f,  0x00,  0x66,  0xb2,  0xa5,  0xbd,  0x91,  0x81,  0x74,  0x70,
-  0x99,  0x38,  0xd8,  0x3a,  0xfd,  0x69,  0xd2,  0x5e,  0x3b,  0xf9,  0xea,  0x40,
-  0x2a,  0x3a,  0x02,  0x3d,  0xc5,  0x55,  0xf3,  0x8f,  0xf7,  0x13,  0xfe,  0xf9,
-  0x15,  0xbc,  0x21,  0x6d,  0xce,  0x6a,  0x95,  0x6f,  0xa2,  0x64,  0xf1,  0x5e,
-  0x48,  0xa3,  0x7b,  0x48,  0x1f,  0x69,  0xfb,  0x8d,  0xd4,  0xd6,  0xac,  0x52,
-  0x89,  0xa3,  0x57,  0x5e,  0x86,  0xb0,  0xfc,  0xe3,  0xfd,  0xc4,  0xff,  0x00,
-  0xbe,  0x45,  0x59,  0x4b,  0xc7,  0x8d,  0x61,  0x0a,  0x14,  0x03,  0xd4,  0x01,
-  0xef,  0x44,  0xe1,  0x7d,  0x85,  0x4e,  0xaf,  0x2e,  0xec,  0xd6,  0xcd,  0x15,
-  0x1e,  0xea,  0x5d,  0xd5,  0xcd,  0x63,  0xba,  0xe3,  0xeb,  0xc0,  0xbc,  0x71,
-  0xf0,  0x57,  0x55,  0x83,  0x57,  0x9e,  0xe7,  0x44,  0x85,  0x6f,  0x6c,  0xa6,
-  0x72,  0xe2,  0x25,  0x70,  0xaf,  0x16,  0x4e,  0x76,  0xe0,  0x91,  0x91,  0xe9,
-  0x8a,  0xf7,  0xad,  0xd4,  0x66,  0xbe,  0x7f,  0x39,  0xc8,  0xf0,  0x99,  0xe5,
-  0x18,  0xd2,  0xc4,  0xdd,  0x72,  0xbb,  0xa6,  0xb7,  0x5d,  0xfb,  0xef,  0xe8,
-  0x17,  0xb1,  0xf2,  0xc5,  0xff,  0x00,  0xc3,  0x5f,  0x12,  0xe9,  0x96,  0x53,
-  0x5d,  0xdd,  0x69,  0x52,  0x43,  0x6f,  0x0a,  0x97,  0x92,  0x42,  0xe8,  0x42,
-  0x81,  0xd4,  0xf0,  0x6b,  0x99,  0xaf,  0xaa,  0xfe,  0x21,  0x9c,  0xf8,  0x1f,
-  0x5c,  0xff,  0x00,  0xaf,  0x47,  0xfe,  0x55,  0xf2,  0xa5,  0x7e,  0x01,  0xc5,
-  0x59,  0x1e,  0x1f,  0x22,  0xc4,  0x53,  0xa3,  0x87,  0x93,  0x92,  0x94,  0x6f,
-  0xef,  0x5b,  0xbd,  0xba,  0x24,  0x5a,  0x77,  0x0a,  0xe9,  0xec,  0xbe,  0x19,
-  0xf8,  0x9b,  0x51,  0xb3,  0x86,  0xea,  0xdb,  0x49,  0x92,  0x5b,  0x79,  0x90,
-  0x49,  0x1b,  0x87,  0x40,  0x19,  0x48,  0xc8,  0x3d,  0x6b,  0x98,  0xaf,  0xac,
-  0x3c,  0x08,  0x71,  0xe0,  0xad,  0x0b,  0xfe,  0xbc,  0xa1,  0xff,  0x00,  0xd0,
-  0x05,  0x57,  0x0a,  0xe4,  0x58,  0x7c,  0xf6,  0xbd,  0x5a,  0x58,  0x89,  0x4a,
-  0x2a,  0x2a,  0xfe,  0xed,  0xbb,  0xdb,  0xaa,  0x60,  0xdd,  0x8f,  0x9e,  0xdb,
-  0xe1,  0x4f,  0x8a,  0xd1,  0x4b,  0x1d,  0x1a,  0x50,  0x00,  0xc9,  0x3e,  0x62,
-  0x7f,  0xf1,  0x55,  0xc9,  0xd7,  0xd9,  0x17,  0x4d,  0xfe,  0x8d,  0x37,  0xfb,
-  0x87,  0xf9,  0x57,  0xc6,  0xf5,  0xd1,  0xc5,  0x9c,  0x3d,  0x86,  0xc8,  0x5d,
-  0x05,  0x87,  0x9c,  0xa5,  0xcf,  0xcd,  0x7e,  0x6b,  0x74,  0xb6,  0xd6,  0x4b,
-  0xb8,  0x27,  0x70,  0xae,  0x87,  0x47,  0xf0,  0x07,  0x88,  0x35,  0xfb,  0x04,
-  0xbd,  0xb0,  0xd3,  0x64,  0xb9,  0xb5,  0x72,  0x42,  0xc8,  0xae,  0xa0,  0x12,
-  0x0e,  0x0f,  0x53,  0xeb,  0x5c,  0xf5,  0x7d,  0x27,  0xf0,  0x54,  0xe3,  0xe1,
-  0xed,  0x8f,  0xfd,  0x74,  0x97,  0xff,  0x00,  0x43,  0x35,  0xe7,  0x70,  0xbe,
-  0x4f,  0x43,  0x3c,  0xc6,  0xcb,  0x0d,  0x5e,  0x4d,  0x25,  0x16,  0xf4,  0xb5,
-  0xee,  0x9a,  0x5d,  0x53,  0xee,  0x0d,  0xd8,  0xf3,  0x1f,  0x0d,  0x7c,  0x12,
-  0xd7,  0xb5,  0x3d,  0x42,  0x31,  0xa9,  0x40,  0x34,  0xdb,  0x20,  0xc0,  0xc8,
-  0xee,  0xea,  0xce,  0x47,  0x70,  0xa0,  0x13,  0xcf,  0xb9,  0xe2,  0xbe,  0x87,
-  0xb7,  0x82,  0x3b,  0x4b,  0x78,  0xa0,  0x89,  0x42,  0x45,  0x12,  0x84,  0x45,
-  0x1d,  0x80,  0x18,  0x02,  0x97,  0x34,  0x9b,  0xab,  0xfa,  0x07,  0x25,  0xe1,
-  0xfc,  0x1e,  0x45,  0x09,  0x47,  0x0d,  0x76,  0xe5,  0xbb,  0x7a,  0xbd,  0x36,
-  0x5a,  0x24,  0xad,  0xf2,  0x22,  0xf7,  0x24,  0xcd,  0x19,  0xa8,  0xf7,  0x51,
-  0xba,  0xbe,  0x96,  0xc1,  0x71,  0xd2,  0x48,  0x22,  0x46,  0x76,  0xe0,  0x0e,
-  0x6b,  0x2a,  0x5b,  0xd9,  0x18,  0x17,  0x47,  0x11,  0xe4,  0xe3,  0x60,  0xeb,
-  0xf5,  0xa7,  0x49,  0x78,  0xef,  0xe7,  0xa9,  0x00,  0xa8,  0xe8,  0x08,  0xf7,
-  0x02,  0xaa,  0xf9,  0xc7,  0xfb,  0x89,  0xff,  0x00,  0x7c,  0x8a,  0xe9,  0x84,
-  0x2d,  0xb9,  0xc5,  0x56,  0xaf,  0x36,  0x89,  0x93,  0xc5,  0x7b,  0x22,  0x8d,
-  0xef,  0x20,  0x7d,  0xa7,  0xee,  0x37,  0x53,  0x5a,  0xd1,  0x4a,  0x26,  0x8d,
-  0x5d,  0x7a,  0x1a,  0xc2,  0xf3,  0x8f,  0xf7,  0x13,  0xfe,  0xf9,  0x15,  0x65,
-  0x2f,  0x1e,  0x34,  0x84,  0x28,  0x50,  0x09,  0xe4,  0x01,  0xef,  0x44,  0xe1,
-  0x7d,  0x85,  0x4e,  0xaf,  0x2e,  0xec,  0xd6,  0xa6,  0xcb,  0x28,  0x86,  0x36,
-  0x76,  0xe8,  0x29,  0x37,  0x56,  0x63,  0xde,  0x3c,  0x89,  0x30,  0x60,  0xa4,
-  0x0e,  0x80,  0x8f,  0x7a,  0xc2,  0x30,  0xe6,  0x3a,  0xa7,  0x53,  0x91,  0x0d,
-  0x96,  0xf6,  0x46,  0x05,  0xd2,  0x40,  0x9b,  0x8f,  0xdc,  0x5e,  0xa3,  0xde,
-  0x96,  0x2b,  0xd9,  0x14,  0x07,  0x77,  0x0f,  0xb4,  0xfd,  0xc6,  0xeb,  0xf5,
-  0xaa,  0xfe,  0x71,  0xfe,  0xe2,  0x7f,  0xdf,  0x22,  0x8f,  0x38,  0xff,  0x00,
-  0x71,  0x3f,  0xef,  0x91,  0x5d,  0x7c,  0xaa,  0xd6,  0xb1,  0xc1,  0xce,  0xef,
-  0x7b,  0x9b,  0xb1,  0xc8,  0x25,  0x45,  0x75,  0xe8,  0x46,  0x69,  0xd5,  0x95,
-  0x1d,  0xe3,  0xa0,  0x81,  0x46,  0x02,  0x9e,  0xa0,  0x0f,  0x72,  0x2b,  0x4b,
-  0x35,  0xc9,  0x28,  0xf2,  0x9d,  0xf0,  0xa9,  0xce,  0x85,  0x92,  0x41,  0x1a,
-  0x33,  0xb7,  0x40,  0x32,  0x6b,  0x2a,  0x5b,  0xd9,  0x1c,  0x17,  0x47,  0x09,
-  0x93,  0x8d,  0x83,  0xaf,  0xd6,  0x9d,  0x25,  0xe3,  0xbf,  0x9e,  0xa4,  0x02,
-  0xa3,  0xa0,  0x23,  0xdc,  0x55,  0x5f,  0x38,  0xff,  0x00,  0x71,  0x3f,  0xef,
-  0x91,  0x5b,  0xc2,  0x16,  0xdc,  0xe6,  0xa9,  0x57,  0x9b,  0x44,  0xc8,  0xea,
-  0x70,  0xa4,  0x88,  0x30,  0x09,  0xff,  0x00,  0xf5,  0xd3,  0x4d,  0xbb,  0x09,
-  0x84,  0x59,  0x1b,  0xbd,  0x7b,  0x56,  0x95,  0xb4,  0x66,  0x18,  0x42,  0x13,
-  0x92,  0x3d,  0x2a,  0xe5,  0x2b,  0x23,  0x2a,  0x70,  0x72,  0x6d,  0x32,  0x7a,
-  0xc8,  0x2a,  0x40,  0x9f,  0x20,  0x8f,  0xff,  0x00,  0x5d,  0x6a,  0xe6,  0xa3,
-  0xb9,  0x8c,  0xcf,  0x09,  0x40,  0x40,  0x27,  0xd6,  0xb1,  0x83,  0xe5,  0x3a,
-  0x6a,  0x47,  0x99,  0x5c,  0xc7,  0xa2,  0xa5,  0x5b,  0x76,  0x69,  0x8c,  0x59,
-  0x1b,  0xbf,  0x4a,  0x3e,  0xce,  0xde,  0x7f,  0x95,  0x91,  0xbb,  0xd7,  0xb5,
-  0x74,  0xdd,  0x1c,  0x3c,  0xac,  0x7a,  0xa9,  0x2d,  0x6f,  0x80,  0x7f,  0xcb,
-  0x1a,  0xd6,  0xa8,  0x6d,  0xe3,  0x30,  0xc2,  0xa8,  0x48,  0x24,  0x77,  0x15,
-  0x26,  0x6b,  0x9a,  0x6f,  0x99,  0x9d,  0xf4,  0xe3,  0xca,  0x8c,  0xb6,  0x52,
-  0x1a,  0xe3,  0x20,  0xff,  0x00,  0x96,  0x15,  0x5e,  0xb6,  0x2e,  0x23,  0x33,
-  0x44,  0xc8,  0x08,  0x04,  0xd6,  0x67,  0xd9,  0xdb,  0xcf,  0xf2,  0xb2,  0x37,
-  0x7a,  0xf6,  0xad,  0xa1,  0x24,  0xd1,  0xcb,  0x52,  0x0e,  0x2d,  0x58,  0x8a,
-  0xa7,  0x0a,  0x48,  0x83,  0x00,  0x9f,  0xff,  0x00,  0x5d,  0x34,  0xdb,  0xb2,
-  0xcc,  0x22,  0xc8,  0xdd,  0xeb,  0xda,  0xb4,  0xad,  0xa3,  0x30,  0xc2,  0xaa,
-  0x4e,  0x48,  0xf4,  0xa2,  0x52,  0xb2,  0x0a,  0x70,  0x72,  0x6d,  0x32,  0x7a,
-  0x29,  0xa4,  0xd1,  0x9a,  0xe5,  0xb1,  0xde,  0x3a,  0x8a,  0x6e,  0x73,  0x41,
-  0x34,  0x58,  0x0e,  0x7f,  0xe2,  0x1f,  0xfc,  0x88,  0xfa,  0xe7,  0xfd,  0x7a,
-  0xbf,  0xf2,  0xaf,  0x95,  0xab,  0xeb,  0x2f,  0x18,  0x58,  0x4b,  0xaa,  0xf8,
-  0x57,  0x56,  0xb4,  0x80,  0x6e,  0x9a,  0x6b,  0x69,  0x15,  0x17,  0xd5,  0xb6,
-  0x9c,  0x0f,  0xce,  0xbe,  0x4e,  0x65,  0x2a,  0x48,  0x20,  0x82,  0x38,  0x20,
-  0xf6,  0xaf,  0xc1,  0x7c,  0x46,  0x84,  0x96,  0x32,  0x84,  0xed,  0xa3,  0x8b,
-  0x5f,  0x73,  0xff,  0x00,  0x82,  0x8d,  0x20,  0x25,  0x7d,  0x5d,  0xe0,  0x5f,
-  0xf9,  0x12,  0xf4,  0x2f,  0xfa,  0xf2,  0x87,  0xff,  0x00,  0x40,  0x15,  0xf2,
-  0x9a,  0x23,  0x48,  0xea,  0x88,  0xa5,  0x9d,  0x8e,  0x02,  0x81,  0x92,  0x4d,
-  0x7d,  0x69,  0xe1,  0x8b,  0x19,  0x34,  0xbf,  0x0d,  0xe9,  0x76,  0x73,  0x71,
-  0x2c,  0x16,  0xd1,  0xc6,  0xe3,  0xd0,  0x85,  0x00,  0xd5,  0x78,  0x73,  0x09,
-  0x3c,  0x56,  0x22,  0x76,  0xd1,  0x45,  0x2f,  0xc7,  0xfe,  0x00,  0x4c,  0xd0,
-  0xba,  0xff,  0x00,  0x8f,  0x69,  0xbf,  0xdc,  0x3f,  0xca,  0xbe,  0x39,  0xaf,
-  0xb1,  0xe5,  0x5f,  0x32,  0x27,  0x4c,  0xe3,  0x72,  0x91,  0x9a,  0xf9,  0x03,
-  0x50,  0xb1,  0x9b,  0x4c,  0xbe,  0xb8,  0xb4,  0x9d,  0x0a,  0x4d,  0x04,  0x86,
-  0x37,  0x53,  0xd8,  0x83,  0x8a,  0xed,  0xf1,  0x22,  0x12,  0xff,  0x00,  0x65,
-  0x9d,  0xb4,  0xf7,  0xd7,  0xfe,  0x92,  0x10,  0x2b,  0xd7,  0xd2,  0x5f,  0x05,
-  0xbf,  0xe4,  0x9f,  0x58,  0xff,  0x00,  0xd7,  0x49,  0x7f,  0xf4,  0x33,  0x5f,
-  0x36,  0xd7,  0xd3,  0x9f,  0x0a,  0x74,  0xe9,  0xb4,  0xbf,  0x01,  0xe9,  0x91,
-  0x4e,  0xa5,  0x24,  0x75,  0x69,  0x76,  0x9e,  0xa0,  0x33,  0x12,  0x3f,  0x42,
-  0x2b,  0xc3,  0xf0,  0xf6,  0x12,  0x96,  0x69,  0x52,  0x49,  0x68,  0xa0,  0xff,
-  0x00,  0x19,  0x44,  0x72,  0xd8,  0xeb,  0xe8,  0xa6,  0xe6,  0x8c,  0xd7,  0xf4,
-  0x3d,  0x8c,  0x87,  0x51,  0x4d,  0xcd,  0x19,  0xa2,  0xc0,  0x65,  0xb2,  0x90,
-  0xd7,  0x19,  0x04,  0x7f,  0xfb,  0x42,  0xab,  0xd6,  0xc5,  0xc4,  0x66,  0x68,
-  0x59,  0x07,  0x04,  0xfa,  0xd6,  0x67,  0xd9,  0xdb,  0xcf,  0xf2,  0xb2,  0x37,
-  0x7a,  0xf6,  0xae,  0xa8,  0x4a,  0xe8,  0xe0,  0xa9,  0x07,  0x16,  0xac,  0x45,
-  0x53,  0x85,  0x24,  0x41,  0x80,  0x4f,  0xff,  0x00,  0xae,  0x9a,  0x6d,  0xd9,
-  0x66,  0x11,  0x64,  0x6e,  0xf5,  0xed,  0x5a,  0x76,  0xd1,  0x98,  0x21,  0x0a,
-  0x48,  0x27,  0xda,  0x89,  0x4a,  0xc8,  0x29,  0xc1,  0xc9,  0xb4,  0xc9,  0xab,
-  0x20,  0xa9,  0x02,  0x7c,  0x82,  0x3f,  0xfd,  0x75,  0xab,  0x9a,  0x8a,  0xe6,
-  0x33,  0x34,  0x45,  0x41,  0xc1,  0xf7,  0xac,  0x60,  0xf9,  0x4e,  0x9a,  0x91,
-  0xe6,  0x46,  0x45,  0x15,  0x28,  0xb7,  0x66,  0x98,  0xc5,  0x91,  0xb8,  0x77,
-  0xed,  0x47,  0xd9,  0xdb,  0xcf,  0xf2,  0xb2,  0x37,  0x7a,  0xf6,  0xae,  0x9b,
-  0xa3,  0x87,  0x95,  0x8f,  0x55,  0x25,  0xad,  0xf0,  0x0f,  0xf9,  0x63,  0x5a,
-  0xd5,  0x0d,  0xba,  0x18,  0x61,  0x54,  0x24,  0x12,  0x3d,  0x2a,  0x4c,  0xd7,
-  0x34,  0xdf,  0x33,  0x3b,  0xe9,  0xc7,  0x95,  0x19,  0x6c,  0xa4,  0x35,  0xc6,
-  0x41,  0xff,  0x00,  0x2c,  0x2a,  0xbd,  0x6c,  0x5c,  0x46,  0x66,  0x85,  0x90,
-  0x1c,  0x13,  0xeb,  0x59,  0x9f,  0x67,  0x6f,  0x3f,  0xca,  0xc8,  0xdd,  0xfa,
-  0x56,  0xd0,  0x92,  0x68,  0xe5,  0xa9,  0x06,  0x9a,  0xb1,  0xa0,  0xd6,  0xc1,
-  0xae,  0x04,  0xb9,  0x39,  0x1d,  0xaa,  0x6a,  0x28,  0xae,  0x76,  0xdb,  0x3a,
-  0xd2,  0xb6,  0xc1,  0x45,  0x14,  0x52,  0x19,  0x0a,  0xdb,  0x05,  0xb8,  0x32,
-  0xe4,  0xe4,  0xf6,  0xa3,  0xec,  0xc3,  0xed,  0x1e,  0x6e,  0x4e,  0x7d,  0x2a,
-  0x6a,  0x2a,  0xb9,  0x99,  0x3c,  0xa8,  0x28,  0xa2,  0x8a,  0x92,  0x82,  0xa1,
-  0xfb,  0x30,  0xfb,  0x47,  0x9b,  0x93,  0x9f,  0x4a,  0x9a,  0x8a,  0x69,  0xd8,
-  0x4d,  0x5f,  0x72,  0x16,  0xb6,  0x0d,  0x70,  0x25,  0xc9,  0xc8,  0xed,  0x53,
-  0x51,  0x45,  0x0d,  0xb6,  0x09,  0x5b,  0x60,  0xa2,  0x8a,  0x29,  0x0c,  0x28,
-  0xa2,  0x8a,  0x00,  0x2b,  0x83,  0xf1,  0x57,  0xc1,  0xdd,  0x1b,  0xc4,  0xb7,
-  0xaf,  0x79,  0x1b,  0xcb,  0xa7,  0x5d,  0x48,  0x73,  0x21,  0x80,  0x02,  0x8e,
-  0x7d,  0x4a,  0x9e,  0xff,  0x00,  0x42,  0x2b,  0xbc,  0xa2,  0xbc,  0xfc,  0x76,
-  0x5f,  0x85,  0xcc,  0xa9,  0xfb,  0x1c,  0x5d,  0x35,  0x38,  0xf9,  0xfe,  0x8f,
-  0x75,  0xf2,  0x1a,  0x6d,  0x1c,  0x3f,  0x84,  0xbe,  0x11,  0xe8,  0xde,  0x16,
-  0xbb,  0x4b,  0xc2,  0xd2,  0x5f,  0xde,  0x27,  0x29,  0x24,  0xf8,  0xda,  0x87,
-  0xd5,  0x54,  0x77,  0xf7,  0x39,  0xae,  0xe2,  0x8a,  0x29,  0xe0,  0xb0,  0x18,
-  0x5c,  0xba,  0x97,  0xb1,  0xc2,  0x53,  0x50,  0x8f,  0x97,  0xeb,  0xd5,  0xfc,
-  0xc2,  0xed,  0x85,  0x71,  0xfe,  0x31,  0xf8,  0x5f,  0xa4,  0x78,  0xc6,  0x6f,
-  0xb4,  0xcd,  0xe6,  0x5a,  0x5e,  0xe3,  0x06,  0xe2,  0x0c,  0x65,  0xc7,  0x6d,
-  0xc0,  0xf5,  0xfe,  0x7e,  0xf5,  0xd8,  0x51,  0x55,  0x8c,  0xc1,  0x61,  0xf1,
-  0xf4,  0x9d,  0x0c,  0x54,  0x14,  0xe2,  0xfa,  0x3f,  0xeb,  0x46,  0x17,  0x68,
-  0xf3,  0xbf,  0x0f,  0x7c,  0x11,  0xd1,  0x74,  0x6b,  0xc4,  0xb9,  0xb9,  0x96,
-  0x5d,  0x49,  0xd0,  0xe5,  0x63,  0x94,  0x05,  0x8f,  0x3e,  0xa5,  0x47,  0x5f,
-  0xc4,  0xe3,  0xda,  0xbd,  0x13,  0xa5,  0x14,  0x56,  0x38,  0x1c,  0xb7,  0x07,
-  0x96,  0x41,  0xd3,  0xc1,  0xd3,  0x50,  0x4f,  0x7b,  0x75,  0xf5,  0x7b,  0xb0,
-  0x6d,  0xb0,  0xa2,  0x8a,  0x2b,  0xd3,  0x10,  0x51,  0x45,  0x14,  0x00,  0x54,
-  0x3f,  0x66,  0x1f,  0x68,  0xf3,  0x72,  0x73,  0xe9,  0x53,  0x51,  0x4d,  0x3b,
-  0x09,  0xab,  0xee,  0x42,  0xd6,  0xc1,  0xae,  0x04,  0xb9,  0x39,  0x1d,  0xaa,
-  0x6a,  0x28,  0xa1,  0xb6,  0xc1,  0x2b,  0x6c,  0x14,  0x51,  0x45,  0x21,  0x90,
-  0xad,  0xb0,  0x5b,  0x83,  0x2e,  0x4e,  0x4f,  0x6a,  0x3e,  0xcc,  0x3e,  0xd1,
-  0xe6,  0xe4,  0xe7,  0xd2,  0xa6,  0xa2,  0xab,  0x99,  0x93,  0xca,  0x82,  0x8a,
-  0x28,  0xa9,  0x28,  0x2a,  0x1f,  0xb3,  0x0f,  0xb4,  0x79,  0xb9,  0x39,  0xf4,
-  0xa9,  0xa8,  0xa6,  0x9d,  0x84,  0xd5,  0xf7,  0x3e,  0x20,  0xff,  0x00,  0x87,
-  0xa6,  0xf8,  0x5b,  0xfe,  0x84,  0x7d,  0x63,  0xff,  0x00,  0x02,  0xa2,  0xa3,
-  0xfe,  0x1e,  0x9b,  0xe1,  0x6f,  0xfa,  0x11,  0xf5,  0x8f,  0xfc,  0x0a,  0x8a,
-  0xbe,  0x17,  0xfe,  0xc6,  0xb2,  0xff,  0x00,  0x9f,  0x64,  0xa7,  0x47,  0xa2,
-  0x59,  0x31,  0xe6,  0xd9,  0x31,  0x45,  0x8e,  0x9e,  0x44,  0x7d,  0xcd,  0xff,
-  0x00,  0x0f,  0x4d,  0xf0,  0xb7,  0xfd,  0x08,  0xfa,  0xc7,  0xfe,  0x05,  0x45,
-  0x47,  0xfc,  0x3d,  0x37,  0xc2,  0xdf,  0xf4,  0x23,  0xeb,  0x1f,  0xf8,  0x15,
-  0x15,  0x7c,  0x3b,  0xfd,  0x87,  0x61,  0xff,  0x00,  0x3e,  0xb1,  0xfe,  0x54,
-  0xd9,  0x34,  0x6b,  0x05,  0x1c,  0x5b,  0x47,  0x9f,  0xa5,  0x16,  0x0e,  0x44,
-  0x7d,  0xc9,  0xff,  0x00,  0x0f,  0x4d,  0xf0,  0xb7,  0xfd,  0x08,  0xfa,  0xc7,
-  0xfe,  0x05,  0x45,  0x47,  0xfc,  0x3d,  0x37,  0xc2,  0xdf,  0xf4,  0x23,  0xeb,
-  0x1f,  0xf8,  0x15,  0x15,  0x7c,  0x2f,  0xfd,  0x8d,  0x65,  0xff,  0x00,  0x3e,
-  0xc9,  0xf9,  0x53,  0xe3,  0xd1,  0x2c,  0x4f,  0x26,  0xd9,  0x31,  0xf4,  0xa2,
-  0xc1,  0xc8,  0x8f,  0xb9,  0x7f,  0xe1,  0xe9,  0xbe,  0x16,  0xff,  0x00,  0xa1,
-  0x1f,  0x58,  0xff,  0x00,  0xc0,  0xa8,  0xa8,  0xff,  0x00,  0x87,  0xa6,  0xf8,
-  0x5b,  0xfe,  0x84,  0x7d,  0x63,  0xff,  0x00,  0x02,  0xa2,  0xaf,  0x87,  0x7f,
-  0xb0,  0xec,  0x3f,  0xe7,  0xd6,  0x3f,  0xca,  0x99,  0x26,  0x8d,  0x62,  0x38,
-  0x16,  0xc9,  0x9a,  0x2c,  0x1c,  0x88,  0xfb,  0x97,  0xfe,  0x1e,  0x9b,  0xe1,
-  0x6f,  0xfa,  0x11,  0xf5,  0x8f,  0xfc,  0x0a,  0x8a,  0x8f,  0xf8,  0x7a,  0x6f,
-  0x85,  0xbf,  0xe8,  0x47,  0xd6,  0x3f,  0xf0,  0x2a,  0x2a,  0xf8,  0x5f,  0xfb,
-  0x1a,  0xcb,  0xfe,  0x7d,  0x93,  0xf2,  0xa9,  0x23,  0xd1,  0x2c,  0x48,  0xc9,
-  0xb6,  0x4f,  0xca,  0x8b,  0x07,  0x22,  0x3e,  0xe4,  0xff,  0x00,  0x87,  0xa6,
-  0xf8,  0x5b,  0xfe,  0x84,  0x7d,  0x63,  0xff,  0x00,  0x02,  0xa2,  0xa3,  0xfe,
-  0x1e,  0x9b,  0xe1,  0x6f,  0xfa,  0x11,  0xf5,  0x8f,  0xfc,  0x0a,  0x8a,  0xbe,
-  0x1d,  0xfe,  0xc3,  0xb0,  0xff,  0x00,  0x9f,  0x58,  0xff,  0x00,  0x2a,  0x64,
-  0x9a,  0x35,  0x88,  0x38,  0x16,  0xc9,  0xf9,  0x51,  0x60,  0xe4,  0x47,  0xdc,
-  0xbf,  0xf0,  0xf4,  0xdf,  0x0b,  0x7f,  0xd0,  0x8f,  0xac,  0x7f,  0xe0,  0x54,
-  0x54,  0x7f,  0xc3,  0xd3,  0x7c,  0x2d,  0xff,  0x00,  0x42,  0x3e,  0xb1,  0xff,
-  0x00,  0x81,  0x51,  0x57,  0xc2,  0xff,  0x00,  0xd8,  0xd6,  0x5f,  0xf3,  0xec,
-  0x9f,  0x95,  0x48,  0x9a,  0x1d,  0x89,  0x19,  0x36,  0xc9,  0xf9,  0x51,  0x60,
-  0xe4,  0x47,  0xdc,  0x9f,  0xf0,  0xf4,  0xdf,  0x0b,  0x7f,  0xd0,  0x8f,  0xac,
-  0x7f,  0xe0,  0x54,  0x54,  0x7f,  0xc3,  0xd3,  0x7c,  0x2d,  0xff,  0x00,  0x42,
-  0x3e,  0xb1,  0xff,  0x00,  0x81,  0x51,  0x57,  0xc3,  0xbf,  0xd8,  0x76,  0x1f,
-  0xf3,  0xeb,  0x1f,  0xe5,  0x51,  0xbe,  0x8d,  0x63,  0x9c,  0x0b,  0x64,  0xfc,
-  0xa8,  0xb0,  0x72,  0x23,  0xee,  0x6f,  0xf8,  0x7a,  0x6f,  0x85,  0xbf,  0xe8,
-  0x47,  0xd6,  0x3f,  0xf0,  0x2a,  0x2a,  0x3f,  0xe1,  0xe9,  0xbe,  0x16,  0xff,
-  0x00,  0xa1,  0x1f,  0x58,  0xff,  0x00,  0xc0,  0xa8,  0xab,  0xe1,  0x7f,  0xec,
-  0x7b,  0x2f,  0xf9,  0xf6,  0x4f,  0xca,  0x9b,  0x2e,  0x9d,  0xa7,  0xdb,  0xed,
-  0x53,  0x67,  0xe6,  0xc8,  0xc0,  0x90,  0xb1,  0xae,  0x4e,  0x3d,  0x68,  0xb0,
-  0x72,  0x23,  0xee,  0xaf,  0xf8,  0x7a,  0x6f,  0x85,  0xbf,  0xe8,  0x47,  0xd6,
-  0x3f,  0xf0,  0x2a,  0x2a,  0x3f,  0xe1,  0xe9,  0xbe,  0x16,  0xff,  0x00,  0xa1,
-  0x1f,  0x58,  0xff,  0x00,  0xc0,  0xa8,  0xab,  0xe1,  0x1f,  0x23,  0x4b,  0xd8,
-  0x1b,  0xec,  0x44,  0x8d,  0xbb,  0x9b,  0x09,  0xf7,  0x06,  0x48,  0xc9,  0xe7,
-  0xd8,  0xfe,  0x54,  0x3d,  0x9e,  0x9e,  0x2e,  0x04,  0x66,  0xcb,  0x60,  0x27,
-  0x68,  0x72,  0xbf,  0x29,  0x3f,  0x5c,  0xd1,  0x60,  0xe4,  0x47,  0xdd,  0xdf,
-  0xf0,  0xf4,  0xdf,  0x0b,  0x7f,  0xd0,  0x8f,  0xac,  0x7f,  0xe0,  0x54,  0x54,
-  0x7f,  0xc3,  0xd3,  0x7c,  0x2d,  0xff,  0x00,  0x42,  0x3e,  0xb1,  0xff,  0x00,
-  0x81,  0x51,  0x57,  0xc1,  0x82,  0xdf,  0x4e,  0x1b,  0xb7,  0xd9,  0x98,  0x88,
-  0x19,  0xda,  0xeb,  0xc9,  0xe7,  0x1c,  0x73,  0xea,  0x45,  0x4d,  0x1d,  0x9e,
-  0x9a,  0x46,  0x0d,  0x91,  0x12,  0x02,  0x41,  0x8c,  0xaf,  0xcd,  0x9c,  0x67,
-  0xd7,  0xd2,  0x8b,  0x07,  0x22,  0x3e,  0xed,  0xff,  0x00,  0x87,  0xa6,  0xf8,
-  0x5b,  0xfe,  0x84,  0x7d,  0x63,  0xff,  0x00,  0x02,  0xa2,  0xa3,  0xfe,  0x1e,
-  0x9b,  0xe1,  0x6f,  0xfa,  0x11,  0xf5,  0x8f,  0xfc,  0x0a,  0x8a,  0xbe,  0x16,
-  0xb7,  0xd3,  0xf4,  0xeb,  0x86,  0x65,  0xfb,  0x1f,  0x96,  0xea,  0x01,  0x2b,
-  0x22,  0xe0,  0xe0,  0xf7,  0xa7,  0x36,  0x8f,  0x62,  0x49,  0xc5,  0xb2,  0x62,
-  0x8b,  0x07,  0x22,  0x3e,  0xe7,  0xff,  0x00,  0x87,  0xa6,  0xf8,  0x5b,  0xfe,
-  0x84,  0x7d,  0x63,  0xff,  0x00,  0x02,  0xa2,  0xa3,  0xfe,  0x1e,  0x9b,  0xe1,
-  0x6f,  0xfa,  0x11,  0xf5,  0x8f,  0xfc,  0x0a,  0x8a,  0xbe,  0x17,  0xfe,  0xc6,
-  0xb2,  0x3f,  0xf2,  0xec,  0x95,  0x30,  0xd0,  0xec,  0x40,  0xff,  0x00,  0x8f,
-  0x64,  0xa2,  0xc1,  0xc8,  0x8f,  0xb8,  0xbf,  0xe1,  0xe9,  0xbe,  0x16,  0xff,
-  0x00,  0xa1,  0x1f,  0x58,  0xff,  0x00,  0xc0,  0xa8,  0xa8,  0xff,  0x00,  0x87,
-  0xa6,  0xf8,  0x5b,  0xfe,  0x84,  0x7d,  0x63,  0xff,  0x00,  0x02,  0xa2,  0xaf,
-  0x87,  0x7f,  0xb1,  0x2c,  0x07,  0xfc,  0xba,  0xc7,  0xf9,  0x54,  0x27,  0x47,
-  0xb2,  0x27,  0xfe,  0x3d,  0x92,  0x8b,  0x07,  0x22,  0x3e,  0xe8,  0xff,  0x00,
-  0x87,  0xa6,  0xf8,  0x5b,  0xfe,  0x84,  0x7d,  0x63,  0xff,  0x00,  0x02,  0xa2,
-  0xa3,  0xfe,  0x1e,  0x9b,  0xe1,  0x6f,  0xfa,  0x11,  0xf5,  0x8f,  0xfc,  0x0a,
-  0x8a,  0xbe,  0x17,  0x1a,  0x2d,  0x91,  0x38,  0xfb,  0x32,  0x54,  0xdf,  0xd8,
-  0x76,  0x1f,  0xf3,  0xea,  0x9f,  0x95,  0x16,  0x0e,  0x44,  0x7d,  0xc5,  0xff,
-  0x00,  0x0f,  0x4d,  0xf0,  0xb7,  0xfd,  0x08,  0xfa,  0xc7,  0xfe,  0x05,  0x45,
-  0x47,  0xfc,  0x3d,  0x37,  0xc2,  0xdf,  0xf4,  0x23,  0xeb,  0x1f,  0xf8,  0x15,
-  0x15,  0x7c,  0x3a,  0x74,  0x4b,  0x00,  0x33,  0xf6,  0x58,  0xff,  0x00,  0x2a,
-  0x84,  0xe8,  0xd6,  0x5f,  0xf3,  0xec,  0x94,  0x58,  0x39,  0x11,  0xf7,  0x47,
-  0xfc,  0x3d,  0x37,  0xc2,  0xdf,  0xf4,  0x23,  0xeb,  0x1f,  0xf8,  0x15,  0x15,
-  0x1f,  0xf0,  0xf4,  0xdf,  0x0b,  0x7f,  0xd0,  0x8f,  0xac,  0x7f,  0xe0,  0x54,
-  0x55,  0xf0,  0xc2,  0xe8,  0xb6,  0x4c,  0x40,  0xfb,  0x32,  0x54,  0xbf,  0xd8,
-  0x76,  0x1f,  0xf3,  0xea,  0x94,  0x58,  0x39,  0x11,  0xf7,  0x17,  0xfc,  0x3d,
-  0x37,  0xc2,  0xdf,  0xf4,  0x23,  0xeb,  0x1f,  0xf8,  0x15,  0x15,  0x1f,  0xf0,
-  0xf4,  0xdf,  0x0b,  0x7f,  0xd0,  0x8f,  0xac,  0x7f,  0xe0,  0x54,  0x55,  0xf0,
-  0xe3,  0x68,  0xb6,  0x0a,  0x09,  0xfb,  0x2c,  0x7f,  0x95,  0x45,  0xfd,  0x8d,
-  0x65,  0xff,  0x00,  0x3e,  0xc9,  0x45,  0x83,  0x91,  0x1f,  0x74,  0x7f,  0xc3,
-  0xd3,  0x7c,  0x2d,  0xff,  0x00,  0x42,  0x3e,  0xb1,  0xff,  0x00,  0x81,  0x51,
-  0x51,  0xff,  0x00,  0x0f,  0x4d,  0xf0,  0xb7,  0xfd,  0x08,  0xfa,  0xc7,  0xfe,
-  0x05,  0x45,  0x5f,  0x0c,  0x26,  0x89,  0x64,  0xcd,  0xff,  0x00,  0x1e,  0xc9,
-  0x52,  0xff,  0x00,  0x61,  0xd8,  0x7f,  0xcf,  0xac,  0x7f,  0x95,  0x16,  0x0e,
-  0x44,  0x7d,  0xc5,  0xff,  0x00,  0x0f,  0x4d,  0xf0,  0xb7,  0xfd,  0x08,  0xfa,
-  0xc7,  0xfe,  0x05,  0x45,  0x47,  0xfc,  0x3d,  0x37,  0xc2,  0xdf,  0xf4,  0x23,
-  0xeb,  0x1f,  0xf8,  0x15,  0x15,  0x7c,  0x38,  0xfa,  0x2d,  0x82,  0xaf,  0xfc,
-  0x7a,  0xc7,  0xf9,  0x54,  0x5f,  0xd8,  0xd6,  0x5f,  0xf3,  0xec,  0x94,  0x58,
-  0x39,  0x11,  0x72,  0xa7,  0x45,  0xda,  0xb8,  0xa8,  0xe3,  0x5c,  0xb6,  0x7d,
-  0x2a,  0x5a,  0xa2,  0xc2,  0xa1,  0x66,  0xdc,  0xd9,  0xa7,  0xc8,  0xd8,  0x18,
-  0xf5,  0xa8,  0xa8,  0x01,  0x40,  0xc9,  0xa9,  0xd4,  0x6d,  0x18,  0xa8,  0xe2,
-  0x5e,  0x73,  0x52,  0x50,  0x00,  0x4e,  0x05,  0x40,  0xc7,  0x71,  0xcd,  0x49,
-  0x2b,  0x71,  0x8a,  0x8a,  0x80,  0x14,  0x0c,  0x9c,  0x54,  0xe0,  0x60,  0x62,
-  0xa3,  0x89,  0x7b,  0xd4,  0x94,  0x00,  0x13,  0x80,  0x4d,  0x40,  0x4e,  0x4e,
-  0x69,  0xf2,  0xb7,  0x6a,  0x8e,  0x80,  0x15,  0x46,  0xe3,  0x8a,  0x9e,  0x99,
-  0x1a,  0xe0,  0x67,  0xd6,  0x9f,  0x40,  0x08,  0xc7,  0x68,  0xcd,  0x41,  0x4f,
-  0x91,  0xb2,  0x71,  0xe9,  0x4c,  0xa0,  0x07,  0x22,  0xee,  0x6f,  0x6a,  0x27,
-  0xb5,  0x59,  0xa4,  0x49,  0x37,  0xbc,  0x6e,  0xbc,  0x06,  0x43,  0x8c,  0x8f,
-  0x43,  0xed,  0x52,  0x46,  0xb8,  0x5f,  0x73,  0x4e,  0xa0,  0x0a,  0xa6,  0xca,
-  0x38,  0xa2,  0x95,  0x41,  0x6f,  0xde,  0x2e,  0xc3,  0xcf,  0x6c,  0x93,  0xff,
-  0x00,  0xb3,  0x1a,  0x87,  0xec,  0x60,  0xca,  0xae,  0xd2,  0x48,  0xe1,  0x4e,
-  0x42,  0x12,  0x36,  0x83,  0xf9,  0x55,  0xa9,  0x1b,  0x73,  0x7b,  0x0a,  0x6d,
-  0x00,  0x57,  0x8b,  0x49,  0xb7,  0x0c,  0xfb,  0x53,  0xcb,  0x0c,  0x00,  0x21,
-  0x38,  0xe8,  0x72,  0x0f,  0xd6,  0xa6,  0x5d,  0x39,  0x17,  0x90,  0xf2,  0x79,
-  0x99,  0x2c,  0x64,  0x27,  0x2c,  0x4e,  0xdc,  0x7e,  0x82,  0xac,  0xa2,  0xed,
-  0x5a,  0x5a,  0x00,  0xad,  0x1d,  0xaa,  0xdb,  0x16,  0x6f,  0x31,  0xe5,  0x91,
-  0xc0,  0x05,  0xe4,  0x39,  0x38,  0x1d,  0xbf,  0x5a,  0x5a,  0x73,  0xb6,  0xe6,
-  0xa6,  0xf5,  0xa0,  0x07,  0xc4,  0xb9,  0x39,  0xf4,  0xa9,  0x69,  0x14,  0x6d,
-  0x18,  0xa5,  0xe9,  0x40,  0x0c,  0x95,  0xb0,  0x31,  0x51,  0x52,  0xb1,  0xdc,
-  0x49,  0xa0,  0x0c,  0x9c,  0x50,  0x03,  0xe2,  0x5e,  0xf5,  0x25,  0x00,  0x60,
-  0x62,  0x82,  0x70,  0x33,  0x40,  0x11,  0xca,  0xdd,  0xaa,  0x3a,  0x52,  0x72,
-  0x73,  0x42,  0x8d,  0xc4,  0x0a,  0x00,  0x92,  0x25,  0xc0,  0xcd,  0x3e,  0x8e,
-  0x94,  0x8c,  0x76,  0x82,  0x68,  0x02,  0x39,  0x5b,  0x27,  0x1e,  0x94,  0xca,
-  0x3a,  0xd3,  0x91,  0x77,  0x35,  0x00,  0x49,  0x1a,  0xe1,  0x7d,  0xcd,  0x3a,
-  0x8a,  0x47,  0x6d,  0xab,  0x40,  0x11,  0xc8,  0xd9,  0x6f,  0x61,  0x4c,  0xa2,
-  0x9d,  0x1a,  0xee,  0x6f,  0x61,  0x40,  0x1f,  0xff,  0xd9
-};
diff --git a/services/camera/libcameraservice/FakeCamera.cpp b/services/camera/libcameraservice/FakeCamera.cpp
deleted file mode 100644
index f3a6a67..0000000
--- a/services/camera/libcameraservice/FakeCamera.cpp
+++ /dev/null
@@ -1,433 +0,0 @@
-/*
-**
-** Copyright 2008, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
-**
-**     http://www.apache.org/licenses/LICENSE-2.0 
-**
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
-** limitations under the License.
-*/
-
-#define LOG_TAG "FakeCamera"
-#include <utils/Log.h>
-
-#include <string.h>
-#include <stdlib.h>
-#include <utils/String8.h>
-
-#include "FakeCamera.h"
-
-
-namespace android {
-
-// TODO: All this rgb to yuv should probably be in a util class.
-
-// TODO: I think something is wrong in this class because the shadow is kBlue
-// and the square color should alternate between kRed and kGreen. However on the
-// emulator screen these are all shades of gray. Y seems ok but the U and V are
-// probably not.
-
-static int tables_initialized = 0;
-uint8_t *gYTable, *gCbTable, *gCrTable;
-
-static int
-clamp(int  x)
-{
-    if (x > 255) return 255;
-    if (x < 0)   return 0;
-    return x;
-}
-
-/* the equation used by the video code to translate YUV to RGB looks like this
- *
- *    Y  = (Y0 - 16)*k0
- *    Cb = Cb0 - 128
- *    Cr = Cr0 - 128
- *
- *    G = ( Y - k1*Cr - k2*Cb )
- *    R = ( Y + k3*Cr )
- *    B = ( Y + k4*Cb )
- *
- */
-
-static const double  k0 = 1.164;
-static const double  k1 = 0.813;
-static const double  k2 = 0.391;
-static const double  k3 = 1.596;
-static const double  k4 = 2.018;
-
-/* let's try to extract the value of Y
- *
- *   G + k1/k3*R + k2/k4*B = Y*( 1 + k1/k3 + k2/k4 )
- *
- *   Y  = ( G + k1/k3*R + k2/k4*B ) / (1 + k1/k3 + k2/k4)
- *   Y0 = ( G0 + k1/k3*R0 + k2/k4*B0 ) / ((1 + k1/k3 + k2/k4)*k0) + 16
- *
- * let define:
- *   kYr = k1/k3
- *   kYb = k2/k4
- *   kYy = k0 * ( 1 + kYr + kYb )
- *
- * we have:
- *    Y  = ( G + kYr*R + kYb*B )
- *    Y0 = clamp[ Y/kYy + 16 ]
- */
-
-static const double kYr = k1/k3;
-static const double kYb = k2/k4;
-static const double kYy = k0*( 1. + kYr + kYb );
-
-static void
-initYtab( void )
-{
-    const  int imax = (int)( (kYr + kYb)*(31 << 2) + (61 << 3) + 0.1 );
-    int    i;
-
-    gYTable = (uint8_t *)malloc(imax);
-
-    for(i=0; i<imax; i++) {
-        int  x = (int)(i/kYy + 16.5);
-        if (x < 16) x = 16;
-        else if (x > 235) x = 235;
-        gYTable[i] = (uint8_t) x;
-    }
-}
-
-/*
- *   the source is RGB565, so adjust for 8-bit range of input values:
- *
- *   G = (pixels >> 3) & 0xFC;
- *   R = (pixels >> 8) & 0xF8;
- *   B = (pixels & 0x1f) << 3;
- *
- *   R2 = (pixels >> 11)      R = R2*8
- *   B2 = (pixels & 0x1f)     B = B2*8
- *
- *   kYr*R = kYr2*R2 =>  kYr2 = kYr*8
- *   kYb*B = kYb2*B2 =>  kYb2 = kYb*8
- *
- *   we want to use integer multiplications:
- *
- *   SHIFT1 = 9
- *
- *   (ALPHA*R2) >> SHIFT1 == R*kYr  =>  ALPHA = kYr*8*(1 << SHIFT1)
- *
- *   ALPHA = kYr*(1 << (SHIFT1+3))
- *   BETA  = kYb*(1 << (SHIFT1+3))
- */
-
-static const int  SHIFT1  = 9;
-static const int  ALPHA   = (int)( kYr*(1 << (SHIFT1+3)) + 0.5 );
-static const int  BETA    = (int)( kYb*(1 << (SHIFT1+3)) + 0.5 );
-
-/*
- *  now let's try to get the values of Cb and Cr
- *
- *  R-B = (k3*Cr - k4*Cb)
- *
- *    k3*Cr = k4*Cb + (R-B)
- *    k4*Cb = k3*Cr - (R-B)
- *
- *  R-G = (k1+k3)*Cr + k2*Cb
- *      = (k1+k3)*Cr + k2/k4*(k3*Cr - (R-B)/k0)
- *      = (k1 + k3 + k2*k3/k4)*Cr - k2/k4*(R-B)
- *
- *  kRr*Cr = (R-G) + kYb*(R-B)
- *
- *  Cr  = ((R-G) + kYb*(R-B))/kRr
- *  Cr0 = clamp(Cr + 128)
- */
-
-static const double  kRr = (k1 + k3 + k2*k3/k4);
-
-static void
-initCrtab( void )
-{
-    uint8_t *pTable;
-    int i;
-
-    gCrTable = (uint8_t *)malloc(768*2);
-
-    pTable = gCrTable + 384;
-    for(i=-384; i<384; i++)
-        pTable[i] = (uint8_t) clamp( i/kRr + 128.5 );
-}
-
-/*
- *  B-G = (k2 + k4)*Cb + k1*Cr
- *      = (k2 + k4)*Cb + k1/k3*(k4*Cb + (R-B))
- *      = (k2 + k4 + k1*k4/k3)*Cb + k1/k3*(R-B)
- *
- *  kBb*Cb = (B-G) - kYr*(R-B)
- *
- *  Cb   = ((B-G) - kYr*(R-B))/kBb
- *  Cb0  = clamp(Cb + 128)
- *
- */
-
-static const double  kBb = (k2 + k4 + k1*k4/k3);
-
-static void
-initCbtab( void )
-{
-    uint8_t *pTable;
-    int i;
-
-    gCbTable = (uint8_t *)malloc(768*2);
-
-    pTable = gCbTable + 384;
-    for(i=-384; i<384; i++)
-        pTable[i] = (uint8_t) clamp( i/kBb + 128.5 );
-}
-
-/*
- *   SHIFT2 = 16
- *
- *   DELTA = kYb*(1 << SHIFT2)
- *   GAMMA = kYr*(1 << SHIFT2)
- */
-
-static const int  SHIFT2 = 16;
-static const int  DELTA  = kYb*(1 << SHIFT2);
-static const int  GAMMA  = kYr*(1 << SHIFT2);
-
-int32_t ccrgb16toyuv_wo_colorkey(uint8_t *rgb16, uint8_t *yuv420,
-        uint32_t *param, uint8_t *table[])
-{
-    uint16_t *inputRGB = (uint16_t*)rgb16;
-    uint8_t *outYUV = yuv420;
-    int32_t width_dst = param[0];
-    int32_t height_dst = param[1];
-    int32_t pitch_dst = param[2];
-    int32_t mheight_dst = param[3];
-    int32_t pitch_src = param[4];
-    uint8_t *y_tab = table[0];
-    uint8_t *cb_tab = table[1];
-    uint8_t *cr_tab = table[2];
-
-    int32_t size16 = pitch_dst*mheight_dst;
-    int32_t i,j,count;
-    int32_t ilimit,jlimit;
-    uint8_t *tempY,*tempU,*tempV;
-    uint16_t pixels;
-    int   tmp;
-uint32_t temp;
-
-    tempY = outYUV;
-    tempU = outYUV + (height_dst * pitch_dst);
-    tempV = tempU + 1;
-
-    jlimit = height_dst;
-    ilimit = width_dst;
-
-    for(j=0; j<jlimit; j+=1)
-    {
-        for (i=0; i<ilimit; i+=2)
-        {
-            int32_t   G_ds = 0, B_ds = 0, R_ds = 0;
-            uint8_t   y0, y1, u, v;
-
-            pixels =  inputRGB[i];
-            temp = (BETA*(pixels & 0x001F) + ALPHA*(pixels>>11) );
-            y0   = y_tab[(temp>>SHIFT1) + ((pixels>>3) & 0x00FC)];
-
-            G_ds    += (pixels>>1) & 0x03E0;
-            B_ds    += (pixels<<5) & 0x03E0;
-            R_ds    += (pixels>>6) & 0x03E0;
-
-            pixels =  inputRGB[i+1];
-            temp = (BETA*(pixels & 0x001F) + ALPHA*(pixels>>11) );
-            y1   = y_tab[(temp>>SHIFT1) + ((pixels>>3) & 0x00FC)];
-
-            G_ds    += (pixels>>1) & 0x03E0;
-            B_ds    += (pixels<<5) & 0x03E0;
-            R_ds    += (pixels>>6) & 0x03E0;
-
-            R_ds >>= 1;
-            B_ds >>= 1;
-            G_ds >>= 1;
-
-            tmp = R_ds - B_ds;
-
-            u = cb_tab[(((B_ds-G_ds)<<SHIFT2) - GAMMA*tmp)>>(SHIFT2+2)];
-            v = cr_tab[(((R_ds-G_ds)<<SHIFT2) + DELTA*tmp)>>(SHIFT2+2)];
-
-            tempY[0] = y0;
-            tempY[1] = y1;
-            tempY += 2;
-
-            if ((j&1) == 0) {
-                tempU[0] = u;
-                tempV[0] = v;
-                tempU += 2;
-                tempV += 2;
-            }
-        }
-
-        inputRGB += pitch_src;
-    }
-
-    return 1;
-}
-
-#define min(a,b) ((a)<(b)?(a):(b))
-#define max(a,b) ((a)>(b)?(a):(b))
-
-static void convert_rgb16_to_yuv420(uint8_t *rgb, uint8_t *yuv, int width, int height)
-{
-    if (!tables_initialized) {
-        initYtab();
-        initCrtab();
-        initCbtab();
-        tables_initialized = 1;
-    }
-
-    uint32_t param[6];
-    param[0] = (uint32_t) width;
-    param[1] = (uint32_t) height;
-    param[2] = (uint32_t) width;
-    param[3] = (uint32_t) height;
-    param[4] = (uint32_t) width;
-    param[5] = (uint32_t) 0;
-
-    uint8_t *table[3];
-    table[0] = gYTable;
-    table[1] = gCbTable + 384;
-    table[2] = gCrTable + 384;
-
-    ccrgb16toyuv_wo_colorkey(rgb, yuv, param, table);
-}
-
-const int FakeCamera::kRed;
-const int FakeCamera::kGreen;
-const int FakeCamera::kBlue;
-
-FakeCamera::FakeCamera(int width, int height)
-          : mTmpRgb16Buffer(0)
-{
-    setSize(width, height);
-}
-
-FakeCamera::~FakeCamera()
-{
-    delete[] mTmpRgb16Buffer;
-}
-
-void FakeCamera::setSize(int width, int height)
-{
-    mWidth = width;
-    mHeight = height;
-    mCounter = 0;
-    mCheckX = 0;
-    mCheckY = 0;
-
-    // This will cause it to be reallocated on the next call
-    // to getNextFrameAsYuv420().
-    delete[] mTmpRgb16Buffer;
-    mTmpRgb16Buffer = 0;
-}
-
-void FakeCamera::getNextFrameAsRgb565(uint16_t *buffer)
-{
-    int size = mWidth / 10;
-
-    drawCheckerboard(buffer, size);
-
-    int x = ((mCounter*3)&255);
-    if(x>128) x = 255 - x;
-    int y = ((mCounter*5)&255);
-    if(y>128) y = 255 - y;
-
-    drawSquare(buffer, x*size/32, y*size/32, (size*5)>>1, (mCounter&0x100)?kRed:kGreen, kBlue);
-
-    mCounter++;
-}
-
-void FakeCamera::getNextFrameAsYuv420(uint8_t *buffer)
-{
-    if (mTmpRgb16Buffer == 0)
-        mTmpRgb16Buffer = new uint16_t[mWidth * mHeight];
-
-    getNextFrameAsRgb565(mTmpRgb16Buffer);
-    convert_rgb16_to_yuv420((uint8_t*)mTmpRgb16Buffer, buffer, mWidth, mHeight);
-}
-
-void FakeCamera::drawSquare(uint16_t *dst, int x, int y, int size, int color, int shadow)
-{
-    int square_xstop, square_ystop, shadow_xstop, shadow_ystop;
-
-    square_xstop = min(mWidth, x+size);
-    square_ystop = min(mHeight, y+size);
-    shadow_xstop = min(mWidth, x+size+(size/4));
-    shadow_ystop = min(mHeight, y+size+(size/4));
-
-    // Do the shadow.
-    uint16_t *sh = &dst[(y+(size/4))*mWidth];
-    for (int j = y + (size/4); j < shadow_ystop; j++) {
-        for (int i = x + (size/4); i < shadow_xstop; i++) {
-            sh[i] &= shadow;
-        }
-        sh += mWidth;
-    }
-
-    // Draw the square.
-    uint16_t *sq = &dst[y*mWidth];
-    for (int j = y; j < square_ystop; j++) {
-        for (int i = x; i < square_xstop; i++) {
-            sq[i] = color;
-        }
-        sq += mWidth;
-    }
-}
-
-void FakeCamera::drawCheckerboard(uint16_t *dst, int size)
-{
-    bool black = true;
-
-    if((mCheckX/size)&1)
-        black = false;
-    if((mCheckY/size)&1)
-        black = !black;
-
-    int county = mCheckY%size;
-    int checkxremainder = mCheckX%size;
-
-    for(int y=0;y<mHeight;y++) {
-        int countx = checkxremainder;
-        bool current = black;
-        for(int x=0;x<mWidth;x++) {
-            dst[y*mWidth+x] = current?0:0xffff;
-            if(countx++ >= size) {
-                countx=0;
-                current = !current;
-            }
-        }
-        if(county++ >= size) {
-            county=0;
-            black = !black;
-        }
-    }
-    mCheckX += 3;
-    mCheckY++;
-}
-
-
-void FakeCamera::dump(int fd) const
-{
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-    snprintf(buffer, 255, " width x height (%d x %d), counter (%d), check x-y coordinate(%d, %d)\n", mWidth, mHeight, mCounter, mCheckX, mCheckY);
-    result.append(buffer);
-    ::write(fd, result.string(), result.size());
-}
-
-
-}; // namespace android
diff --git a/services/camera/libcameraservice/FakeCamera.h b/services/camera/libcameraservice/FakeCamera.h
deleted file mode 100644
index 724de20..0000000
--- a/services/camera/libcameraservice/FakeCamera.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
-**
-** Copyright 2008, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
-**
-**     http://www.apache.org/licenses/LICENSE-2.0 
-**
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
-** limitations under the License.
-*/
-
-#ifndef ANDROID_HARDWARE_FAKECAMERA_H
-#define ANDROID_HARDWARE_FAKECAMERA_H
-
-#include <sys/types.h>
-#include <stdint.h>
-
-namespace android {
-
-/*
- * FakeCamera is used in the CameraHardwareStub to provide a fake video feed
- * when the system does not have a camera in hardware.
- * The fake video is a moving black and white checkerboard background with a
- * bouncing gray square in the foreground.
- * This class is not thread-safe.
- *
- * TODO: Since the major methods provides a raw/uncompressed video feed, rename
- * this class to RawVideoSource.
- */
-
-class FakeCamera {
-public:
-    FakeCamera(int width, int height);
-    ~FakeCamera();
-
-    void setSize(int width, int height);
-    void getNextFrameAsYuv420(uint8_t *buffer);
-    // Write to the fd a string representing the current state.
-    void dump(int fd) const;
-
-private:
-    // TODO: remove the uint16_t buffer param everywhere since it is a field of
-    // this class.
-    void getNextFrameAsRgb565(uint16_t *buffer);
-
-    void drawSquare(uint16_t *buffer, int x, int y, int size, int color, int shadow);
-    void drawCheckerboard(uint16_t *buffer, int size);
-
-    static const int kRed = 0xf800;
-    static const int kGreen = 0x07c0;
-    static const int kBlue = 0x003e;
-
-    int         mWidth, mHeight;
-    int         mCounter;
-    int         mCheckX, mCheckY;
-    uint16_t    *mTmpRgb16Buffer;
-};
-
-}; // namespace android
-
-#endif // ANDROID_HARDWARE_FAKECAMERA_H
diff --git a/services/camera/libcameraservice/MediaConsumer.cpp b/services/camera/libcameraservice/MediaConsumer.cpp
new file mode 100644
index 0000000..0d857cf
--- /dev/null
+++ b/services/camera/libcameraservice/MediaConsumer.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaConsumer"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include <utils/Log.h>
+
+#include "MediaConsumer.h"
+
+#define MC_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define MC_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define MC_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define MC_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define MC_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__)
+
+namespace android {
+
+// Get an ID that's unique within this process.
+static int32_t createProcessUniqueId() {
+    static volatile int32_t globalCounter = 0;
+    return android_atomic_inc(&globalCounter);
+}
+
+MediaConsumer::MediaConsumer(uint32_t maxLockedBuffers) :
+    mMaxLockedBuffers(maxLockedBuffers),
+    mCurrentLockedBuffers(0)
+{
+    mName = String8::format("mc-unnamed-%d-%d", getpid(),
+            createProcessUniqueId());
+
+    mBufferQueue = new BufferQueue(true);
+
+    wp<BufferQueue::ConsumerListener> listener;
+    sp<BufferQueue::ConsumerListener> proxy;
+    listener = static_cast<BufferQueue::ConsumerListener*>(this);
+    proxy = new BufferQueue::ProxyConsumerListener(listener);
+
+    status_t err = mBufferQueue->consumerConnect(proxy);
+    if (err != NO_ERROR) {
+        ALOGE("MediaConsumer: error connecting to BufferQueue: %s (%d)",
+                strerror(-err), err);
+    } else {
+        mBufferQueue->setSynchronousMode(true);
+        mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER);
+        mBufferQueue->setConsumerName(mName);
+    }
+}
+
+MediaConsumer::~MediaConsumer()
+{
+    Mutex::Autolock _l(mMutex);
+    for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+        freeBufferLocked(i);
+    }
+    mBufferQueue->consumerDisconnect();
+    mBufferQueue.clear();
+}
+
+void MediaConsumer::setName(const String8& name) {
+    Mutex::Autolock _l(mMutex);
+    mName = name;
+    mBufferQueue->setConsumerName(name);
+}
+
+status_t MediaConsumer::getNextBuffer(buffer_handle_t *buffer, nsecs_t *timestamp) {
+    status_t err;
+
+    if (!buffer) return BAD_VALUE;
+    if (mCurrentLockedBuffers == mMaxLockedBuffers) {
+        return INVALID_OPERATION;
+    }
+
+    BufferQueue::BufferItem b;
+
+    Mutex::Autolock _l(mMutex);
+
+    err = mBufferQueue->acquireBuffer(&b);
+    if (err != OK) {
+        if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
+            return BAD_VALUE;
+        } else {
+            MC_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err);
+            return err;
+        }
+    }
+
+    int buf = b.mBuf;
+
+    if (b.mGraphicBuffer != NULL) {
+        mBufferSlot[buf] = b.mGraphicBuffer;
+    }
+
+    if (b.mFence.get()) {
+        err = b.mFence->wait(Fence::TIMEOUT_NEVER);
+        if (err != OK) {
+            MC_LOGE("Failed to wait for fence of acquired buffer: %s (%d)",
+                    strerror(-err), err);
+            return err;
+        }
+    }
+
+    *buffer = mBufferSlot[buf]->handle;
+    *timestamp = b.mTimestamp;
+
+    mCurrentLockedBuffers++;
+
+    return OK;
+}
+
+status_t MediaConsumer::freeBuffer(buffer_handle_t buffer) {
+    Mutex::Autolock _l(mMutex);
+    int buf = 0;
+    status_t err;
+
+    for (; buf < BufferQueue::NUM_BUFFER_SLOTS; buf++) {
+        if (buffer == mBufferSlot[buf]->handle) break;
+    }
+    if (buf == BufferQueue::NUM_BUFFER_SLOTS) {
+        MC_LOGE("%s: Can't find buffer to free", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    err = mBufferQueue->releaseBuffer(buf, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR,
+            Fence::NO_FENCE);
+    if (err == BufferQueue::STALE_BUFFER_SLOT) {
+        freeBufferLocked(buf);
+    } else if (err != OK) {
+        MC_LOGE("%s: Unable to release graphic buffer %d to queue", __FUNCTION__,
+                buf);
+        return err;
+    }
+
+    mCurrentLockedBuffers--;
+
+    return OK;
+}
+
+void MediaConsumer::setFrameAvailableListener(
+        const sp<FrameAvailableListener>& listener) {
+    MC_LOGV("setFrameAvailableListener");
+    Mutex::Autolock lock(mMutex);
+    mFrameAvailableListener = listener;
+}
+
+
+void MediaConsumer::onFrameAvailable() {
+    MC_LOGV("onFrameAvailable");
+    sp<FrameAvailableListener> listener;
+    { // scope for the lock
+        Mutex::Autolock _l(mMutex);
+        listener = mFrameAvailableListener;
+    }
+
+    if (listener != NULL) {
+        MC_LOGV("actually calling onFrameAvailable");
+        listener->onFrameAvailable();
+    }
+}
+
+void MediaConsumer::onBuffersReleased() {
+    MC_LOGV("onBuffersReleased");
+
+    Mutex::Autolock lock(mMutex);
+
+    uint32_t mask = 0;
+    mBufferQueue->getReleasedBuffers(&mask);
+    for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+        if (mask & (1 << i)) {
+            freeBufferLocked(i);
+        }
+    }
+
+}
+
+status_t MediaConsumer::freeBufferLocked(int buf) {
+    status_t err = OK;
+
+    mBufferSlot[buf] = NULL;
+    return err;
+}
+
+} // namespace android
diff --git a/services/camera/libcameraservice/MediaConsumer.h b/services/camera/libcameraservice/MediaConsumer.h
new file mode 100644
index 0000000..3377d94
--- /dev/null
+++ b/services/camera/libcameraservice/MediaConsumer.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SERVERS_CAMERA_MEDIACONSUMER_H
+#define ANDROID_SERVERS_CAMERA_MEDIACONSUMER_H
+
+#include <gui/BufferQueue.h>
+
+#include <ui/GraphicBuffer.h>
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/threads.h>
+
+#define ANDROID_GRAPHICS_MEDIACONSUMER_JNI_ID "mMediaConsumer"
+
+namespace android {
+
+/**
+ * MediaConsumer is a BufferQueue consumer endpoint that makes it
+ * straightforward to bridge Camera 2 to the existing media recording framework.
+ * This queue is synchronous by default.
+ *
+ * TODO: This is a temporary replacement for the full camera->media recording
+ * path using SurfaceMediaEncoder or equivalent.
+ */
+
+class MediaConsumer: public virtual RefBase,
+                     protected BufferQueue::ConsumerListener
+{
+  public:
+    struct FrameAvailableListener : public virtual RefBase {
+        // onFrameAvailable() is called each time an additional frame becomes
+        // available for consumption. A new frame queued will always trigger the
+        // callback, whether the queue is empty or not.
+        //
+        // This is called without any lock held and can be called concurrently
+        // by multiple threads.
+        virtual void onFrameAvailable() = 0;
+    };
+
+    // Create a new media consumer. The maxBuffers parameter specifies
+    // how many buffers can be locked for user access at the same time.
+    MediaConsumer(uint32_t maxBuffers);
+
+    virtual ~MediaConsumer();
+
+    // set the name of the MediaConsumer that will be used to identify it in
+    // log messages.
+    void setName(const String8& name);
+
+    // Gets the next graphics buffer from the producer. Returns BAD_VALUE if no
+    // new buffer is available, and INVALID_OPERATION if the maximum number of
+    // buffers is already in use.
+    //
+    // Only a fixed number of buffers can be available at a time, determined by
+    // the construction-time maxBuffers parameter. If INVALID_OPERATION is
+    // returned by getNextBuffer, then old buffers must be returned to the
+    // queue by calling freeBuffer before more buffers can be acquired.
+    status_t getNextBuffer(buffer_handle_t *buffer, nsecs_t *timestamp);
+
+    // Returns a buffer to the queue, allowing it to be reused. Since
+    // only a fixed number of buffers may be locked at a time, old buffers must
+    // be released by calling unlockBuffer to ensure new buffers can be acquired by
+    // lockNextBuffer.
+    status_t freeBuffer(buffer_handle_t buffer);
+
+    // setFrameAvailableListener sets the listener object that will be notified
+    // when a new frame becomes available.
+    void setFrameAvailableListener(const sp<FrameAvailableListener>& listener);
+
+    sp<ISurfaceTexture> getProducerInterface() const { return mBufferQueue; }
+  protected:
+
+    // Implementation of the BufferQueue::ConsumerListener interface.  These
+    // calls are used to notify the MediaConsumer of asynchronous events in the
+    // BufferQueue.
+    virtual void onFrameAvailable();
+    virtual void onBuffersReleased();
+
+  private:
+    // Free local buffer state
+    status_t freeBufferLocked(int buf);
+
+    // Maximum number of buffers that can be locked at a time
+    uint32_t mMaxLockedBuffers;
+
+    // mName is a string used to identify the SurfaceTexture in log messages.
+    // It can be set by the setName method.
+    String8 mName;
+
+    // mFrameAvailableListener is the listener object that will be called when a
+    // new frame becomes available. If it is not NULL it will be called from
+    // queueBuffer.
+    sp<FrameAvailableListener> mFrameAvailableListener;
+
+    // Underlying buffer queue
+    sp<BufferQueue> mBufferQueue;
+
+    // Array for caching buffers from the buffer queue
+    sp<GraphicBuffer> mBufferSlot[BufferQueue::NUM_BUFFER_SLOTS];
+    // Count of currently outstanding buffers
+    uint32_t mCurrentLockedBuffers;
+
+    // mMutex is the mutex used to prevent concurrent access to the member
+    // variables of MediaConsumer objects. It must be locked whenever the
+    // member variables are accessed.
+    mutable Mutex mMutex;
+};
+
+} // namespace android
+
+#endif // ANDROID_SERVERS_CAMERA_MEDIACONSUMER_H