Code drop from //branches/cupcake/...@124589
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index 008569f..71744be 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -37,16 +37,29 @@
 
 class AudioRecord
 {
-public: 
-    
+public:
+
     enum stream_type {
         DEFAULT_INPUT   =-1,
         MIC_INPUT       = 0,
         NUM_STREAM_TYPES
     };
-    
-    static const int DEFAULT_SAMPLE_RATE = 8000; 
-    
+
+    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
+     */
+    enum event_type {
+        EVENT_MORE_DATA = 0,        // Request to reqd 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()).
+        EVENT_NEW_POS = 3,          // Record head is at a new position 
+                                    // (See setPositionUpdatePeriod()).
+    };
+
     /* Create Buffer on the stack and pass it to obtainBuffer()
      * and releaseBuffer().
      */
@@ -75,71 +88,108 @@
 
 //    static status_t setMasterMute(bool mute);
 
-    /* Returns AudioFlinger's frame count. AudioRecord's buffers will
-     * be created with this size.
-     */
-    static  size_t      frameCount();
-
     /* 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 availlable.
+     * invokes the callback when a new buffer becomes ready or an overrun condition occurs.
+     * Parameters:
+     *
+     * event:   type of event notified (see enum AudioRecord::event_type).
+     * user:    Pointer to context for use by the callback receiver.
+     * info:    Pointer to optional parameter according to event type:
+     *          - EVENT_MORE_DATA: pointer to AudioRecord::Buffer struct. The callback must not read
+     *          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.
      */
-    typedef bool (*callback_t)(void* user, const Buffer& info);
+
+    typedef void (*callback_t)(int event, void* user, void *info);
 
     /* Constructs an uninitialized AudioRecord. No connection with
      * AudioFlinger takes place.
      */
                         AudioRecord();
-                        
+
     /* Creates an AudioRecord track and registers it with AudioFlinger.
      * Once created, the track needs to be started before it can be used.
      * Unspecified values are set to the audio hardware's current
      * values.
+     *
+     * Parameters:
+     *
+     * streamType:         Select the audio input to record to (e.g. AudioRecord::MIC_INPUT).
+     * sampleRate:         Track sampling rate in Hz.
+     * format:             PCM sample format (e.g AudioSystem::PCM_16_BIT for signed
+     *                     16 bits per sample).
+     * channelCount:       Number of PCM channels (e.g 2 for stereo).
+     * frameCount:         Total size of track PCM buffer in frames. This defines the
+     *                     latency of the track.
+     * flags:              Reserved for future use.
+     * cbf:                Callback function. If not null, this function is called periodically
+     *                     to provide new PCM data.
+     * 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.
      */
-     
-                        AudioRecord(int streamType      = 0,
+
+                        AudioRecord(int streamType,
                                     uint32_t sampleRate = 0,
                                     int format          = 0,
                                     int channelCount    = 0,
-                                    int bufferCount     = 0,
+                                    int frameCount      = 0,
                                     uint32_t flags      = 0,
-                                    callback_t cbf = 0, void* user = 0);
+                                    callback_t cbf = 0,
+                                    void* user = 0,
+                                    int notificationFrames = 0);
 
 
     /* Terminates the AudioRecord and unregisters it from AudioFlinger.
      * Also destroys all resources assotiated with the AudioRecord.
-     */ 
+     */
                         ~AudioRecord();
 
 
-    /* Initialize an uninitialized AudioRecord. */
+    /* Initialize an uninitialized AudioRecord.
+     * Returned status (from utils/Errors.h) can be:
+     *  - NO_ERROR: successful intialization
+     *  - INVALID_OPERATION: AudioRecord is already intitialized or record device is already in use
+     *  - BAD_VALUE: invalid parameter (channelCount, format, sampleRate...)
+     *  - NO_INIT: audio server or audio hardware not initialized
+     *  - PERMISSION_DENIED: recording is not allowed for the requesting process
+     * */
             status_t    set(int streamType      = 0,
                             uint32_t sampleRate = 0,
                             int format          = 0,
                             int channelCount    = 0,
-                            int bufferCount     = 0,
+                            int frameCount      = 0,
                             uint32_t flags      = 0,
-                            callback_t cbf = 0, void* user = 0);
-        
+                            callback_t cbf = 0,
+                            void* user = 0,
+                            int notificationFrames = 0,
+                            bool threadCanCallJava = false);
+
 
     /* Result of constructing the AudioRecord. This must be checked
      * before using any AudioRecord API (except for set()), using
-     * an uninitialized AudioRecord prduces undefined results.
+     * an uninitialized AudioRecord produces undefined results.
+     * See set() method above for possible return codes.
      */
             status_t    initCheck() const;
 
-    /* Returns this track's latency in nanoseconds or framecount.
-     * This only includes the latency due to the fill buffer size.
-     * In particular, the hardware or driver latencies are not accounted.
+    /* Returns this track's latency in milliseconds.
+     * This includes the latency due to AudioRecord buffer size
+     * and audio hardware driver.
      */
-            nsecs_t     latency() const;
+            uint32_t     latency() const;
 
-   /* getters, see constructor */ 
-            
+   /* getters, see constructor */
+
             uint32_t    sampleRate() const;
             int         format() const;
             int         channelCount() const;
-            int         bufferCount() const;
+            uint32_t    frameCount() const;
+            int         frameSize() const;
 
 
     /* After it's created the track is not active. Call start() to
@@ -158,27 +208,79 @@
      */
             uint32_t    getSampleRate();
 
+    /* Sets marker position. When record reaches the number of frames specified,
+     * a callback with event type EVENT_MARKER is called. Calling setMarkerPosition
+     * with marker == 0 cancels marker notification callback. 
+     * If the AudioRecord has been opened with no callback function associated, 
+     * the operation will fail.
+     *
+     * Parameters:
+     *
+     * marker:   marker position expressed in frames.
+     *
+     * Returned status (from utils/Errors.h) can be:
+     *  - NO_ERROR: successful operation
+     *  - INVALID_OPERATION: the AudioRecord has no callback installed.
+     */
+            status_t    setMarkerPosition(uint32_t marker);
+            status_t    getMarkerPosition(uint32_t *marker);
+
+
+    /* Sets position update period. Every time the number of frames specified has been recorded, 
+     * a callback with event type EVENT_NEW_POS is called. 
+     * Calling setPositionUpdatePeriod with updatePeriod == 0 cancels new position notification 
+     * callback. 
+     * If the AudioRecord has been opened with no callback function associated,
+     * the operation will fail.
+     *
+     * Parameters:
+     *
+     * updatePeriod:  position update notification period expressed in frames.
+     *
+     * Returned status (from utils/Errors.h) can be:
+     *  - NO_ERROR: successful operation
+     *  - INVALID_OPERATION: the AudioRecord has no callback installed.
+     */
+            status_t    setPositionUpdatePeriod(uint32_t updatePeriod);
+            status_t    getPositionUpdatePeriod(uint32_t *updatePeriod);
+
+
+    /* Gets record head position. The position is the  total number of frames 
+     * recorded since record start. 
+     *
+     * Parameters:
+     *
+     *  position:  Address where to return record head position within AudioRecord buffer.
+     *
+     * Returned status (from utils/Errors.h) can be:
+     *  - NO_ERROR: successful operation
+     *  - BAD_VALUE:  position is NULL
+     */
+            status_t    getPosition(uint32_t *position);
+
+            
+            
     /* obtains a buffer of "frameCount" frames. The buffer must be
      * filled entirely. If the track is stopped, obtainBuffer() returns
      * STOPPED instead of NO_ERROR as long as there are buffers availlable,
      * at which point NO_MORE_BUFFERS is returned.
      * Buffers will be returned until the pool (buffercount())
-     * is exhausted, at which point obtainBuffer() will either block 
+     * is exhausted, at which point obtainBuffer() will either block
      * or return WOULD_BLOCK depending on the value of the "blocking"
-     * parameter. 
+     * parameter.
      */
-     
+
         enum {
             NO_MORE_BUFFERS = 0x80000001,
             STOPPED = 1
         };
-     
+
             status_t    obtainBuffer(Buffer* audioBuffer, bool blocking);
             void        releaseBuffer(Buffer* audioBuffer);
 
 
     /* As a convenience we provide a read() interface to the audio buffer.
-     * This is implemented on top of lockBuffer/unlockBuffer. 
+     * This is implemented on top of lockBuffer/unlockBuffer.
      */
             ssize_t     read(void* buffer, size_t size);
 
@@ -191,15 +293,16 @@
     class ClientRecordThread : public Thread
     {
     public:
-        ClientRecordThread(AudioRecord& receiver);
+        ClientRecordThread(AudioRecord& receiver, bool bCanCallJava = false);
     private:
         friend class AudioRecord;
         virtual bool        threadLoop();
         virtual status_t    readyToRun() { return NO_ERROR; }
         virtual void        onFirstRef() {}
         AudioRecord& mReceiver;
+        Mutex       mLock;
     };
-    
+
             bool processAudioBuffer(const sp<ClientRecordThread>& thread);
 
     sp<IAudioFlinger>       mAudioFlinger;
@@ -207,27 +310,26 @@
     sp<IMemory>             mCblkMemory;
     sp<ClientRecordThread>  mClientRecordThread;
     Mutex                   mRecordThreadLock;
-    
+
     uint32_t                mSampleRate;
-    size_t                  mFrameCount;
+    uint32_t                mFrameCount;
 
     audio_track_cblk_t*     mCblk;
     uint8_t                 mFormat;
-    uint8_t                 mBufferCount;
-    uint8_t                 mChannelCount   : 4;
-    uint8_t                 mReserved       : 3;
+    uint8_t                 mChannelCount;
+    uint8_t                 mReserved[2];
     status_t                mStatus;
-    nsecs_t                 mLatency;
+    uint32_t                mLatency;
 
     volatile int32_t        mActive;
 
     callback_t              mCbf;
     void*                   mUserData;
-    
-    AudioRecord::Buffer      mAudioBuffer;
-    size_t                  mPosition;
-
-    uint32_t                mReservedFBC[4];
+    uint32_t                mNotificationFrames;
+    uint32_t                mRemainingFrames;
+    uint32_t                mMarkerPosition;
+    uint32_t                mNewPosition;
+    uint32_t                mUpdatePeriod;
 };
 
 }; // namespace android
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 9fcbea5..77676bf 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -48,9 +48,10 @@
     enum audio_routes {
         ROUTE_EARPIECE       = (1 << 0),
         ROUTE_SPEAKER        = (1 << 1),
-        ROUTE_BLUETOOTH      = (1 << 2),
+        ROUTE_BLUETOOTH_SCO  = (1 << 2),
         ROUTE_HEADSET        = (1 << 3),
-        ROUTE_ALL       = (ROUTE_EARPIECE | ROUTE_SPEAKER | ROUTE_BLUETOOTH | ROUTE_HEADSET)
+        ROUTE_BLUETOOTH_A2DP = (1 << 4),
+        ROUTE_ALL       = 0xFFFFFFFF
     };
 
     /* These are static methods to control the system-wide AudioFlinger
@@ -95,6 +96,10 @@
     static float linearToLog(int volume);
     static int logToLinear(float volume);
 
+    static status_t getOutputSamplingRate(int* samplingRate);
+    static status_t getOutputFrameCount(int* frameCount);
+    static status_t getOutputLatency(uint32_t* latency);
+
     // ----------------------------------------------------------------------------
 
 private:
@@ -115,6 +120,9 @@
     static Mutex gLock;
     static sp<IAudioFlinger> gAudioFlinger;
     static audio_error_callback gAudioErrorCallback;
+    static int gOutSamplingRate;
+    static int gOutFrameCount;
+    static uint32_t gOutLatency;
 };
 
 };  // namespace android
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index a89d7ff..f382451 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -41,15 +41,16 @@
 
 class AudioTrack
 {
-public: 
+public:
 
     enum stream_type {
-        DEFAULT     =-1,
-        VOICE_CALL  = 0,
-        SYSTEM      = 1,
-        RING        = 2,
-        MUSIC       = 3,
-        ALARM       = 4,
+        DEFAULT         =-1,
+        VOICE_CALL      = 0,
+        SYSTEM          = 1,
+        RING            = 2,
+        MUSIC           = 3,
+        ALARM           = 4,
+        NOTIFICATION    = 5,
         NUM_STREAM_TYPES
     };
 
@@ -59,6 +60,17 @@
         RIGHT  = 1
     };
 
+    /* Events used by AudioTrack callback function (audio_track_cblk_t).
+     */
+    enum event_type {
+        EVENT_MORE_DATA = 0,        // Request to write more data to PCM buffer.
+        EVENT_UNDERRUN = 1,         // PCM buffer underrun occured.
+        EVENT_LOOP_END = 2,         // Sample loop end was reached; playback restarted from loop start if loop count was not 0.
+        EVENT_MARKER = 3,           // Playback head is at the specified marker position (See setMarkerPosition()).
+        EVENT_NEW_POS = 4,          // Playback head is at a new position (See setPositionUpdatePeriod()).
+        EVENT_BUFFER_END = 5        // Playback head is at the end of the buffer.
+    };
+
     /* Create Buffer on the stack and pass it to obtainBuffer()
      * and releaseBuffer().
      */
@@ -81,72 +93,132 @@
         };
     };
 
-    /* Returns AudioFlinger's frame count. AudioTrack's buffers will
-     * be created with this size.
-     */
-    static  size_t      frameCount();
 
     /* 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 availlable.
+     * invokes the callback when a new buffer becomes availlable or an underrun condition occurs.
+     * Parameters:
+     *
+     * event:   type of event notified (see enum AudioTrack::event_type).
+     * user:    Pointer to context for use by the callback receiver.
+     * info:    Pointer to optional parameter according to event type:
+     *          - EVENT_MORE_DATA: pointer to AudioTrack::Buffer struct. The callback must not write
+     *          more bytes than indicated by 'size' field and update 'size' if less bytes are
+     *          written.
+     *          - EVENT_UNDERRUN: unused.
+     *          - EVENT_LOOP_END: pointer to an int indicating the number of loops remaining.
+     *          - 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_BUFFER_END: unused.
      */
-    typedef void (*callback_t)(void* user, const Buffer& info);
+
+    typedef void (*callback_t)(int event, void* user, void *info);
 
     /* Constructs an uninitialized AudioTrack. No connection with
      * AudioFlinger takes place.
      */
                         AudioTrack();
-                        
+
     /* Creates an audio track and registers it with AudioFlinger.
      * Once created, the track needs to be started before it can be used.
      * Unspecified values are set to the audio hardware's current
      * values.
+     *
+     * Parameters:
+     *
+     * streamType:         Select the type of audio stream this track is attached to
+     *                     (e.g. AudioTrack::MUSIC).
+     * sampleRate:         Track sampling rate in Hz.
+     * format:             PCM sample format (e.g AudioSystem::PCM_16_BIT for signed
+     *                     16 bits per sample).
+     * channelCount:       Number of PCM channels (e.g 2 for stereo).
+     * frameCount:         Total size of track PCM buffer in frames. This defines the
+     *                     latency of the track.
+     * flags:              Reserved for future use.
+     * cbf:                Callback function. If not null, this function is called periodically
+     *                     to request new PCM data.
+     * notificationFrames: The callback function is called each time notificationFrames PCM
+     *                     frames have been comsumed from track input buffer.
+     * user                Context for use by the callback receiver.
      */
-     
+
+                        AudioTrack( int streamType,
+                                    uint32_t sampleRate  = 0,
+                                    int format           = 0,
+                                    int channelCount     = 0,
+                                    int frameCount       = 0,
+                                    uint32_t flags       = 0,
+                                    callback_t cbf       = 0,
+                                    void* user           = 0,
+                                    int notificationFrames = 0);
+
+    /* Creates an audio track and registers it with AudioFlinger. With this constructor,
+     * The PCM data to be rendered by AudioTrack is passed in a shared memory buffer
+     * identified by the argument sharedBuffer. This prototype is for static buffer playback.
+     * PCM data must be present into memory before the AudioTrack is started.
+     * The Write() and Flush() methods are not supported in this case.
+     * It is recommented to pass a callback function to be notified of playback end by an
+     * EVENT_UNDERRUN event.
+     */
+
                         AudioTrack( int streamType,
                                     uint32_t sampleRate = 0,
                                     int format          = 0,
                                     int channelCount    = 0,
-                                    int bufferCount     = 0,
+                                    const sp<IMemory>& sharedBuffer = 0,
                                     uint32_t flags      = 0,
-                                    callback_t cbf = 0, void* user = 0);
-
+                                    callback_t cbf      = 0,
+                                    void* user          = 0,
+                                    int notificationFrames = 0);
 
     /* Terminates the AudioTrack and unregisters it from AudioFlinger.
      * Also destroys all resources assotiated with the AudioTrack.
-     */ 
+     */
                         ~AudioTrack();
 
 
-    /* Initialize an uninitialized AudioTrack. */
+    /* Initialize an uninitialized AudioTrack.
+     * Returned status (from utils/Errors.h) can be:
+     *  - NO_ERROR: successful intialization
+     *  - INVALID_OPERATION: AudioTrack is already intitialized
+     *  - BAD_VALUE: invalid parameter (channelCount, format, sampleRate...)
+     *  - NO_INIT: audio server or audio hardware not initialized
+     * */
             status_t    set(int streamType      =-1,
                             uint32_t sampleRate = 0,
                             int format          = 0,
                             int channelCount    = 0,
-                            int bufferCount     = 0,
+                            int frameCount      = 0,
                             uint32_t flags      = 0,
-                            callback_t cbf = 0, void* user = 0);
-        
+                            callback_t cbf      = 0,
+                            void* user          = 0,
+                            int notificationFrames = 0,
+                            const sp<IMemory>& sharedBuffer = 0,
+                            bool threadCanCallJava = false);
+
 
     /* Result of constructing the AudioTrack. This must be checked
      * before using any AudioTrack API (except for set()), using
-     * an uninitialized AudoiTrack prduces undefined results.
+     * an uninitialized AudioTrack produces undefined results.
+     * See set() method above for possible return codes.
      */
             status_t    initCheck() const;
 
-    /* Returns this track's latency in nanoseconds or framecount.
-     * This only includes the latency due to the fill buffer size.
-     * In particular, the hardware or driver latencies are not accounted.
+    /* Returns this track's latency in milliseconds.
+     * This includes the latency due to AudioTrack buffer size, AudioMixer (if any)
+     * and audio hardware driver.
      */
-            nsecs_t     latency() const;
+            uint32_t     latency() const;
 
-   /* getters, see constructor */ 
-            
+    /* getters, see constructor */
+
             int         streamType() const;
             uint32_t    sampleRate() const;
             int         format() const;
             int         channelCount() const;
-            int         bufferCount() const;
+            uint32_t    frameCount() const;
+            int         frameSize() const;
+            sp<IMemory>& sharedBuffer();
 
 
     /* After it's created the track is not active. Call start() to
@@ -189,21 +261,103 @@
             void        setSampleRate(int sampleRate);
             uint32_t    getSampleRate();
 
+    /* Enables looping and sets the start and end points of looping.
+     *
+     * Parameters:
+     *
+     * loopStart:   loop start expressed as the number of PCM frames played since AudioTrack start.
+     * loopEnd:     loop end expressed as the number of PCM frames played since AudioTrack start.
+     * loopCount:   number of loops to execute. Calling setLoop() with loopCount == 0 cancels any pending or
+     *          active loop. loopCount = -1 means infinite looping.
+     *
+     * For proper operation the following condition must be respected:
+     *          (loopEnd-loopStart) <= framecount()
+     */
+            status_t    setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount);
+            status_t    getLoop(uint32_t *loopStart, uint32_t *loopEnd, int *loopCount);
+
+
+    /* Sets marker position. When playback reaches the number of frames specified, a callback with event 
+     * type EVENT_MARKER is called. Calling setMarkerPosition with marker == 0 cancels marker notification 
+     * callback. 
+     * If the AudioTrack has been opened with no callback function associated, the operation will fail.
+     *
+     * Parameters:
+     *
+     * marker:   marker position expressed in frames.
+     *
+     * Returned status (from utils/Errors.h) can be:
+     *  - NO_ERROR: successful operation
+     *  - INVALID_OPERATION: the AudioTrack has no callback installed.
+     */
+            status_t    setMarkerPosition(uint32_t marker);
+            status_t    getMarkerPosition(uint32_t *marker);
+
+
+    /* Sets position update period. Every time the number of frames specified has been played, 
+     * a callback with event type EVENT_NEW_POS is called. 
+     * Calling setPositionUpdatePeriod with updatePeriod == 0 cancels new position notification 
+     * callback. 
+     * If the AudioTrack has been opened with no callback function associated, the operation will fail.
+     *
+     * Parameters:
+     *
+     * updatePeriod:  position update notification period expressed in frames.
+     *
+     * Returned status (from utils/Errors.h) can be:
+     *  - NO_ERROR: successful operation
+     *  - INVALID_OPERATION: the AudioTrack has no callback installed.
+     */
+            status_t    setPositionUpdatePeriod(uint32_t updatePeriod);
+            status_t    getPositionUpdatePeriod(uint32_t *updatePeriod);
+
+
+    /* Sets playback head position within AudioTrack buffer. The new position is specified
+     * in number of frames. 
+     * This method must be called with the AudioTrack in paused or stopped state.
+     * Note that the actual position set is <position> modulo the AudioTrack buffer size in frames. 
+     * Therefore using this method makes sense only when playing a "static" audio buffer 
+     * as opposed to streaming.
+     * The getPosition() method on the other hand returns the total number of frames played since
+     * playback start.
+     *
+     * Parameters:
+     *
+     * position:  New playback head position within AudioTrack buffer.
+     *
+     * Returned status (from utils/Errors.h) can be:
+     *  - NO_ERROR: successful operation
+     *  - INVALID_OPERATION: the AudioTrack is not stopped.
+     *  - BAD_VALUE: The specified position is beyond the number of frames present in AudioTrack buffer 
+     */
+            status_t    setPosition(uint32_t position);
+            status_t    getPosition(uint32_t *position);
+
+    /* Forces AudioTrack buffer full condition. When playing a static buffer, this method avoids 
+     * rewriting the buffer before restarting playback after a stop.
+     * This method must be called with the AudioTrack in paused or stopped state.
+     *
+     * Returned status (from utils/Errors.h) can be:
+     *  - NO_ERROR: successful operation
+     *  - INVALID_OPERATION: the AudioTrack is not stopped.
+     */
+            status_t    reload();
+
     /* obtains a buffer of "frameCount" frames. The buffer must be
      * filled entirely. If the track is stopped, obtainBuffer() returns
      * STOPPED instead of NO_ERROR as long as there are buffers availlable,
      * at which point NO_MORE_BUFFERS is returned.
      * Buffers will be returned until the pool (buffercount())
-     * is exhausted, at which point obtainBuffer() will either block 
+     * is exhausted, at which point obtainBuffer() will either block
      * or return WOULD_BLOCK depending on the value of the "blocking"
-     * parameter. 
+     * parameter.
      */
-     
+
         enum {
             NO_MORE_BUFFERS = 0x80000001,
             STOPPED = 1
         };
-     
+
             status_t    obtainBuffer(Buffer* audioBuffer, bool blocking);
             void        releaseBuffer(Buffer* audioBuffer);
 
@@ -211,10 +365,10 @@
     /* As a convenience we provide a write() interface to the audio buffer.
      * This is implemented on top of lockBuffer/unlockBuffer. For best
      * performance
-     * 
+     *
      */
             ssize_t     write(const void* buffer, size_t size);
-            
+
     /*
      * Dumps the state of an audio track.
      */
@@ -229,7 +383,7 @@
     class AudioTrackThread : public Thread
     {
     public:
-        AudioTrackThread(AudioTrack& receiver);
+        AudioTrackThread(AudioTrack& receiver, bool bCanCallJava = false);
     private:
         friend class AudioTrack;
         virtual bool        threadLoop();
@@ -238,37 +392,37 @@
         AudioTrack& mReceiver;
         Mutex       mLock;
     };
-    
+
             bool processAudioBuffer(const sp<AudioTrackThread>& thread);
 
     sp<IAudioFlinger>       mAudioFlinger;
     sp<IAudioTrack>         mAudioTrack;
     sp<IMemory>             mCblkMemory;
     sp<AudioTrackThread>    mAudioTrackThread;
-    
+
     float                   mVolume[2];
     uint32_t                mSampleRate;
-    size_t                  mFrameCount;
+    uint32_t                mFrameCount;
 
     audio_track_cblk_t*     mCblk;
     uint8_t                 mStreamType;
     uint8_t                 mFormat;
-    uint8_t                 mBufferCount;
-    uint8_t                 mChannelCount   : 4;
-    uint8_t                 mMuted          : 1;
-    uint8_t                 mReserved       : 2;
+    uint8_t                 mChannelCount;
+    uint8_t                 mMuted;
     status_t                mStatus;
-    nsecs_t                 mLatency;
+    uint32_t                mLatency;
 
     volatile int32_t        mActive;
 
     callback_t              mCbf;
     void*                   mUserData;
-    
-    AudioTrack::Buffer      mAudioBuffer;
-    size_t                  mPosition;
-
-    uint32_t                mReservedFBC[4];
+    uint32_t                mNotificationFrames;
+    sp<IMemory>             mSharedBuffer;
+    int                     mLoopCount;
+    uint32_t                mRemainingFrames;
+    uint32_t                mMarkerPosition;
+    uint32_t                mNewPosition;
+    uint32_t                mUpdatePeriod;
 };
 
 
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index fa8e121..69703b2 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -46,8 +46,10 @@
                                 uint32_t sampleRate,
                                 int format,
                                 int channelCount,
-                                int bufferCount,
-                                uint32_t flags) = 0;
+                                int frameCount,
+                                uint32_t flags,
+                                const sp<IMemory>& sharedBuffer,
+                                status_t *status) = 0;
 
     virtual sp<IAudioRecord> openRecord(
                                 pid_t pid,
@@ -55,8 +57,9 @@
                                 uint32_t sampleRate,
                                 int format,
                                 int channelCount,
-                                int bufferCount,
-                                uint32_t flags) = 0;
+                                int frameCount,
+                                uint32_t flags,
+                                status_t *status) = 0;
 
     /* query the audio hardware state. This state never changes,
      * and therefore can be cached.
@@ -65,6 +68,7 @@
     virtual     int         channelCount() const = 0;
     virtual     int         format() const = 0;
     virtual     size_t      frameCount() const = 0;
+    virtual     uint32_t    latency() const = 0;
 
     /* set/get the audio hardware state. This will probably be used by
      * the preference panel, mostly.
diff --git a/include/media/IMediaMetadataRetriever.h b/include/media/IMediaMetadataRetriever.h
new file mode 100644
index 0000000..c677e83
--- /dev/null
+++ b/include/media/IMediaMetadataRetriever.h
@@ -0,0 +1,56 @@
+/*
+**
+** Copyright (C) 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_IMEDIAMETADATARETRIEVER_H
+#define ANDROID_IMEDIAMETADATARETRIEVER_H
+
+#include <utils/RefBase.h>
+#include <utils/IInterface.h>
+#include <utils/Parcel.h>
+#include <utils/IMemory.h>
+
+namespace android {
+
+class IMediaMetadataRetriever: public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(MediaMetadataRetriever);
+    virtual void            disconnect() = 0;
+    virtual status_t        setDataSource(const char* srcUrl) = 0;
+    virtual status_t        setDataSource(int fd, int64_t offset, int64_t length) = 0;
+    virtual status_t        setMode(int mode) = 0;
+    virtual status_t        getMode(int* mode) const = 0;
+    virtual sp<IMemory>     captureFrame() = 0;
+    virtual sp<IMemory>     extractAlbumArt() = 0;
+    virtual const char*     extractMetadata(int keyCode) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnMediaMetadataRetriever: public BnInterface<IMediaMetadataRetriever>
+{
+public:
+    virtual status_t    onTransact(uint32_t code,
+                                   const Parcel& data,
+                                   Parcel* reply,
+                                   uint32_t flags = 0);
+};
+
+}; // namespace android
+
+#endif // ANDROID_IMEDIAMETADATARETRIEVER_H
+
diff --git a/include/media/IMediaPlayer.h b/include/media/IMediaPlayer.h
index 43abf77..a683e74 100644
--- a/include/media/IMediaPlayer.h
+++ b/include/media/IMediaPlayer.h
@@ -38,7 +38,6 @@
     virtual status_t        stop() = 0;
     virtual status_t        pause() = 0;
     virtual status_t        isPlaying(bool* state) = 0;
-    virtual status_t        getVideoSize(int* w, int* h) = 0;
     virtual status_t        seekTo(int msec) = 0;
     virtual status_t        getCurrentPosition(int* msec) = 0;
     virtual status_t        getDuration(int* msec) = 0;
diff --git a/include/media/IMediaPlayerService.h b/include/media/IMediaPlayerService.h
index 63c7a00..8125cc9 100644
--- a/include/media/IMediaPlayerService.h
+++ b/include/media/IMediaPlayerService.h
@@ -23,18 +23,24 @@
 
 #include <media/IMediaPlayerClient.h>
 #include <media/IMediaPlayer.h>
+#include <media/IMediaMetadataRetriever.h>
 
 namespace android {
 
+class IMediaRecorder;
+
 class IMediaPlayerService: public IInterface
 {
 public:
     DECLARE_META_INTERFACE(MediaPlayerService);
 
+    virtual sp<IMediaRecorder>  createMediaRecorder(pid_t pid) = 0;  
+    virtual sp<IMediaMetadataRetriever> createMetadataRetriever(pid_t pid) = 0;
+
     virtual sp<IMediaPlayer>    create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url) = 0;
     virtual sp<IMediaPlayer>    create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length) = 0;
-    virtual sp<IMemory>         decode(const char* url, uint32_t *pSampleRate, int* pNumChannels) = 0;
-    virtual sp<IMemory>         decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels) = 0;
+    virtual sp<IMemory>         decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;
+    virtual sp<IMemory>         decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/media/IMediaRecorder.h b/include/media/IMediaRecorder.h
new file mode 100644
index 0000000..49e45d1
--- /dev/null
+++ b/include/media/IMediaRecorder.h
@@ -0,0 +1,67 @@
+/*
+ **
+ ** Copyright 2008, HTC Inc.
+ **
+ ** 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_IMEDIARECORDER_H
+#define ANDROID_IMEDIARECORDER_H
+
+#include <utils/IInterface.h>
+
+namespace android {
+
+class ISurface;
+class ICamera;
+
+class IMediaRecorder: public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(MediaRecorder);
+
+    virtual	status_t		setCamera(const sp<ICamera>& camera) = 0;
+    virtual	status_t		setPreviewSurface(const sp<ISurface>& surface) = 0;
+    virtual	status_t		setVideoSource(int vs) = 0;
+    virtual	status_t		setAudioSource(int as) = 0;
+    virtual	status_t		setOutputFormat(int of) = 0;
+    virtual	status_t		setVideoEncoder(int ve) = 0;
+    virtual	status_t		setAudioEncoder(int ae) = 0;
+    virtual	status_t		setOutputFile(const char* path) = 0;
+    virtual	status_t		setVideoSize(int width, int height) = 0;
+    virtual	status_t		setVideoFrameRate(int frames_per_second) = 0;
+    virtual	status_t		prepare() = 0;
+    virtual	status_t		getMaxAmplitude(int* max) = 0;
+    virtual	status_t		start() = 0;
+    virtual	status_t		stop() = 0;
+    virtual	status_t		reset() = 0;
+    virtual status_t        init() = 0;
+    virtual status_t        close() = 0;
+    virtual	status_t		release() = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnMediaRecorder: public BnInterface<IMediaRecorder>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+}; // namespace android
+
+#endif // ANDROID_IMEDIARECORDER_H
+
diff --git a/include/media/MediaMetadataRetrieverInterface.h b/include/media/MediaMetadataRetrieverInterface.h
new file mode 100644
index 0000000..b178836
--- /dev/null
+++ b/include/media/MediaMetadataRetrieverInterface.h
@@ -0,0 +1,52 @@
+/*
+**
+** Copyright (C) 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_MEDIAMETADATARETRIEVERINTERFACE_H
+#define ANDROID_MEDIAMETADATARETRIEVERINTERFACE_H
+
+#include <utils/RefBase.h>
+#include <media/mediametadataretriever.h>
+#include <private/media/VideoFrame.h>
+
+namespace android {
+
+// Abstract base class
+class MediaMetadataRetrieverBase : public RefBase
+{
+public:
+                        MediaMetadataRetrieverBase() {}
+    virtual             ~MediaMetadataRetrieverBase() {}
+    virtual status_t    setDataSource(const char *url) = 0;
+    virtual status_t    setDataSource(int fd, int64_t offset, int64_t length) = 0;
+    virtual status_t    setMode(int mode) = 0;
+    virtual status_t    getMode(int* mode) const = 0;
+    virtual VideoFrame* captureFrame() = 0;
+    virtual MediaAlbumArt* extractAlbumArt() = 0;
+    virtual const char* extractMetadata(int keyCode) = 0;
+};
+
+// MediaMetadataRetrieverInterface
+class MediaMetadataRetrieverInterface : public MediaMetadataRetrieverBase
+{
+public:
+    virtual             ~MediaMetadataRetrieverInterface() {}
+};
+
+}; // namespace android
+
+#endif // ANDROID_MEDIAMETADATARETRIEVERINTERFACE_H
+
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index 275e789..30e4578 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -26,6 +26,7 @@
 #include <utils/RefBase.h>
 
 #include <media/mediaplayer.h>
+#include <media/AudioSystem.h>
 
 namespace android {
 
@@ -36,6 +37,9 @@
 };
 
 #define DEFAULT_AUDIOSINK_BUFFERCOUNT 4
+#define DEFAULT_AUDIOSINK_BUFFERSIZE 1200
+#define DEFAULT_AUDIOSINK_SAMPLERATE 44100
+
 
 // callback mechanism for passing messages to MediaPlayer object
 typedef void (*notify_callback_f)(void* cookie, int msg, int ext1, int ext2);
@@ -57,7 +61,7 @@
         virtual ssize_t     frameSize() const = 0;
         virtual uint32_t    latency() const = 0;
         virtual float       msecsPerFrame() const = 0;
-        virtual status_t    open(uint32_t sampleRate, int channelCount, int bufferCount=DEFAULT_AUDIOSINK_BUFFERCOUNT) = 0;
+        virtual status_t    open(uint32_t sampleRate, int channelCount, int format=AudioSystem::PCM_16_BIT, int bufferCount=DEFAULT_AUDIOSINK_BUFFERCOUNT) = 0;
         virtual void        start() = 0;
         virtual ssize_t     write(const void* buffer, size_t size) = 0;
         virtual void        stop() = 0;
@@ -80,8 +84,6 @@
     virtual status_t    stop() = 0;
     virtual status_t    pause() = 0;
     virtual bool        isPlaying() = 0;
-    virtual status_t    getVideoWidth(int *w) {return 0;}
-    virtual status_t    getVideoHeight(int *h) {return 0;}
     virtual status_t    seekTo(int msec) = 0;
     virtual status_t    getCurrentPosition(int *msec) = 0;
     virtual status_t    getDuration(int *msec) = 0;
diff --git a/include/media/PVMediaRecorder.h b/include/media/PVMediaRecorder.h
new file mode 100644
index 0000000..ec497ae
--- /dev/null
+++ b/include/media/PVMediaRecorder.h
@@ -0,0 +1,60 @@
+/*
+ **
+ ** Copyright 2008, HTC Inc.
+ **
+ ** 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_PVMEDIARECORDER_H
+#define ANDROID_PVMEDIARECORDER_H
+
+#include <media/mediarecorder.h>
+
+namespace android {
+
+class ISurface;
+class ICamera;
+class AuthorDriverWrapper;
+
+class PVMediaRecorder
+{
+public:
+    PVMediaRecorder();
+    ~PVMediaRecorder();
+
+    status_t init();
+    status_t setAudioSource(audio_source as);
+    status_t setVideoSource(video_source vs);
+    status_t setOutputFormat(output_format of);
+    status_t setAudioEncoder(audio_encoder ae);
+    status_t setVideoEncoder(video_encoder ve);
+    status_t setVideoSize(int width, int height);
+    status_t setVideoFrameRate(int frames_per_second);
+    status_t setCamera(const sp<ICamera>& camera);
+    status_t setPreviewSurface(const sp<ISurface>& surface);
+    status_t setOutputFile(const char *path);
+    status_t prepare();
+    status_t start();
+    status_t stop();
+    status_t close();
+    status_t reset();
+    status_t getMaxAmplitude(int *max);
+
+private:
+    AuthorDriverWrapper*            mAuthorDriverWrapper;
+};
+
+}; // namespace android
+
+#endif // ANDROID_PVMEDIARECORDER_H
+
diff --git a/include/media/PVMetadataRetriever.h b/include/media/PVMetadataRetriever.h
new file mode 100644
index 0000000..c202dfe
--- /dev/null
+++ b/include/media/PVMetadataRetriever.h
@@ -0,0 +1,51 @@
+/*
+**
+** Copyright (C) 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_PVMETADATARETRIEVER_H
+#define ANDROID_PVMETADATARETRIEVER_H
+
+#include <utils/Errors.h>
+#include <media/MediaMetadataRetrieverInterface.h>
+#include <private/media/VideoFrame.h>
+
+namespace android {
+
+class MetadataDriver;
+
+class PVMetadataRetriever : public MediaMetadataRetrieverInterface
+{
+public:
+                        PVMetadataRetriever();
+    virtual             ~PVMetadataRetriever();
+
+    virtual status_t    setDataSource(const char *url);
+    virtual status_t    setDataSource(int fd, int64_t offset, int64_t length);
+    virtual status_t    setMode(int mode);
+    virtual status_t    getMode(int* mode) const;
+    virtual VideoFrame* captureFrame();
+    virtual MediaAlbumArt* extractAlbumArt();
+    virtual const char* extractMetadata(int keyCode);
+
+private:
+    mutable Mutex       mLock;
+    MetadataDriver*     mMetadataDriver;
+    char*               mDataSourcePath;
+};
+
+}; // namespace android
+
+#endif // ANDROID_PVMETADATARETRIEVER_H
diff --git a/include/media/PVPlayer.h b/include/media/PVPlayer.h
index 8164d8c..5f302ed 100644
--- a/include/media/PVPlayer.h
+++ b/include/media/PVPlayer.h
@@ -41,8 +41,6 @@
     virtual status_t    stop();
     virtual status_t    pause();
     virtual bool        isPlaying();
-    virtual status_t    getVideoWidth(int *w);
-    virtual status_t    getVideoHeight(int *h);
     virtual status_t    seekTo(int msec);
     virtual status_t    getCurrentPosition(int *msec);
     virtual status_t    getDuration(int *msec);
@@ -54,11 +52,11 @@
             void        sendEvent(int msg, int ext1=0, int ext2=0) { MediaPlayerBase::sendEvent(msg, ext1, ext2); }
 
 private:
-    static void         do_nothing(status_t s, void *cookie) { }
-    static void         run_init(status_t s, void *cookie);
-    static void         run_set_video_surface(status_t s, void *cookie);
-    static void         run_set_audio_output(status_t s, void *cookie);
-    static void         run_prepare(status_t s, void *cookie);
+    static void         do_nothing(status_t s, void *cookie, bool cancelled) { }
+    static void         run_init(status_t s, void *cookie, bool cancelled);
+    static void         run_set_video_surface(status_t s, void *cookie, bool cancelled);
+    static void         run_set_audio_output(status_t s, void *cookie, bool cancelled);
+    static void         run_prepare(status_t s, void *cookie, bool cancelled);
 
     PlayerDriver*               mPlayerDriver;
     char *                      mDataSourcePath;
diff --git a/include/media/ToneGenerator.h b/include/media/ToneGenerator.h
index bc27d35..da1489f 100644
--- a/include/media/ToneGenerator.h
+++ b/include/media/ToneGenerator.h
@@ -85,7 +85,7 @@
         TONE_RESTARTING  //
     };
 
-    static const unsigned int NUM_PCM_BUFFERS = 2; // number of pcm buffers of audio track
+    static const unsigned int NUM_PCM_BUFFERS = 2; // Number of AudioTrack pcm buffers
     
     static const unsigned int TONEGEN_MAX_WAVES = 3;
     static const unsigned int TONEGEN_MAX_SEGMENTS = 4;  // Maximun number of elenemts in
@@ -126,14 +126,17 @@
     const ToneDescriptor *mpToneDesc;  // pointer to active tone descriptor
     const ToneDescriptor *mpNewToneDesc;  // pointer to next active tone descriptor
 
-    unsigned int mSamplingRate;  // Sampling rate
+    int mSamplingRate;  // AudioFlinger Sampling rate
+    int mBufferSize;  // PCM buffer size in frames
     AudioTrack *mpAudioTrack;  // Pointer to audio track used for playback
     Mutex mLock;  // Mutex to control concurent access to ToneGenerator object from audio callback and application API
     Mutex mCbkCondLock; // Mutex associated to mWaitCbkCond
     Condition mWaitCbkCond; // condition enabling interface to wait for audio callback completion after a change is requested
     float mVolume;  // Volume applied to audio track
+    int mStreamType; // Audio stream used for output
 
-    static void audioCallback(void* user, const AudioTrack::Buffer& info);
+    bool initAudioTrack();
+    static void audioCallback(int event, void* user, void *info);
     bool prepareWave();
     unsigned int numWaves();
     void clearWaveGens();
diff --git a/include/media/mediametadataretriever.h b/include/media/mediametadataretriever.h
index 586dda1c..05cba30 100644
--- a/include/media/mediametadataretriever.h
+++ b/include/media/mediametadataretriever.h
@@ -18,10 +18,16 @@
 #ifndef MEDIAMETADATARETRIEVER_H
 #define MEDIAMETADATARETRIEVER_H
 
-#include <graphics/SkBitmap.h>      // for SkBitmap
+#include <utils/Errors.h>  // for status_t
+#include <utils/threads.h>
+#include <utils/IMemory.h>
+#include <media/IMediaMetadataRetriever.h>
 
 namespace android {
 
+class IMediaPlayerService;
+class IMediaMetadataRetriever;
+
 // Keep these in synch with the constants defined in MediaMetadataRetriever.java
 // class.
 enum {
@@ -38,62 +44,45 @@
     METADATA_KEY_NUM_TRACKS      = 10,
     METADATA_KEY_IS_DRM_CRIPPLED = 11,
     METADATA_KEY_CODEC           = 12,
+    METADATA_KEY_RATING          = 13,
+    METADATA_KEY_COMMENT         = 14,
+    METADATA_KEY_COPYRIGHT       = 15,
     // Add more here...
 };
 
-// A utility class that holds the size and actual data in album art.
-class MediaAlbumArt {
-public:
-    MediaAlbumArt(): length(0), data(NULL) {}
-    MediaAlbumArt(const MediaAlbumArt& copy) { 
-        // Don't be caught by uninitialized variables!!
-        length = 0; 
-        data = NULL; 
-        setData(copy.length, copy.data);
-    }
-    MediaAlbumArt(const char* url);
-    ~MediaAlbumArt() { clearData(); }
 
-    void clearData();
-    status_t setData(unsigned int len, const char* buf);
-    char *getData() const { return copyData(length, data); }
-    unsigned int getLength() const { return length; }
-    
-private:
-    // Disable copy assignment operator!
-    MediaAlbumArt& operator=(const MediaAlbumArt& rhs);
-    static char* copyData(unsigned int len, const char* buf);
-    
-    unsigned int length;    // Number of bytes in data.
-    char *data;             // Actual binary data.
-};
-
-class MediaMetadataRetrieverImpl
+class MediaMetadataRetriever: public RefBase
 {
 public:
-    virtual ~MediaMetadataRetrieverImpl() {};
-    virtual status_t setDataSource(const char* dataSourceUrl) = 0;
-    virtual SkBitmap *captureFrame() = 0;
-    virtual const char* extractMetadata(int keyCode) = 0;
-    virtual MediaAlbumArt* extractAlbumArt() = 0;
-    virtual void setMode(int mode) = 0;
-};
-
-class MediaMetadataRetriever
-{
-public:
-    static status_t setDataSource(const char* dataSourceUrl);
-    static SkBitmap *captureFrame();
-    static const char* extractMetadata(int keyCode);
-    static MediaAlbumArt* extractAlbumArt();
-    static void setMode(int mode);
-    static void release();
-    static void create();
+    MediaMetadataRetriever();
+    ~MediaMetadataRetriever();
+    void disconnect();
+    status_t setDataSource(const char* dataSourceUrl);
+    status_t setDataSource(int fd, int64_t offset, int64_t length);
+    status_t setMode(int mode);
+    status_t getMode(int* mode);
+    sp<IMemory> captureFrame();
+    sp<IMemory> extractAlbumArt();
+    const char* extractMetadata(int keyCode);
 
 private:
-    MediaMetadataRetriever() {}
-    static MediaMetadataRetrieverImpl *mRetriever;
-    static void                       *mLibHandler;
+    static const sp<IMediaPlayerService>& getService();
+
+    class DeathNotifier: public IBinder::DeathRecipient
+    {
+    public:
+        DeathNotifier() {}
+        virtual ~DeathNotifier();
+        virtual void binderDied(const wp<IBinder>& who);
+    };
+
+    static sp<DeathNotifier>                  sDeathNotifier;
+    static Mutex                              sServiceLock;
+    static sp<IMediaPlayerService>            sService;
+
+    Mutex                                     mLock;
+    sp<IMediaMetadataRetriever>               mRetriever;
+
 };
 
 }; // namespace android
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index aadfc32..7288445 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -17,11 +17,12 @@
 #ifndef ANDROID_MEDIAPLAYER_H
 #define ANDROID_MEDIAPLAYER_H
 
+#include <utils/IMemory.h>
 #include <ui/Surface.h>
-#include <media/AudioTrack.h>
 #include <media/IMediaPlayerClient.h>
 #include <media/IMediaPlayer.h>
 #include <media/IMediaPlayerService.h>
+#include <utils/SortedVector.h>
 
 namespace android {
 
@@ -31,6 +32,7 @@
     MEDIA_PLAYBACK_COMPLETE = 2,
     MEDIA_BUFFERING_UPDATE  = 3,
     MEDIA_SEEK_COMPLETE     = 4,
+    MEDIA_SET_VIDEO_SIZE    = 5,
     MEDIA_ERROR             = 100,
 };
 
@@ -52,18 +54,18 @@
 
 // ----------------------------------------------------------------------------
 // ref-counted object for callbacks
-class MediaPlayerListener: public RefBase
+class MediaPlayerListener: virtual public RefBase
 {
 public:
     virtual void notify(int msg, int ext1, int ext2) = 0;
 };
 
-class MediaPlayer : public BnMediaPlayerClient, public IBinder::DeathRecipient
+class MediaPlayer : public BnMediaPlayerClient
 {
 public:
     MediaPlayer();
     ~MediaPlayer();
-
+            void            onFirstRef();
             void            disconnect();
             status_t        setDataSource(const char *url);
             status_t        setDataSource(int fd, int64_t offset, int64_t length);
@@ -83,10 +85,11 @@
             status_t        reset();
             status_t        setAudioStreamType(int type);
             status_t        setLooping(int loop);
+            bool            isLooping();
             status_t        setVolume(float leftVolume, float rightVolume);
             void            notify(int msg, int ext1, int ext2);
-    static  sp<IMemory>     decode(const char* url, uint32_t *pSampleRate, int* pNumChannels);
-    static  sp<IMemory>     decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels);
+    static  sp<IMemory>     decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
+    static  sp<IMemory>     decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
 
 private:
             void            clear_l();
@@ -96,7 +99,8 @@
             status_t        setDataSource(const sp<IMediaPlayer>& player);
 
     static const sp<IMediaPlayerService>& getMediaPlayerService();
-    virtual void binderDied(const wp<IBinder>& who);
+    static void addObitRecipient(const wp<MediaPlayer>& recipient);
+    static void removeObitRecipient(const wp<MediaPlayer>& recipient);
 
     class DeathNotifier: public IBinder::DeathRecipient
     {
@@ -107,8 +111,6 @@
         virtual void binderDied(const wp<IBinder>& who);
     };
 
-    static sp<DeathNotifier> mDeathNotifier;
-
     sp<IMediaPlayer>            mPlayer;
     Mutex                       mLock;
     Mutex                       mNotifyLock;
@@ -125,11 +127,15 @@
     bool                        mLoop;
     float                       mLeftVolume;
     float                       mRightVolume;
+    int                         mVideoWidth;
+    int                         mVideoHeight;
 
     friend class DeathNotifier;
 
-    static  Mutex               mServiceLock;
-    static  sp<IMediaPlayerService>    mMediaPlayerService;
+    static  Mutex                           sServiceLock;
+    static  sp<IMediaPlayerService>         sMediaPlayerService;
+    static  sp<DeathNotifier>               sDeathNotifier;
+    static  SortedVector< wp<MediaPlayer> > sObitRecipients;
 };
 
 }; // namespace android
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h
index f247424..a901d32 100644
--- a/include/media/mediarecorder.h
+++ b/include/media/mediarecorder.h
@@ -1,28 +1,30 @@
 /*
- * Copyright (C) 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.
+ ** Copyright (C) 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 MEDIARECORDER_H
-#define MEDIARECORDER_H
+#ifndef ANDROID_MEDIARECORDER_H
+#define ANDROID_MEDIARECORDER_H
 
 #include <utils.h>
-#include <ui/SurfaceComposerClient.h>
 
 namespace android {
 
-class AuthorDriverWrapper;
+class Surface;
+class IMediaRecorder;
+class ICamera;
 
 typedef void (*media_completion_f)(status_t status, void *cookie);
 
@@ -31,7 +33,7 @@
  */
 enum audio_source {
     AUDIO_SOURCE_DEFAULT = 0,
-    AUDIO_SOURCE_MIC = 1, 
+    AUDIO_SOURCE_MIC = 1,
 };
 
 enum video_source {
@@ -39,10 +41,13 @@
     VIDEO_SOURCE_CAMERA = 1,
 };
 
+//Please update java/android/android/media/MediaRecorder.java if the following is updated.
 enum output_format {
     OUTPUT_FORMAT_DEFAULT = 0,
-    OUTPUT_FORMAT_THREE_GPP = 1,
-    OUTPUT_FORMAT_MPEG_4 = 2,
+    OUTPUT_FORMAT_THREE_GPP,
+    OUTPUT_FORMAT_MPEG_4,
+    OUTPUT_FORMAT_RAW_AMR,
+    OUTPUT_FORMAT_LIST_END // must be last - used to validate format type
 };
 
 enum audio_encoder {
@@ -57,26 +62,29 @@
     VIDEO_ENCODER_MPEG_4_SP = 3,
 };
 
+// Maximum frames per second is 24
+#define MEDIA_RECORDER_MAX_FRAME_RATE         24
+
 /*
  * The state machine of the media_recorder uses a set of different state names.
  * The mapping between the media_recorder and the pvauthorengine is shown below:
- * 
+ *
  *    mediarecorder                        pvauthorengine
  * ----------------------------------------------------------------
  *    MEDIA_RECORDER_ERROR                 ERROR
  *    MEDIA_RECORDER_IDLE                  IDLE
  *    MEDIA_RECORDER_INITIALIZED           OPENED
- *    MEDIA_RECORDER_PREPARING
+ *    MEDIA_RECORDER_DATASOURCE_CONFIGURED
  *    MEDIA_RECORDER_PREPARED              INITIALIZED
  *    MEDIA_RECORDER_RECORDING             RECORDING
  */
 enum media_recorder_states {
-    MEDIA_RECORDER_ERROR =         0,
-    MEDIA_RECORDER_IDLE =          1 << 0,
-    MEDIA_RECORDER_INITIALIZED =   1 << 1,
-    MEDIA_RECORDER_PREPARING =     1 << 2,
-    MEDIA_RECORDER_PREPARED =      1 << 3,
-    MEDIA_RECORDER_RECORDING =     1 << 4,
+    MEDIA_RECORDER_ERROR                 =      0,
+    MEDIA_RECORDER_IDLE                  = 1 << 0,
+    MEDIA_RECORDER_INITIALIZED           = 1 << 1,
+    MEDIA_RECORDER_DATASOURCE_CONFIGURED = 1 << 2,
+    MEDIA_RECORDER_PREPARED              = 1 << 3,
+    MEDIA_RECORDER_RECORDING             = 1 << 4,
 };
 
 class MediaRecorder
@@ -85,36 +93,39 @@
     MediaRecorder();
     ~MediaRecorder();
 
-    status_t init();
-
-    status_t setAudioSource(audio_source as);
-    status_t setVideoSource(video_source vs);
-    status_t setOutputFormat(output_format of);
-    status_t setAudioEncoder(audio_encoder ae);
-    status_t setVideoEncoder(video_encoder ve);
-    status_t setVideoSize(int width, int height);
-    status_t setVideoFrameRate(int frames_per_second);
-    status_t setPreviewSurface(const sp<Surface>& surface);
-
-    status_t setOutputFile(const char *path);
-    // XXX metadata setup
-
-    status_t prepare();
-    status_t start();
-    status_t stop();
-    status_t reset();
-    status_t getIfOutputFormatSpecified();
-
-    status_t getMaxAmplitude(int *max);
+    status_t    initCheck();
+    status_t    setCamera(const sp<ICamera>& camera);
+    status_t    setPreviewSurface(const sp<Surface>& surface);
+    status_t    setVideoSource(int vs);
+    status_t    setAudioSource(int as);
+    status_t    setOutputFormat(int of);
+    status_t    setVideoEncoder(int ve);
+    status_t    setAudioEncoder(int ae);
+    status_t    setOutputFile(const char* path);
+    status_t    setVideoSize(int width, int height);
+    status_t    setVideoFrameRate(int frames_per_second);
+    status_t    prepare();
+    status_t    getMaxAmplitude(int* max);
+    status_t    start();
+    status_t    stop();
+    status_t    reset();
+    status_t    init();
+    status_t    close();
+    status_t    release();
 
 private:
-    AuthorDriverWrapper            *mAuthorDriverWrapper;
-    bool                           mOutputFormatSpecified;
-    media_recorder_states          mCurrentState;
+    void                    doCleanUp();
+    status_t                doReset();
 
+    sp<IMediaRecorder>      mMediaRecorder;
+    media_recorder_states   mCurrentState;
+    bool                    mIsAudioSourceSet;
+    bool                    mIsVideoSourceSet;
+    bool                    mIsAudioEncoderSet;
+    bool                    mIsVideoEncoderSet;
+    bool                    mIsOutputFileSet;
 };
 
-}; // namespace android
+};  // namespace android
 
-#endif // MEDIAPLAYER_H
-
+#endif // ANDROID_MEDIARECORDER_H
diff --git a/include/media/mediascanner.h b/include/media/mediascanner.h
index 5d0122d..fbef1db 100644
--- a/include/media/mediascanner.h
+++ b/include/media/mediascanner.h
@@ -23,6 +23,7 @@
 namespace android {
 
 class MediaScannerClient;
+class StringArray;
 
 class MediaScanner 
 {
@@ -35,6 +36,7 @@
     status_t processFile(const char *path, const char *mimeType, MediaScannerClient& client);
     status_t processDirectory(const char *path, const char* extensions, 
             MediaScannerClient& client, ExceptionCheck exceptionCheck, void* exceptionEnv);
+    void setLocale(const char* locale);
     
     // extracts album art as a block of data
     char* extractAlbumArt(int fd);
@@ -45,16 +47,36 @@
     status_t doProcessDirectory(char *path, int pathRemaining, const char* extensions, 
             MediaScannerClient& client, ExceptionCheck exceptionCheck, void* exceptionEnv);
     void initializeForThread();
+    
+    // current locale (like "ja_JP"), created/destroyed with strdup()/free()
+    char* mLocale;
 };
 
 
 class MediaScannerClient
 {
 public:
-	virtual ~MediaScannerClient() {}
+	MediaScannerClient();
+	virtual ~MediaScannerClient();
+	void setLocale(const char* locale);
+	void beginFile();
+	bool addStringTag(const char* name, const char* value);
+	void endFile();
+	
 	virtual bool scanFile(const char* path, long long lastModified, long long fileSize) = 0;
 	virtual bool handleStringTag(const char* name, const char* value) = 0;
 	virtual bool setMimeType(const char* mimeType) = 0;
+
+protected:
+    void convertValues(uint32_t encoding);
+
+protected:
+    // cached name and value strings, for native encoding support.
+    StringArray*    mNames;
+    StringArray*    mValues;
+    
+    // default encoding based on MediaScanner::mLocale string
+    uint32_t        mLocaleEncoding;
 };
 
 }; // namespace android
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index 1878f3c..72ed281 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -31,29 +31,41 @@
 
 struct audio_track_cblk_t
 {
-    enum {
-        SEQUENCE_MASK   = 0xFFFFFF00,
-        BUFFER_MASK     = 0x000000FF
-    };
 
+    // The data members are grouped so that members accessed frequently and in the same context
+    // are in the same line of data cache.
                 Mutex       lock;
                 Condition   cv;
     volatile    uint32_t    user;
     volatile    uint32_t    server;
+                uint32_t    userBase;
+                uint32_t    serverBase;
+    void*       buffers;
+    uint32_t    frameCount;
+    // Cache line boundary
+    uint32_t    loopStart;
+    uint32_t    loopEnd;
+    int         loopCount;
     volatile    union {
                     uint16_t    volume[2];
                     uint32_t    volumeLR;
                 };
                 uint16_t    sampleRate;
-                uint16_t    reserved;
-
-                void*       buffers;
-                size_t      size;
-            
+                uint16_t    channels;
+                int16_t     flowControlFlag; // underrun (out) or overrrun (in) indication
+                uint8_t     out;        // out equals 1 for AudioTrack and 0 for AudioRecord
+                uint8_t     forceReady; 
+                // Padding ensuring that data buffer starts on a cache line boundary (32 bytes). 
+                // See AudioFlinger::TrackBase constructor
+                int32_t     Padding[4];
+                
                             audio_track_cblk_t();
-                uint32_t    stepUser(int bufferCount);
-                bool        stepServer(int bufferCount);
-                void*       buffer(int id) const;
+                uint32_t    stepUser(uint32_t frameCount);
+                bool        stepServer(uint32_t frameCount);
+                void*       buffer(uint32_t offset) const;
+                uint32_t    framesAvailable();
+                uint32_t    framesAvailable_l();
+                uint32_t    framesReady();
 };
 
 
diff --git a/include/private/media/VideoFrame.h b/include/private/media/VideoFrame.h
new file mode 100644
index 0000000..9c35274
--- /dev/null
+++ b/include/private/media/VideoFrame.h
@@ -0,0 +1,127 @@
+/*
+**
+** Copyright (C) 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_VIDEO_FRAME_H
+#define ANDROID_VIDEO_FRAME_H
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <utils/Log.h>
+
+namespace android {
+
+// A simple buffer to hold binary data
+class MediaAlbumArt 
+{
+public:
+    MediaAlbumArt(): mSize(0), mData(0) {}
+
+    explicit MediaAlbumArt(const char* url) {
+        mSize = 0;
+        mData = NULL;
+        FILE *in = fopen(url, "r");
+        if (!in) {
+            return;
+        }
+        fseek(in, 0, SEEK_END);
+        mSize = ftell(in);  // Allocating buffer of size equals to the external file size.
+        if (mSize == 0 || (mData = new uint8_t[mSize]) == NULL) {
+            fclose(in);
+            if (mSize != 0) {
+                mSize = 0;
+            }
+            return;
+        }
+        rewind(in);
+        if (fread(mData, 1, mSize, in) != mSize) {  // Read failed.
+            delete[] mData;
+            mData = NULL;
+            mSize = 0;
+            return;
+        }
+        fclose(in);
+    }
+
+    MediaAlbumArt(const MediaAlbumArt& copy) { 
+        mSize = copy.mSize; 
+        mData = NULL;  // initialize it first 
+        if (mSize > 0 && copy.mData != NULL) {
+           mData = new uint8_t[copy.mSize];
+           if (mData != NULL) {
+               memcpy(mData, copy.mData, mSize);
+           } else {
+               mSize = 0;
+           }
+        }
+    }
+
+    ~MediaAlbumArt() {
+        if (mData != 0) {
+            delete[] mData;
+        }
+    }
+
+    // Intentional public access modifier:
+    // We have to know the internal structure in order to share it between
+    // processes?
+    uint32_t mSize;            // Number of bytes in mData
+    uint8_t* mData;            // Actual binary data
+};
+
+// Represents a color converted (RGB-based) video frame
+// with bitmap pixels stored in FrameBuffer
+class VideoFrame
+{
+public:
+    VideoFrame(): mWidth(0), mHeight(0), mDisplayWidth(0), mDisplayHeight(0), mSize(0), mData(0) {}
+ 
+    VideoFrame(const VideoFrame& copy) {
+        mWidth = copy.mWidth;
+        mHeight = copy.mHeight;
+        mDisplayWidth = copy.mDisplayWidth;
+        mDisplayHeight = copy.mDisplayHeight;
+        mSize = copy.mSize;
+        mData = NULL;  // initialize it first
+        if (mSize > 0 && copy.mData != NULL) {
+            mData = new uint8_t[mSize];
+            if (mData != NULL) {
+                memcpy(mData, copy.mData, mSize);
+            } else {
+                mSize = 0;
+            }
+        }
+    }
+
+    ~VideoFrame() {
+        if (mData != 0) {
+            delete[] mData;
+        }
+    }
+
+    // Intentional public access modifier:
+    uint32_t mWidth;
+    uint32_t mHeight;
+    uint32_t mDisplayWidth;
+    uint32_t mDisplayHeight;
+    uint32_t mSize;            // Number of bytes in mData
+    uint8_t* mData;            // Actual binary data
+};
+
+}; // namespace android
+
+#endif // ANDROID_VIDEO_FRAME_H
diff --git a/include/private/opengles/gl_context.h b/include/private/opengles/gl_context.h
index 67d50fd..2aa78d8 100644
--- a/include/private/opengles/gl_context.h
+++ b/include/private/opengles/gl_context.h
@@ -532,6 +532,10 @@
             vertex_t const* v1,
             vertex_t const* v2);
 
+    void initLine(
+            vertex_t const* v0,
+            vertex_t const* v1);
+
     inline void initLerp(vertex_t const* v0, uint32_t enables);
 
     int iteratorsScale(int32_t it[3],
@@ -543,6 +547,9 @@
     void iterators0032(int32_t it[3],
             int32_t c0, int32_t c1, int32_t c2) const;
 
+    void iterators0032(int64_t it[3],
+            int32_t c0, int32_t c1, int32_t c2) const;
+
     GGLcoord area() const { return m_area; }
 
 private:
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index cfa837a..650684a 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -12,6 +12,9 @@
 	IMediaPlayerService.cpp \
 	IMediaPlayerClient.cpp \
 	IMediaPlayer.cpp \
+	IMediaRecorder.cpp \
+	mediarecorder.cpp \
+	IMediaMetadataRetriever.cpp \
 	mediametadataretriever.cpp \
 	ToneGenerator.cpp
 
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index f3e4123..bbb9548 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -2,19 +2,20 @@
 **
 ** 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 
+** 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 
+**     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 
+** 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 "AudioRecord"
 
 #include <stdint.h>
@@ -53,24 +54,26 @@
         uint32_t sampleRate,
         int format,
         int channelCount,
-        int bufferCount,
+        int frameCount,
         uint32_t flags,
-        callback_t cbf, void* user)
+        callback_t cbf,
+        void* user,
+        int notificationFrames)
     : mStatus(NO_INIT)
 {
     mStatus = set(streamType, sampleRate, format, channelCount,
-            bufferCount, flags, cbf, user);
+            frameCount, flags, cbf, user, notificationFrames);
 }
 
 AudioRecord::~AudioRecord()
 {
     if (mStatus == NO_ERROR) {
-        if (mPosition) {
-            releaseBuffer(&mAudioBuffer);
-        }
-        // obtainBuffer() will give up with an error
-        mAudioRecord->stop();
+        // Make sure that callback function exits in the case where
+        // it is looping on buffer empty condition in obtainBuffer().
+        // Otherwise the callback thread will never exit.
+        stop();
         if (mClientRecordThread != 0) {
+            mCblk->cv.signal();
             mClientRecordThread->requestExitAndWait();
             mClientRecordThread.clear();
         }
@@ -84,11 +87,15 @@
         uint32_t sampleRate,
         int format,
         int channelCount,
-        int bufferCount,
+        int frameCount,
         uint32_t flags,
-        callback_t cbf, void* user)
+        callback_t cbf,
+        void* user,
+        int notificationFrames,
+        bool threadCanCallJava)
 {
 
+    LOGV("set(): sampleRate %d, channelCount %d, frameCount %d",sampleRate, channelCount, frameCount);
     if (mAudioFlinger != 0) {
         return INVALID_OPERATION;
     }
@@ -112,11 +119,6 @@
     if (channelCount == 0) {
         channelCount = 1;
     }
-    if (bufferCount == 0) {
-        bufferCount = 2;
-    } else if (bufferCount < 2) {
-        return BAD_VALUE;
-    }
 
     // validate parameters
     if (format != AudioSystem::PCM_16_BIT) {
@@ -125,22 +127,34 @@
     if (channelCount != 1 && channelCount != 2) {
         return BAD_VALUE;
     }
-    if (bufferCount < 2) {
+
+    // TODO: Get input frame count from hardware.
+    int minFrameCount = 1024*2;
+
+    if (frameCount == 0) {
+        frameCount = minFrameCount;
+    } else if (frameCount < minFrameCount) {
         return BAD_VALUE;
     }
 
+    if (notificationFrames == 0) {
+        notificationFrames = frameCount/2;
+    }
+
     // open record channel
+    status_t status;
     sp<IAudioRecord> record = audioFlinger->openRecord(getpid(), streamType,
-            sampleRate, format, channelCount, bufferCount, flags);
+            sampleRate, format, channelCount, frameCount, flags, &status);
     if (record == 0) {
-        return NO_INIT;
+        LOGE("AudioFlinger could not create record track, status: %d", status);
+        return status;
     }
     sp<IMemory> cblk = record->getCblk();
     if (cblk == 0) {
         return NO_INIT;
     }
     if (cbf != 0) {
-        mClientRecordThread = new ClientRecordThread(*this);
+        mClientRecordThread = new ClientRecordThread(*this, threadCanCallJava);
         if (mClientRecordThread == 0) {
             return NO_INIT;
         }
@@ -153,16 +167,23 @@
     mCblkMemory = cblk;
     mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
     mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
+    mCblk->out = 0;
     mSampleRate = sampleRate;
-    mFrameCount = audioFlinger->frameCount();
     mFormat = format;
-    mBufferCount = bufferCount;
+    // Update buffer size in case it has been limited by AudioFlinger during track creation
+    mFrameCount = mCblk->frameCount;
     mChannelCount = channelCount;
     mActive = 0;
     mCbf = cbf;
+    mNotificationFrames = notificationFrames;
+    mRemainingFrames = notificationFrames;
     mUserData = user;
-    mLatency = seconds(mFrameCount) / mSampleRate;
-    mPosition = 0;
+    // TODO: add audio hardware input latency here
+    mLatency = (1000*mFrameCount) / mSampleRate;
+    mMarkerPosition = 0;
+    mNewPosition = 0;
+    mUpdatePeriod = 0;
+
     return NO_ERROR;
 }
 
@@ -173,7 +194,7 @@
 
 // -------------------------------------------------------------------------
 
-nsecs_t AudioRecord::latency() const
+uint32_t AudioRecord::latency() const
 {
     return mLatency;
 }
@@ -193,9 +214,14 @@
     return mChannelCount;
 }
 
-int AudioRecord::bufferCount() const
+uint32_t AudioRecord::frameCount() const
 {
-    return mBufferCount;
+    return mFrameCount;
+}
+
+int AudioRecord::frameSize() const
+{
+    return channelCount()*((format() == AudioSystem::PCM_8_BIT) ? sizeof(uint8_t) : sizeof(int16_t));
 }
 
 // -------------------------------------------------------------------------
@@ -203,54 +229,60 @@
 status_t AudioRecord::start()
 {
     status_t ret = NO_ERROR;
-    
-    // If using record thread, protect start sequence to make sure that
-    // no stop command is processed before the thread is started
-    if (mClientRecordThread != 0) {
-        mRecordThreadLock.lock();        
-    }
+    sp<ClientRecordThread> t = mClientRecordThread;
 
-    if (android_atomic_or(1, &mActive) == 0) {
-        setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT);
-        ret = mAudioRecord->start();
-        if (ret == NO_ERROR) {
-            if (mClientRecordThread != 0) {
-                mClientRecordThread->run("ClientRecordThread", THREAD_PRIORITY_AUDIO_CLIENT);
+    LOGV("start");
+
+    if (t != 0) {
+        if (t->exitPending()) {
+            if (t->requestExitAndWait() == WOULD_BLOCK) {
+                LOGE("AudioRecord::start called from thread");
+                return WOULD_BLOCK;
             }
         }
+        t->mLock.lock();
+     }
+
+    if (android_atomic_or(1, &mActive) == 0) {
+        mNewPosition = mCblk->user + mUpdatePeriod;
+        if (t != 0) {
+           t->run("ClientRecordThread", THREAD_PRIORITY_AUDIO_CLIENT);
+        } else {
+            setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT);
+        }
+        ret = mAudioRecord->start();
     }
-    
-    if (mClientRecordThread != 0) {
-        mRecordThreadLock.unlock();        
+
+    if (t != 0) {
+        t->mLock.unlock();
     }
-    
+
     return ret;
 }
 
 status_t AudioRecord::stop()
 {
-    // If using record thread, protect stop sequence to make sure that
-    // no start command is processed before requestExit() is called
-    if (mClientRecordThread != 0) {
-        mRecordThreadLock.lock();        
-    }
+    sp<ClientRecordThread> t = mClientRecordThread;
+
+    LOGV("stop");
+
+    if (t != 0) {
+        t->mLock.lock();
+     }
 
     if (android_atomic_and(~1, &mActive) == 1) {
-        if (mPosition) {
-            mPosition = 0;
-            releaseBuffer(&mAudioBuffer);
-        }
         mAudioRecord->stop();
-        setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL);
-        if (mClientRecordThread != 0) {
-            mClientRecordThread->requestExit();
+        if (t != 0) {
+            t->requestExit();
+        } else {
+            setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL);
         }
     }
-    
-    if (mClientRecordThread != 0) {
-        mRecordThreadLock.unlock();        
+
+    if (t != 0) {
+        t->mLock.unlock();
     }
-    
+
     return NO_ERROR;
 }
 
@@ -259,22 +291,74 @@
     return !mActive;
 }
 
+status_t AudioRecord::setMarkerPosition(uint32_t marker)
+{
+    if (mCbf == 0) return INVALID_OPERATION;
+
+    mMarkerPosition = marker;
+
+    return NO_ERROR;
+}
+
+status_t AudioRecord::getMarkerPosition(uint32_t *marker)
+{
+    if (marker == 0) return BAD_VALUE;
+
+    *marker = mMarkerPosition;
+
+    return NO_ERROR;
+}
+
+status_t AudioRecord::setPositionUpdatePeriod(uint32_t updatePeriod)
+{
+    if (mCbf == 0) return INVALID_OPERATION;
+
+    uint32_t curPosition;
+    getPosition(&curPosition);
+    mNewPosition = curPosition + updatePeriod;
+    mUpdatePeriod = updatePeriod;
+
+    return NO_ERROR;
+}
+
+status_t AudioRecord::getPositionUpdatePeriod(uint32_t *updatePeriod)
+{
+    if (updatePeriod == 0) return BAD_VALUE;
+
+    *updatePeriod = mUpdatePeriod;
+
+    return NO_ERROR;
+}
+
+status_t AudioRecord::getPosition(uint32_t *position)
+{
+    if (position == 0) return BAD_VALUE;
+
+    *position = mCblk->user;
+
+    return NO_ERROR;
+}
+
+
 // -------------------------------------------------------------------------
 
 status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, bool blocking)
 {
-    int active = mActive;
+    int active;
     int timeout = 0;
     status_t result;
     audio_track_cblk_t* cblk = mCblk;
+    uint32_t framesReq = audioBuffer->frameCount;
 
-    const uint32_t u = cblk->user;
-    uint32_t s = cblk->server;
+    audioBuffer->frameCount  = 0;
+    audioBuffer->size        = 0;
 
-    if (u == s) {
+    uint32_t framesReady = cblk->framesReady();
+
+    if (framesReady == 0) {
         Mutex::Autolock _l(cblk->lock);
         goto start_loop_here;
-        while (u == s) {
+        while (framesReady == 0) {
             active = mActive;
             if (UNLIKELY(!active))
                 return NO_MORE_BUFFERS;
@@ -284,40 +368,45 @@
             result = cblk->cv.waitRelative(cblk->lock, seconds(1));
             if (__builtin_expect(result!=NO_ERROR, false)) {
                 LOGW(   "obtainBuffer timed out (is the CPU pegged?) "
-                        "user=%08x, server=%08x", u, s);
+                        "user=%08x, server=%08x", cblk->user, cblk->server);
                 timeout = 1;
             }
             // read the server count again
         start_loop_here:
-            s = cblk->server;
+            framesReady = cblk->framesReady();
         }
     }
 
     LOGW_IF(timeout,
         "*** SERIOUS WARNING *** obtainBuffer() timed out "
         "but didn't need to be locked. We recovered, but "
-        "this shouldn't happen (user=%08x, server=%08x)", u, s);
+        "this shouldn't happen (user=%08x, server=%08x)", cblk->user, cblk->server);
+
+    if (framesReq > framesReady) {
+        framesReq = framesReady;
+    }
+
+    uint32_t u = cblk->user;
+    uint32_t bufferEnd = cblk->userBase + cblk->frameCount;
+
+    if (u + framesReady > bufferEnd) {
+        framesReq = bufferEnd - u;
+    }
 
     audioBuffer->flags       = 0;
     audioBuffer->channelCount= mChannelCount;
     audioBuffer->format      = mFormat;
-    audioBuffer->frameCount  = mFrameCount;
-    audioBuffer->size        = cblk->size;
-    audioBuffer->raw         = (int8_t*)
-            cblk->buffer(cblk->user & audio_track_cblk_t::BUFFER_MASK);
+    audioBuffer->frameCount  = framesReq;
+    audioBuffer->size        = framesReq*mChannelCount*sizeof(int16_t);
+    audioBuffer->raw         = (int8_t*)cblk->buffer(u);
+    active = mActive;
     return active ? status_t(NO_ERROR) : status_t(STOPPED);
 }
 
 void AudioRecord::releaseBuffer(Buffer* audioBuffer)
 {
-    // next buffer...
-    if (UNLIKELY(mPosition)) {
-        // clean the remaining part of the buffer
-        size_t capacity = mAudioBuffer.size - mPosition;
-        memset(mAudioBuffer.i8 + mPosition, 0, capacity);
-    }
     audio_track_cblk_t* cblk = mCblk;
-    cblk->stepUser(mBufferCount);
+    cblk->stepUser(audioBuffer->frameCount);
 }
 
 // -------------------------------------------------------------------------
@@ -325,32 +414,38 @@
 ssize_t AudioRecord::read(void* buffer, size_t userSize)
 {
     ssize_t read = 0;
+    Buffer audioBuffer;
+    int8_t *dst = static_cast<int8_t*>(buffer);
+
+    if (ssize_t(userSize) < 0) {
+        // sanity-check. user is most-likely passing an error code.
+        LOGE("AudioRecord::read(buffer=%p, size=%u (%d)",
+                buffer, userSize, userSize);
+        return BAD_VALUE;
+    }
+
+    LOGV("read size: %d", userSize);
+
     do {
-        if (mPosition == 0) {
-            status_t err = obtainBuffer(&mAudioBuffer, true);
-            if (err < 0) {
-                // out of buffers, return #bytes written
-                if (err == status_t(NO_MORE_BUFFERS))
-                    break;
-                return ssize_t(err);
-            }
+
+        audioBuffer.frameCount = userSize/mChannelCount/sizeof(int16_t);
+
+        status_t err = obtainBuffer(&audioBuffer, true);
+        if (err < 0) {
+            // out of buffers, return #bytes written
+            if (err == status_t(NO_MORE_BUFFERS))
+                break;
+            return ssize_t(err);
         }
 
-        size_t capacity = mAudioBuffer.size - mPosition;
-        size_t toRead = userSize < capacity ? userSize : capacity;
+        size_t bytesRead = audioBuffer.size;
+        memcpy(dst, audioBuffer.i8, bytesRead);
 
-        memcpy(buffer, mAudioBuffer.i8 + mPosition, toRead);
+        dst += bytesRead;
+        userSize -= bytesRead;
+        read += bytesRead;
 
-        buffer = static_cast<int8_t*>(buffer) + toRead;
-        mPosition += toRead;
-        userSize -= toRead;
-        capacity -= toRead;
-        read += toRead;
-
-        if (capacity == 0) {
-            mPosition = 0;
-            releaseBuffer(&mAudioBuffer);
-        }
+        releaseBuffer(&audioBuffer);
     } while (userSize);
 
     return read;
@@ -361,28 +456,83 @@
 bool AudioRecord::processAudioBuffer(const sp<ClientRecordThread>& thread)
 {
     Buffer audioBuffer;
-    bool more;
+    uint32_t frames = mRemainingFrames;
+    size_t readSize = 0;
+
+    // Manage marker callback
+    if (mMarkerPosition > 0) {
+        if (mCblk->user >= mMarkerPosition) {
+            mCbf(EVENT_MARKER, mUserData, (void *)&mMarkerPosition);
+            mMarkerPosition = 0;
+        }
+    }
+
+    // Manage new position callback
+    if (mUpdatePeriod > 0) {
+        while (mCblk->user >= mNewPosition) {
+            mCbf(EVENT_NEW_POS, mUserData, (void *)&mNewPosition);
+            mNewPosition += mUpdatePeriod;
+        }
+    }
 
     do {
-        status_t err = obtainBuffer(&audioBuffer, true); 
+        audioBuffer.frameCount = frames;
+        status_t err = obtainBuffer(&audioBuffer, false);
         if (err < NO_ERROR) {
-            LOGE("Error obtaining an audio buffer, giving up.");
-            return false;
+            if (err != WOULD_BLOCK) {
+                LOGE("Error obtaining an audio buffer, giving up.");
+                return false;
+            }
         }
-        more = mCbf(mUserData, audioBuffer);
+        if (err == status_t(STOPPED)) return false;
+
+        if (audioBuffer.size == 0) break;
+
+        size_t reqSize = audioBuffer.size;
+        mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);
+        readSize = audioBuffer.size;
+
+        // Sanity check on returned size
+        if (ssize_t(readSize) <= 0) break;
+        if (readSize > reqSize) readSize = reqSize;
+
+        audioBuffer.size = readSize;
+        audioBuffer.frameCount = readSize/mChannelCount/sizeof(int16_t);
+        frames -= audioBuffer.frameCount;
+
         releaseBuffer(&audioBuffer);
-    } while (more && !thread->exitPending());
 
-    // stop the track automatically
-    this->stop();
+    } while (frames);
 
+    
+    // Manage overrun callback
+    if (mActive && (mCblk->framesAvailable_l() == 0)) {
+        LOGV("Overrun user: %x, server: %x, flowControlFlag %d", mCblk->user, mCblk->server, mCblk->flowControlFlag);
+        if (mCblk->flowControlFlag == 0) {
+            mCbf(EVENT_OVERRUN, mUserData, 0);
+            mCblk->flowControlFlag = 1;
+        }
+    }
+
+    // If no data was read, it is likely that obtainBuffer() did
+    // not find available data in PCM buffer: we release the processor for
+    // a few millisecond before polling again for available data.
+    if (readSize == 0) {
+        usleep(5000);
+    } 
+
+    if (frames == 0) {
+        mRemainingFrames = mNotificationFrames;
+    } else {
+        mRemainingFrames = frames;
+    }
     return true;
 }
 
 // =========================================================================
 
-AudioRecord::ClientRecordThread::ClientRecordThread(AudioRecord& receiver)
-    : Thread(false), mReceiver(receiver)
+AudioRecord::ClientRecordThread::ClientRecordThread(AudioRecord& receiver, bool bCanCallJava)
+    : Thread(bCanCallJava), mReceiver(receiver)
 {
 }
 
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 22de463..a375b55 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -28,6 +28,11 @@
 sp<IAudioFlinger> AudioSystem::gAudioFlinger;
 sp<AudioSystem::DeathNotifier> AudioSystem::gDeathNotifier;
 audio_error_callback AudioSystem::gAudioErrorCallback = NULL;
+// Cached values
+int AudioSystem::gOutSamplingRate = 0;
+int AudioSystem::gOutFrameCount = 0;
+uint32_t AudioSystem::gOutLatency = 0;
+
 
 // establish binder interface to AudioFlinger service
 const sp<IAudioFlinger>& AudioSystem::get_audio_flinger()
@@ -47,11 +52,15 @@
             gDeathNotifier = new DeathNotifier();
         } else {
             if (gAudioErrorCallback) {
-                gAudioErrorCallback(NO_ERROR);               
+                gAudioErrorCallback(NO_ERROR);
             }
          }
         binder->linkToDeath(gDeathNotifier);
         gAudioFlinger = interface_cast<IAudioFlinger>(binder);
+        // Cache frequently accessed parameters 
+        gOutFrameCount = (int)gAudioFlinger->frameCount();
+        gOutSamplingRate = (int)gAudioFlinger->sampleRate();
+        gOutLatency = gAudioFlinger->latency();
     }
     LOGE_IF(gAudioFlinger==0, "no AudioFlinger!?");
     return gAudioFlinger;
@@ -71,7 +80,7 @@
 }
 
 status_t AudioSystem::bluetoothSco(bool state) {
-    uint32_t mask = ROUTE_BLUETOOTH;
+    uint32_t mask = ROUTE_BLUETOOTH_SCO;
     uint32_t routes = state ? mask : ROUTE_EARPIECE;
     return setRouting(MODE_IN_CALL, routes, ROUTE_ALL);
 }
@@ -79,7 +88,7 @@
 status_t AudioSystem::isBluetoothScoOn(bool* state) {
     uint32_t routes = 0;
     status_t s = getRouting(MODE_IN_CALL, &routes);
-    *state = !!(routes & ROUTE_BLUETOOTH);
+    *state = !!(routes & ROUTE_BLUETOOTH_SCO);
     return s;
 }
 
@@ -235,11 +244,50 @@
     return volume ? 100 - int(dBConvertInverse * log(volume) + 0.5) : 0;
 }
 
+status_t AudioSystem::getOutputSamplingRate(int* samplingRate)
+{
+    if (gOutSamplingRate == 0) {
+        const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+        if (af == 0) return PERMISSION_DENIED;
+        // gOutSamplingRate is updated by get_audio_flinger()
+    }    
+    *samplingRate = gOutSamplingRate;
+    
+    return NO_ERROR;
+}
+
+status_t AudioSystem::getOutputFrameCount(int* frameCount)
+{
+    if (gOutFrameCount == 0) {
+        const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+        if (af == 0) return PERMISSION_DENIED;
+        // gOutSamplingRate is updated by get_audio_flinger()
+    }
+    *frameCount = gOutFrameCount;
+    return NO_ERROR;
+}
+
+status_t AudioSystem::getOutputLatency(uint32_t* latency)
+{
+    if (gOutLatency == 0) {
+        const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+        if (af == 0) return PERMISSION_DENIED;
+        // gOutLatency is updated by get_audio_flinger()
+    }    
+    *latency = gOutLatency;
+    
+    return NO_ERROR;
+}
+
 // ---------------------------------------------------------------------------
 
-void AudioSystem::DeathNotifier::binderDied(const wp<IBinder>& who) {    
+void AudioSystem::DeathNotifier::binderDied(const wp<IBinder>& who) {
     Mutex::Autolock _l(AudioSystem::gLock);
     AudioSystem::gAudioFlinger.clear();
+    AudioSystem::gOutSamplingRate = 0;
+    AudioSystem::gOutFrameCount = 0;
+    AudioSystem::gOutLatency = 0;
+    
     if (gAudioErrorCallback) {
         gAudioErrorCallback(DEAD_OBJECT);
     }
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 298170a..d4f2e5a 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -2,16 +2,16 @@
 **
 ** Copyright 2007, 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 
+** 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 
+**     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 
+** 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.
 */
 
@@ -21,6 +21,7 @@
 
 #include <stdint.h>
 #include <sys/types.h>
+#include <limits.h>
 
 #include <sched.h>
 #include <sys/resource.h>
@@ -44,19 +45,6 @@
 
 // ---------------------------------------------------------------------------
 
-static volatile size_t gFrameCount = 0;
-
-size_t AudioTrack::frameCount()
-{
-    if (gFrameCount) return gFrameCount;
-    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
-    if (af == 0) return PERMISSION_DENIED;
-    gFrameCount = af->frameCount();
-    return gFrameCount;
-}
-
-// ---------------------------------------------------------------------------
-
 AudioTrack::AudioTrack()
     : mStatus(NO_INIT)
 {
@@ -67,24 +55,44 @@
         uint32_t sampleRate,
         int format,
         int channelCount,
-        int bufferCount,
+        int frameCount,
         uint32_t flags,
-        callback_t cbf, void* user)
+        callback_t cbf,
+        void* user,
+        int notificationFrames)
     : mStatus(NO_INIT)
 {
     mStatus = set(streamType, sampleRate, format, channelCount,
-            bufferCount, flags, cbf, user);
+            frameCount, flags, cbf, user, notificationFrames, 0);
+}
+
+AudioTrack::AudioTrack(
+        int streamType,
+        uint32_t sampleRate,
+        int format,
+        int channelCount,
+        const sp<IMemory>& sharedBuffer,
+        uint32_t flags,
+        callback_t cbf,
+        void* user,
+        int notificationFrames)
+    : mStatus(NO_INIT)
+{
+    mStatus = set(streamType, sampleRate, format, channelCount,
+            0, flags, cbf, user, notificationFrames, sharedBuffer);
 }
 
 AudioTrack::~AudioTrack()
 {
+    LOGV_IF(mSharedBuffer != 0, "Destructor sharedBuffer: %p", mSharedBuffer->pointer());
+
     if (mStatus == NO_ERROR) {
-        if (mPosition) {
-            releaseBuffer(&mAudioBuffer);
-        }
-        // obtainBuffer() will give up with an error
-        mAudioTrack->stop();
+        // Make sure that callback function exits in the case where
+        // it is looping on buffer full condition in obtainBuffer().
+        // Otherwise the callback thread will never exit.
+        stop();
         if (mAudioTrackThread != 0) {
+            mCblk->cv.signal();
             mAudioTrackThread->requestExitAndWait();
             mAudioTrackThread.clear();
         }
@@ -98,11 +106,17 @@
         uint32_t sampleRate,
         int format,
         int channelCount,
-        int bufferCount,
+        int frameCount,
         uint32_t flags,
-        callback_t cbf, void* user)
+        callback_t cbf,
+        void* user,
+        int notificationFrames,
+        const sp<IMemory>& sharedBuffer,
+        bool threadCanCallJava)
 {
 
+    LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size());
+
     if (mAudioFlinger != 0) {
         LOGE("Track already in use");
         return INVALID_OPERATION;
@@ -113,13 +127,26 @@
        LOGE("Could not get audioflinger");
        return NO_INIT;
     }
+    int afSampleRate;
+    if (AudioSystem::getOutputSamplingRate(&afSampleRate) != NO_ERROR) {
+        return NO_INIT;
+    }
+    int afFrameCount;
+    if (AudioSystem::getOutputFrameCount(&afFrameCount) != NO_ERROR) {
+        return NO_INIT;
+    }
+    uint32_t afLatency;
+    if (AudioSystem::getOutputLatency(&afLatency) != NO_ERROR) {
+        return NO_INIT;
+    }
+
 
     // handle default values first.
     if (streamType == DEFAULT) {
         streamType = MUSIC;
     }
     if (sampleRate == 0) {
-        sampleRate = audioFlinger->sampleRate();
+        sampleRate = afSampleRate;
     }
     // these below should probably come from the audioFlinger too...
     if (format == 0) {
@@ -128,12 +155,10 @@
     if (channelCount == 0) {
         channelCount = 2;
     }
-    if (bufferCount == 0) {
-        bufferCount = 2;
-    }
 
     // validate parameters
-    if (format != AudioSystem::PCM_16_BIT) {
+    if (((format != AudioSystem::PCM_8_BIT) || mSharedBuffer != 0) &&
+        (format != AudioSystem::PCM_16_BIT)) {
         LOGE("Invalid format");
         return BAD_VALUE;
     }
@@ -141,17 +166,51 @@
         LOGE("Invalid channel number");
         return BAD_VALUE;
     }
-    if (bufferCount < 2) {
-       LOGE("Invalid buffer count");
-       return BAD_VALUE;
+
+    // Ensure that buffer depth covers at least audio hardware latency
+    uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSampleRate);
+    // When playing from shared buffer, playback will start even if last audioflinger
+    // block is partly filled.
+    if (sharedBuffer != 0 && minBufCount > 1) {
+        minBufCount--;
+    }
+
+    int minFrameCount = (afFrameCount*sampleRate*minBufCount)/afSampleRate;
+
+    if (sharedBuffer == 0) {
+        if (frameCount == 0) {
+            frameCount = minFrameCount;
+        }
+        if (notificationFrames == 0) {
+            notificationFrames = frameCount/2;
+        }
+        // Make sure that application is notified with sufficient margin
+        // before underrun
+        if (notificationFrames > frameCount/2) {
+            notificationFrames = frameCount/2;
+        }
+    } else {
+        // Ensure that buffer alignment matches channelcount
+        if (((uint32_t)sharedBuffer->pointer() & (channelCount | 1)) != 0) {
+            LOGE("Invalid buffer alignement: address %p, channelCount %d", sharedBuffer->pointer(), channelCount);
+            return BAD_VALUE;
+        }
+        frameCount = sharedBuffer->size()/channelCount/sizeof(int16_t);
+    }
+
+    if (frameCount < minFrameCount) {
+      LOGE("Invalid buffer size: minFrameCount %d, frameCount %d", minFrameCount, frameCount);
+      return BAD_VALUE;
     }
 
     // create the track
+    status_t status;
     sp<IAudioTrack> track = audioFlinger->createTrack(getpid(),
-            streamType, sampleRate, format, channelCount, bufferCount, flags);
+                streamType, sampleRate, format, channelCount, frameCount, flags, sharedBuffer, &status);
+
     if (track == 0) {
-        LOGE("AudioFlinger could not create track");
-        return NO_INIT;
+        LOGE("AudioFlinger could not create track, status: %d", status);
+        return status;
     }
     sp<IMemory> cblk = track->getCblk();
     if (cblk == 0) {
@@ -159,7 +218,7 @@
         return NO_INIT;
     }
     if (cbf != 0) {
-        mAudioTrackThread = new AudioTrackThread(*this);
+        mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);
         if (mAudioTrackThread == 0) {
           LOGE("Could not create callback thread");
           return NO_INIT;
@@ -172,23 +231,34 @@
     mAudioTrack = track;
     mCblkMemory = cblk;
     mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
-    mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
+    if (sharedBuffer == 0) {
+        mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
+    } else {
+        mCblk->buffers = sharedBuffer->pointer();
+    }
+    mCblk->out = 1;
     mCblk->volume[0] = mCblk->volume[1] = 0x1000;
     mVolume[LEFT] = 1.0f;
     mVolume[RIGHT] = 1.0f;
     mSampleRate = sampleRate;
-    mFrameCount = audioFlinger->frameCount();
     mStreamType = streamType;
     mFormat = format;
-    mBufferCount = bufferCount;
+    // Update buffer size in case it has been limited by AudioFlinger during track creation
+    mFrameCount = mCblk->frameCount;
     mChannelCount = channelCount;
+    mSharedBuffer = sharedBuffer;
     mMuted = false;
     mActive = 0;
-    mReserved = 0;
     mCbf = cbf;
+    mNotificationFrames = notificationFrames;
+    mRemainingFrames = notificationFrames;
     mUserData = user;
-    mLatency = seconds(mFrameCount) / mSampleRate;
-    mPosition = 0;
+    mLatency = afLatency + (1000*mFrameCount) / mSampleRate;
+    mLoopCount = 0;
+    mMarkerPosition = 0;
+    mNewPosition = 0;
+    mUpdatePeriod = 0;
+    
     return NO_ERROR;
 }
 
@@ -199,7 +269,7 @@
 
 // -------------------------------------------------------------------------
 
-nsecs_t AudioTrack::latency() const
+uint32_t AudioTrack::latency() const
 {
     return mLatency;
 }
@@ -224,9 +294,19 @@
     return mChannelCount;
 }
 
-int AudioTrack::bufferCount() const
+uint32_t AudioTrack::frameCount() const
 {
-    return mBufferCount;
+    return mFrameCount;
+}
+
+int AudioTrack::frameSize() const
+{
+    return channelCount()*((format() == AudioSystem::PCM_8_BIT) ? sizeof(uint8_t) : sizeof(int16_t));
+}
+
+sp<IMemory>& AudioTrack::sharedBuffer()
+{
+    return mSharedBuffer;
 }
 
 // -------------------------------------------------------------------------
@@ -247,6 +327,12 @@
      }
 
     if (android_atomic_or(1, &mActive) == 0) {
+        if (mSharedBuffer != 0) {
+             // Force buffer full condition as data is already present in shared memory
+            mCblk->user = mFrameCount;
+            mCblk->flowControlFlag = 0;
+        }
+        mNewPosition = mCblk->server + mUpdatePeriod;
         if (t != 0) {
            t->run("AudioTrackThread", THREAD_PRIORITY_AUDIO_CLIENT);
         } else {
@@ -270,15 +356,20 @@
     }
 
     if (android_atomic_and(~1, &mActive) == 1) {
-        if (mPosition) {
-            releaseBuffer(&mAudioBuffer);
-        }
         mAudioTrack->stop();
-       if (t != 0) {
-           t->requestExit();
-       } else {
-           setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL);
-       }
+        // Cancel loops (If we are in the middle of a loop, playback
+        // would not stop until loopCount reaches 0).
+        setLoop(0, 0, 0);
+        // Force flush if a shared buffer is used otherwise audioflinger
+        // will not stop before end of buffer is reached.
+        if (mSharedBuffer != 0) {
+            flush();
+        }
+        if (t != 0) {
+            t->requestExit();
+        } else {
+            setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL);
+        }
     }
 
     if (t != 0) {
@@ -294,6 +385,7 @@
 void AudioTrack::flush()
 {
     LOGV("flush");
+
     if (!mActive) {
         mCblk->lock.lock();
         mAudioTrack->flush();
@@ -341,7 +433,16 @@
 
 void AudioTrack::setSampleRate(int rate)
 {
+    int afSamplingRate;
+
+    if (AudioSystem::getOutputSamplingRate(&afSamplingRate) != NO_ERROR) {
+        return;
+    }
+    // Resampler implementation limits input sampling rate to 2 x output sampling rate.
+    if (rate > afSamplingRate*2) rate = afSamplingRate*2;
+
     if (rate > MAX_SAMPLE_RATE) rate = MAX_SAMPLE_RATE;
+
     mCblk->sampleRate = rate;
 }
 
@@ -350,6 +451,129 @@
     return uint32_t(mCblk->sampleRate);
 }
 
+status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount)
+{
+    audio_track_cblk_t* cblk = mCblk;
+
+
+    Mutex::Autolock _l(cblk->lock);
+
+    if (loopCount == 0) {
+        cblk->loopStart = UINT_MAX;
+        cblk->loopEnd = UINT_MAX;
+        cblk->loopCount = 0;
+        mLoopCount = 0;
+        return NO_ERROR;
+    }
+
+    if (loopStart >= loopEnd ||
+        loopStart < cblk->user ||
+        loopEnd - loopStart > mFrameCount) {
+        LOGW("setLoop invalid value: loopStart %d, loopEnd %d, loopCount %d, framecount %d, user %d", loopStart, loopEnd, loopCount, mFrameCount, cblk->user);
+        return BAD_VALUE;
+    }
+    // TODO handle shared buffer here: limit loop end to framecount
+
+    cblk->loopStart = loopStart;
+    cblk->loopEnd = loopEnd;
+    cblk->loopCount = loopCount;
+    mLoopCount = loopCount;
+
+    return NO_ERROR;
+}
+
+status_t AudioTrack::getLoop(uint32_t *loopStart, uint32_t *loopEnd, int *loopCount)
+{
+    if (loopStart != 0) {
+        *loopStart = mCblk->loopStart;
+    }
+    if (loopEnd != 0) {
+        *loopEnd = mCblk->loopEnd;
+    }
+    if (loopCount != 0) {
+        if (mCblk->loopCount < 0) {
+            *loopCount = -1;
+        } else {
+            *loopCount = mCblk->loopCount;
+        }
+    }
+
+    return NO_ERROR;
+}
+
+status_t AudioTrack::setMarkerPosition(uint32_t marker)
+{
+    if (mCbf == 0) return INVALID_OPERATION;
+
+    mMarkerPosition = marker;
+
+    return NO_ERROR;
+}
+
+status_t AudioTrack::getMarkerPosition(uint32_t *marker)
+{
+    if (marker == 0) return BAD_VALUE;
+
+    *marker = mMarkerPosition;
+
+    return NO_ERROR;
+}
+
+status_t AudioTrack::setPositionUpdatePeriod(uint32_t updatePeriod)
+{
+    if (mCbf == 0) return INVALID_OPERATION;
+
+    uint32_t curPosition;
+    getPosition(&curPosition);
+    mNewPosition = curPosition + updatePeriod;
+    mUpdatePeriod = updatePeriod;
+
+    return NO_ERROR;
+}
+
+status_t AudioTrack::getPositionUpdatePeriod(uint32_t *updatePeriod)
+{
+    if (updatePeriod == 0) return BAD_VALUE;
+
+    *updatePeriod = mUpdatePeriod;
+
+    return NO_ERROR;
+}
+
+status_t AudioTrack::setPosition(uint32_t position)
+{
+    Mutex::Autolock _l(mCblk->lock);
+
+    if (!stopped()) return INVALID_OPERATION;
+
+    if (position > mCblk->user) return BAD_VALUE;
+
+    mCblk->server = position;
+    mCblk->forceReady = 1;
+    
+    return NO_ERROR;
+}
+
+status_t AudioTrack::getPosition(uint32_t *position)
+{
+    if (position == 0) return BAD_VALUE;
+
+    *position = mCblk->server;
+
+    return NO_ERROR;
+}
+
+status_t AudioTrack::reload()
+{
+    if (!stopped()) return INVALID_OPERATION;
+    
+    flush();
+
+    mCblk->stepUser(mFrameCount);
+
+    return NO_ERROR;
+}
+
 // -------------------------------------------------------------------------
 
 status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, bool blocking)
@@ -358,21 +582,17 @@
     int timeout = 0;
     status_t result;
     audio_track_cblk_t* cblk = mCblk;
+    uint32_t framesReq = audioBuffer->frameCount;
 
-    uint32_t u = cblk->user;
-    uint32_t u_seq = u & audio_track_cblk_t::SEQUENCE_MASK;
-    uint32_t u_buf = u & audio_track_cblk_t::BUFFER_MASK;
+    audioBuffer->frameCount  = 0;
+    audioBuffer->size = 0;
 
-    uint32_t s = cblk->server;
-    uint32_t s_seq = s & audio_track_cblk_t::SEQUENCE_MASK;
-    uint32_t s_buf = s & audio_track_cblk_t::BUFFER_MASK;
+    uint32_t framesAvail = cblk->framesAvailable();
 
-    LOGW_IF(u_seq < s_seq, "user doesn't fill buffers fast enough");
-
-    if (u_seq > s_seq && u_buf == s_buf) {
+    if (framesAvail == 0) {
         Mutex::Autolock _l(cblk->lock);
         goto start_loop_here;
-        while (u_seq > s_seq && u_buf == s_buf) {
+        while (framesAvail == 0) {
             active = mActive;
             if (UNLIKELY(!active)) {
                 LOGV("Not active and NO_MORE_BUFFERS");
@@ -384,89 +604,101 @@
             result = cblk->cv.waitRelative(cblk->lock, seconds(1));
             if (__builtin_expect(result!=NO_ERROR, false)) {
                 LOGW(   "obtainBuffer timed out (is the CPU pegged?) "
-                        "user=%08x, server=%08x", u, s);
+                        "user=%08x, server=%08x", cblk->user, cblk->server);
                 mAudioTrack->start(); // FIXME: Wake up audioflinger
                 timeout = 1;
             }
-            // Read user count in case a flush has reset while we where waiting on cv.
-            u = cblk->user;
-            u_seq = u & audio_track_cblk_t::SEQUENCE_MASK;
-            u_buf = u & audio_track_cblk_t::BUFFER_MASK;
-
             // read the server count again
         start_loop_here:
-            s = cblk->server;
-            s_seq = s & audio_track_cblk_t::SEQUENCE_MASK;
-            s_buf = s & audio_track_cblk_t::BUFFER_MASK;
+            framesAvail = cblk->framesAvailable_l();
         }
     }
 
+    if (framesReq > framesAvail) {
+        framesReq = framesAvail;
+    }
+
+    uint32_t u = cblk->user;
+    uint32_t bufferEnd = cblk->userBase + cblk->frameCount;
+
+    if (u + framesReq > bufferEnd) {
+        framesReq = bufferEnd - u;
+    }
+
     LOGW_IF(timeout,
         "*** SERIOUS WARNING *** obtainBuffer() timed out "
         "but didn't need to be locked. We recovered, but "
-        "this shouldn't happen (user=%08x, server=%08x)", u, s);
+        "this shouldn't happen (user=%08x, server=%08x)", cblk->user, cblk->server);
 
     audioBuffer->flags       = mMuted ? Buffer::MUTE : 0;
     audioBuffer->channelCount= mChannelCount;
-    audioBuffer->format      = mFormat;
-    audioBuffer->frameCount  = mFrameCount;
-    audioBuffer->size        = cblk->size;
-    audioBuffer->raw         = (int8_t *)cblk->buffer(u_buf);
+    audioBuffer->format      = AudioSystem::PCM_16_BIT;
+    audioBuffer->frameCount  = framesReq;
+    audioBuffer->size = framesReq*mChannelCount*sizeof(int16_t);
+    audioBuffer->raw         = (int8_t *)cblk->buffer(u);
     active = mActive;
     return active ? status_t(NO_ERROR) : status_t(STOPPED);
 }
 
 void AudioTrack::releaseBuffer(Buffer* audioBuffer)
 {
-    // next buffer...
-    if (UNLIKELY(mPosition)) {
-        // clean the remaining part of the buffer
-        size_t capacity = mAudioBuffer.size - mPosition;
-        memset(mAudioBuffer.i8 + mPosition, 0, capacity);
-        mPosition = 0;
-    }
     audio_track_cblk_t* cblk = mCblk;
-    cblk->stepUser(mBufferCount);
+    cblk->stepUser(audioBuffer->frameCount);
 }
 
 // -------------------------------------------------------------------------
 
 ssize_t AudioTrack::write(const void* buffer, size_t userSize)
 {
+
+    if (mSharedBuffer != 0) return INVALID_OPERATION;
+
     if (ssize_t(userSize) < 0) {
         // sanity-check. user is most-likely passing an error code.
-        LOGE("AudioTrack::write(buffer=%p, size=%u (%d)", 
+        LOGE("AudioTrack::write(buffer=%p, size=%u (%d)",
                 buffer, userSize, userSize);
         return BAD_VALUE;
     }
 
     LOGV("write %d bytes, mActive=%d", userSize, mActive);
+
     ssize_t written = 0;
+    const int8_t *src = (const int8_t *)buffer;
+    Buffer audioBuffer;
+
     do {
-        if (mPosition == 0) {
-            status_t err = obtainBuffer(&mAudioBuffer, true);
-            if (err < 0) {
-                // out of buffers, return #bytes written
-                if (err == status_t(NO_MORE_BUFFERS))
-                    break;
-                return ssize_t(err);
-            }
+        audioBuffer.frameCount = userSize/mChannelCount;
+        if (mFormat == AudioSystem::PCM_16_BIT) {
+            audioBuffer.frameCount >>= 1;
         }
 
-        size_t capacity = mAudioBuffer.size - mPosition;
-        size_t toWrite = userSize < capacity ? userSize : capacity;
+        status_t err = obtainBuffer(&audioBuffer, true);
+        if (err < 0) {
+            // out of buffers, return #bytes written
+            if (err == status_t(NO_MORE_BUFFERS))
+                break;
+            return ssize_t(err);
+        }
 
-        memcpy(mAudioBuffer.i8 + mPosition, buffer, toWrite);
-        buffer = static_cast<const int8_t*>(buffer) + toWrite;
-        mPosition += toWrite;
+        size_t toWrite;
+        if (mFormat == AudioSystem::PCM_8_BIT) {
+            // Divide capacity by 2 to take expansion into account
+            toWrite = audioBuffer.size>>1;
+            // 8 to 16 bit conversion
+            int count = toWrite;
+            int16_t *dst = (int16_t *)(audioBuffer.i8);
+            while(count--) {
+                *dst++ = (int16_t)(*src++^0x80) << 8;
+            }
+        }else {
+            toWrite = audioBuffer.size;
+            memcpy(audioBuffer.i8, src, toWrite);
+            src += toWrite;
+        }
         userSize -= toWrite;
-        capacity -= toWrite;
         written += toWrite;
 
-        if (capacity == 0) {
-            mPosition = 0;
-            releaseBuffer(&mAudioBuffer);
-        }
+        releaseBuffer(&audioBuffer);
     } while (userSize);
 
     return written;
@@ -477,16 +709,115 @@
 bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
 {
     Buffer audioBuffer;
+    uint32_t frames;
+    size_t writtenSize = 0;
 
-    status_t err = obtainBuffer(&audioBuffer, true);
-    if (err < NO_ERROR) {
-        LOGE("Error obtaining an audio buffer, giving up.");
-        return false;
+    // Manage underrun callback
+    if (mActive && (mCblk->framesReady() == 0)) {
+        LOGV("Underrun user: %x, server: %x, flowControlFlag %d", mCblk->user, mCblk->server, mCblk->flowControlFlag);
+        if (mCblk->flowControlFlag == 0) {
+            mCbf(EVENT_UNDERRUN, mUserData, 0);
+            if (mCblk->server == mCblk->frameCount) {
+                mCbf(EVENT_BUFFER_END, mUserData, 0);                
+            }
+            mCblk->flowControlFlag = 1;
+            if (mSharedBuffer != 0) return false;
+        }
     }
-    if (err == status_t(STOPPED)) return false;
-    mCbf(mUserData, audioBuffer);
-    releaseBuffer(&audioBuffer);
+    
+    // Manage loop end callback
+    while (mLoopCount > mCblk->loopCount) {
+        int loopCount = -1;
+        mLoopCount--;
+        if (mLoopCount >= 0) loopCount = mLoopCount;
 
+        mCbf(EVENT_LOOP_END, mUserData, (void *)&loopCount);
+    }
+
+    // Manage marker callback
+    if(mMarkerPosition > 0) {
+        if (mCblk->server >= mMarkerPosition) {
+            mCbf(EVENT_MARKER, mUserData, (void *)&mMarkerPosition);
+            mMarkerPosition = 0;
+        }
+    }
+
+    // Manage new position callback
+    if(mUpdatePeriod > 0) {
+        while (mCblk->server >= mNewPosition) {
+            mCbf(EVENT_NEW_POS, mUserData, (void *)&mNewPosition);
+            mNewPosition += mUpdatePeriod;
+        }
+    }
+
+    // If Shared buffer is used, no data is requested from client.
+    if (mSharedBuffer != 0) {
+        frames = 0;
+    } else {
+        frames = mRemainingFrames;
+    }
+
+    do {
+
+        audioBuffer.frameCount = frames;
+
+        status_t err = obtainBuffer(&audioBuffer, false);
+        if (err < NO_ERROR) {
+            if (err != WOULD_BLOCK) {
+                LOGE("Error obtaining an audio buffer, giving up.");
+                return false;
+            }
+        }
+        if (err == status_t(STOPPED)) return false;
+
+        if (audioBuffer.size == 0) break;
+
+        // Divide buffer size by 2 to take into account the expansion
+        // due to 8 to 16 bit conversion: the callback must fill only half
+        // of the destination buffer
+        if (mFormat == AudioSystem::PCM_8_BIT) {
+            audioBuffer.size >>= 1;
+        }
+
+        size_t reqSize = audioBuffer.size;
+        mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);
+        writtenSize = audioBuffer.size;
+
+        // Sanity check on returned size
+        if (ssize_t(writtenSize) <= 0) break;
+        if (writtenSize > reqSize) writtenSize = reqSize;
+
+        if (mFormat == AudioSystem::PCM_8_BIT) {
+            // 8 to 16 bit conversion
+            const int8_t *src = audioBuffer.i8 + writtenSize-1;
+            int count = writtenSize;
+            int16_t *dst = audioBuffer.i16 + writtenSize-1;
+            while(count--) {
+                *dst-- = (int16_t)(*src--^0x80) << 8;
+            }
+            writtenSize <<= 1;
+        }
+
+        audioBuffer.size = writtenSize;
+        audioBuffer.frameCount = writtenSize/mChannelCount/sizeof(int16_t);
+        frames -= audioBuffer.frameCount;
+
+        releaseBuffer(&audioBuffer);
+    }
+    while (frames);
+
+    // If no data was written, it is likely that obtainBuffer() did
+    // not find room in PCM buffer: we release the processor for
+    // a few millisecond before polling again for available room.
+    if (writtenSize == 0) {
+        usleep(5000);
+    }
+
+    if (frames == 0) {
+        mRemainingFrames = mNotificationFrames;
+    } else {
+        mRemainingFrames = frames;
+    }
     return true;
 }
 
@@ -500,11 +831,11 @@
     result.append(" AudioTrack::dump\n");
     snprintf(buffer, 255, "  stream type(%d), left - right volume(%f, %f)\n", mStreamType, mVolume[0], mVolume[1]);
     result.append(buffer);
-    snprintf(buffer, 255, "  format(%d), channel count(%d), frame count(%d), buffer count(%d)\n", mFormat, mChannelCount, mFrameCount, mBufferCount);
+    snprintf(buffer, 255, "  format(%d), channel count(%d), frame count(%d)\n", mFormat, mChannelCount, mFrameCount);
     result.append(buffer);
-    snprintf(buffer, 255, "  sample rate(%d), status(%d), muted(%d), reserved(%d)\n", mSampleRate, mStatus, mMuted, mReserved);
+    snprintf(buffer, 255, "  sample rate(%d), status(%d), muted(%d)\n", mSampleRate, mStatus, mMuted);
     result.append(buffer);
-    snprintf(buffer, 255, "  active(%d), latency (%lld), position(%d)\n", mActive, mLatency, mPosition);
+    snprintf(buffer, 255, "  active(%d), latency (%d)\n", mActive, mLatency);
     result.append(buffer);
     ::write(fd, result.string(), result.size());
     return NO_ERROR;
@@ -512,8 +843,8 @@
 
 // =========================================================================
 
-AudioTrack::AudioTrackThread::AudioTrackThread(AudioTrack& receiver)
-    : Thread(false), mReceiver(receiver)
+AudioTrack::AudioTrackThread::AudioTrackThread(AudioTrack& receiver, bool bCanCallJava)
+    : Thread(bCanCallJava), mReceiver(receiver)
 {
 }
 
@@ -534,25 +865,35 @@
 // =========================================================================
 
 audio_track_cblk_t::audio_track_cblk_t()
-    : user(0), server(0), volumeLR(0), buffers(0), size(0)
+    : user(0), server(0), userBase(0), serverBase(0), buffers(0), frameCount(0),
+    loopStart(UINT_MAX), loopEnd(UINT_MAX), loopCount(0), volumeLR(0), flowControlFlag(1), forceReady(0)
 {
 }
 
-uint32_t audio_track_cblk_t::stepUser(int bufferCount)
+uint32_t audio_track_cblk_t::stepUser(uint32_t frameCount)
 {
     uint32_t u = this->user;
-    uint32_t u_seq = u & audio_track_cblk_t::SEQUENCE_MASK;
-    uint32_t u_buf = u & audio_track_cblk_t::BUFFER_MASK;
-    if (++u_buf >= uint32_t(bufferCount)) {
-        u_seq += 0x100;
-        u_buf = 0;
+
+    u += frameCount;
+    // Ensure that user is never ahead of server for AudioRecord
+    if (!out && u > this->server) {
+        LOGW("stepServer occured after track reset");
+        u = this->server;
     }
-    u = u_seq | u_buf;
-    this->user = u; 
+
+    if (u >= userBase + this->frameCount) {
+        userBase += this->frameCount;
+    }
+
+    this->user = u;
+
+    // Clear flow control error condition as new data has been written/read to/from buffer.
+    flowControlFlag = 0;
+
     return u;
 }
 
-bool audio_track_cblk_t::stepServer(int bufferCount)
+bool audio_track_cblk_t::stepServer(uint32_t frameCount)
 {
     // the code below simulates lock-with-timeout
     // we MUST do this to protect the AudioFlinger server
@@ -570,24 +911,83 @@
     }
 
     uint32_t s = this->server;
-    uint32_t s_seq = s & audio_track_cblk_t::SEQUENCE_MASK;
-    uint32_t s_buf = s & audio_track_cblk_t::BUFFER_MASK;
-    s_buf++;
-    if (s_buf >= uint32_t(bufferCount)) {
-        s_seq += 0x100;
-        s_buf = 0;
-    }
-    s = s_seq | s_buf;
 
-    this->server = s; 
+    s += frameCount;
+    // It is possible that we receive a flush()
+    // while the mixer is processing a block: in this case,
+    // stepServer() is called After the flush() has reset u & s and
+    // we have s > u
+    if (out && s > this->user) {
+        LOGW("stepServer occured after track reset");
+        s = this->user;
+    }
+
+    if (s >= loopEnd) {
+        LOGW_IF(s > loopEnd, "stepServer: s %u > loopEnd %u", s, loopEnd);
+        s = loopStart;
+        if (--loopCount == 0) {
+            loopEnd = UINT_MAX;
+            loopStart = UINT_MAX;
+        }
+    }
+    if (s >= serverBase + this->frameCount) {
+        serverBase += this->frameCount;
+    }
+
+    this->server = s;
+
     cv.signal();
     lock.unlock();
     return true;
 }
 
-void* audio_track_cblk_t::buffer(int id) const
+void* audio_track_cblk_t::buffer(uint32_t offset) const
 {
-    return (char*)this->buffers + id * this->size;
+    return (int16_t *)this->buffers + (offset-userBase)*this->channels;
+}
+
+uint32_t audio_track_cblk_t::framesAvailable()
+{
+    Mutex::Autolock _l(lock);
+    return framesAvailable_l();
+}
+
+uint32_t audio_track_cblk_t::framesAvailable_l()
+{
+    uint32_t u = this->user;
+    uint32_t s = this->server;
+
+    if (out) {
+        if (u < loopEnd) {
+            return s + frameCount - u;
+        } else {
+            uint32_t limit = (s < loopStart) ? s : loopStart;
+            return limit + frameCount - u;
+        }
+    } else {
+        return frameCount + u - s;
+    }
+}
+
+uint32_t audio_track_cblk_t::framesReady()
+{
+    uint32_t u = this->user;
+    uint32_t s = this->server;
+
+    if (out) {
+        if (u < loopEnd) {
+            return u - s;
+        } else {
+            Mutex::Autolock _l(lock);
+            if (loopCount >= 0) {
+                return (loopEnd - loopStart)*loopCount + u - s;
+            } else {
+                return UINT_MAX;
+            }
+        }
+    } else {
+        return s - u;
+    }
 }
 
 // -------------------------------------------------------------------------
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index 474381b..018ea6c 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -2,16 +2,16 @@
 **
 ** Copyright 2007, 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 
+** 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 
+**     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 
+** 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.
 */
 
@@ -34,6 +34,7 @@
     CHANNEL_COUNT,
     FORMAT,
     FRAME_COUNT,
+    LATENCY,
     SET_MASTER_VOLUME,
     SET_MASTER_MUTE,
     MASTER_VOLUME,
@@ -66,8 +67,10 @@
                                 uint32_t sampleRate,
                                 int format,
                                 int channelCount,
-                                int bufferCount,
-                                uint32_t flags)
+                                int frameCount,
+                                uint32_t flags,
+                                const sp<IMemory>& sharedBuffer,
+                                status_t *status)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
@@ -76,13 +79,17 @@
         data.writeInt32(sampleRate);
         data.writeInt32(format);
         data.writeInt32(channelCount);
-        data.writeInt32(bufferCount);
+        data.writeInt32(frameCount);
         data.writeInt32(flags);
-        status_t status = remote()->transact(CREATE_TRACK, data, &reply);
-        if ( status != NO_ERROR) {
-            LOGE("createTrack error: %s", strerror(-status));
+        data.writeStrongBinder(sharedBuffer->asBinder());
+        status_t lStatus = remote()->transact(CREATE_TRACK, data, &reply);
+        if (lStatus != NO_ERROR) {
+            LOGE("createTrack error: %s", strerror(-lStatus));
         }
-        
+        lStatus = reply.readInt32();
+        if (status) {
+            *status = lStatus;
+        }
         return interface_cast<IAudioTrack>(reply.readStrongBinder());
     }
 
@@ -92,8 +99,9 @@
                                 uint32_t sampleRate,
                                 int format,
                                 int channelCount,
-                                int bufferCount,
-                                uint32_t flags)
+                                int frameCount,
+                                uint32_t flags,
+                                status_t *status)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
@@ -102,9 +110,13 @@
         data.writeInt32(sampleRate);
         data.writeInt32(format);
         data.writeInt32(channelCount);
-        data.writeInt32(bufferCount);
+        data.writeInt32(frameCount);
         data.writeInt32(flags);
         remote()->transact(OPEN_RECORD, data, &reply);
+        status_t lStatus = reply.readInt32();
+        if (status) {
+            *status = lStatus;
+        }
         return interface_cast<IAudioRecord>(reply.readStrongBinder());
     }
 
@@ -140,6 +152,14 @@
         return reply.readInt32();
     }
 
+    virtual uint32_t latency() const
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        remote()->transact(LATENCY, data, &reply);
+        return reply.readInt32();
+    }
+
     virtual status_t setMasterVolume(float value)
     {
         Parcel data, reply;
@@ -308,9 +328,12 @@
             int channelCount = data.readInt32();
             size_t bufferCount = data.readInt32();
             uint32_t flags = data.readInt32();
-            sp<IAudioTrack> track = createTrack(pid, 
+            sp<IMemory> buffer = interface_cast<IMemory>(data.readStrongBinder());
+            status_t status;
+            sp<IAudioTrack> track = createTrack(pid,
                     streamType, sampleRate, format,
-                    channelCount, bufferCount, flags);
+                    channelCount, bufferCount, flags, buffer, &status);
+            reply->writeInt32(status);
             reply->writeStrongBinder(track->asBinder());
             return NO_ERROR;
         } break;
@@ -323,8 +346,10 @@
             int channelCount = data.readInt32();
             size_t bufferCount = data.readInt32();
             uint32_t flags = data.readInt32();
+            status_t status;
             sp<IAudioRecord> record = openRecord(pid, streamType,
-                    sampleRate, format, channelCount, bufferCount, flags);
+                    sampleRate, format, channelCount, bufferCount, flags, &status);
+            reply->writeInt32(status);
             reply->writeStrongBinder(record->asBinder());
             return NO_ERROR;
         } break;
@@ -348,7 +373,12 @@
             reply->writeInt32( frameCount() );
             return NO_ERROR;
         } break;
-        case SET_MASTER_VOLUME: {
+        case LATENCY: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            reply->writeInt32( latency() );
+            return NO_ERROR;
+        } break;
+         case SET_MASTER_VOLUME: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             reply->writeInt32( setMasterVolume(data.readFloat()) );
             return NO_ERROR;
diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp
new file mode 100644
index 0000000..615ae37
--- /dev/null
+++ b/media/libmedia/IMediaMetadataRetriever.cpp
@@ -0,0 +1,218 @@
+/*
+**
+** Copyright (C) 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.
+*/
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Parcel.h>
+#include <graphics/SkBitmap.h>
+#include <media/IMediaMetadataRetriever.h>
+
+namespace android {
+
+enum {
+    DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
+    SET_DATA_SOURCE_URL,
+    SET_DATA_SOURCE_FD,
+    SET_MODE,
+    GET_MODE,
+    CAPTURE_FRAME,
+    EXTARCT_ALBUM_ART,
+    EXTRACT_METADATA,
+};
+
+class BpMediaMetadataRetriever: public BpInterface<IMediaMetadataRetriever>
+{
+public:
+    BpMediaMetadataRetriever(const sp<IBinder>& impl)
+        : BpInterface<IMediaMetadataRetriever>(impl)
+    {
+    }
+
+    // disconnect from media metadata retriever service
+    void disconnect()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
+        remote()->transact(DISCONNECT, data, &reply);
+    }
+
+    status_t setDataSource(const char* srcUrl)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
+        data.writeCString(srcUrl);
+        remote()->transact(SET_DATA_SOURCE_URL, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t setDataSource(int fd, int64_t offset, int64_t length)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
+        data.writeFileDescriptor(fd);
+        data.writeInt64(offset);
+        data.writeInt64(length);
+        remote()->transact(SET_DATA_SOURCE_FD, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t setMode(int mode)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
+        data.writeInt32(mode);
+        remote()->transact(SET_MODE, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t getMode(int* mode) const
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
+        remote()->transact(GET_MODE, data, &reply);
+        *mode = reply.readInt32();
+        return reply.readInt32();
+    }
+
+    sp<IMemory> captureFrame()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
+        remote()->transact(CAPTURE_FRAME, data, &reply);
+        status_t ret = reply.readInt32();
+        if (ret != NO_ERROR) {
+            return NULL;
+        }
+        return interface_cast<IMemory>(reply.readStrongBinder());
+    }
+
+    sp<IMemory> extractAlbumArt()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
+        remote()->transact(EXTARCT_ALBUM_ART, data, &reply);
+        status_t ret = reply.readInt32();
+        if (ret != NO_ERROR) {
+            return NULL;
+        }
+        return interface_cast<IMemory>(reply.readStrongBinder());
+    }
+
+    const char* extractMetadata(int keyCode)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
+        data.writeInt32(keyCode);
+        remote()->transact(EXTRACT_METADATA, data, &reply);
+        status_t ret = reply.readInt32();
+        if (ret != NO_ERROR) {
+            return NULL;
+        }
+        return reply.readCString();
+    }
+};
+
+IMPLEMENT_META_INTERFACE(MediaMetadataRetriever, "android.hardware.IMediaMetadataRetriever");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+        do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+            LOGW("Call incorrectly routed to " #interface); \
+            return PERMISSION_DENIED; \
+        } } while (0)
+
+status_t BnMediaMetadataRetriever::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch (code) {
+        case DISCONNECT: {
+            CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
+            disconnect();
+            return NO_ERROR;
+        } break;
+        case SET_DATA_SOURCE_URL: {
+            CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
+            const char* srcUrl = data.readCString();
+            reply->writeInt32(setDataSource(srcUrl));
+            return NO_ERROR;
+        } break;
+        case SET_DATA_SOURCE_FD: {
+            CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
+            int fd = dup(data.readFileDescriptor());
+            int64_t offset = data.readInt64();
+            int64_t length = data.readInt64();
+            reply->writeInt32(setDataSource(fd, offset, length));
+            return NO_ERROR;
+        } break;
+        case SET_MODE: {
+            CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
+            int mode = data.readInt32();
+            reply->writeInt32(setMode(mode));
+            return NO_ERROR;
+        } break;
+        case GET_MODE: {
+            CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
+            int mode;
+            status_t status = getMode(&mode);
+            reply->writeInt32(mode);
+            reply->writeInt32(status);
+            return NO_ERROR;
+        } break;
+        case CAPTURE_FRAME: {
+            CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
+            sp<IMemory> bitmap = captureFrame();
+            if (bitmap != 0) {  // Don't send NULL across the binder interface
+                reply->writeInt32(NO_ERROR);
+                reply->writeStrongBinder(bitmap->asBinder());
+            } else {
+                reply->writeInt32(UNKNOWN_ERROR);
+            }
+            return NO_ERROR;
+        } break;
+        case EXTARCT_ALBUM_ART: {
+            CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
+            sp<IMemory> albumArt = extractAlbumArt();
+            if (albumArt != 0) {  // Don't send NULL across the binder interface
+                reply->writeInt32(NO_ERROR);
+                reply->writeStrongBinder(albumArt->asBinder());
+            } else {
+                reply->writeInt32(UNKNOWN_ERROR);
+            }
+            return NO_ERROR;
+        } break;
+        case EXTRACT_METADATA: {
+            CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
+            int keyCode = data.readInt32();
+            const char* value = extractMetadata(keyCode);
+            if (value != NULL) {  // Don't send NULL across the binder interface
+                reply->writeInt32(NO_ERROR);
+                reply->writeCString(value);
+            } else {
+                reply->writeInt32(UNKNOWN_ERROR);
+            }
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index 8385114..f37519f 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -33,7 +33,6 @@
     STOP,
     IS_PLAYING,
     PAUSE,
-    GET_VIDEO_SIZE,
     SEEK_TO,
     GET_CURRENT_POSITION,
     GET_DURATION,
@@ -109,16 +108,6 @@
         return reply.readInt32();
     }
 
-    status_t getVideoSize(int* w, int* h)
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
-        remote()->transact(GET_VIDEO_SIZE, data, &reply);
-        *w = reply.readInt32();
-        *h = reply.readInt32();
-        return reply.readInt32();
-    }
-
     status_t seekTo(int msec)
     {
         Parcel data, reply;
@@ -235,15 +224,6 @@
             reply->writeInt32(pause());
             return NO_ERROR;
         } break;
-        case GET_VIDEO_SIZE: {
-            CHECK_INTERFACE(IMediaPlayer, data, reply);
-            int w, h;
-            status_t ret = getVideoSize(&w, &h);
-            reply->writeInt32(w);
-            reply->writeInt32(h);
-            reply->writeInt32(ret);
-            return NO_ERROR;
-        } break;
         case SEEK_TO: {
             CHECK_INTERFACE(IMediaPlayer, data, reply);
             reply->writeInt32(seekTo(data.readInt32()));
diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp
index b087100..370e3fb 100644
--- a/media/libmedia/IMediaPlayerService.cpp
+++ b/media/libmedia/IMediaPlayerService.cpp
@@ -21,6 +21,7 @@
 
 #include <utils/IMemory.h>
 #include <media/IMediaPlayerService.h>
+#include <media/IMediaRecorder.h>
 
 namespace android {
 
@@ -29,6 +30,8 @@
     CREATE_FD,
     DECODE_URL,
     DECODE_FD,
+    CREATE_MEDIA_RECORDER,
+    CREATE_METADATA_RETRIEVER,
 };
 
 class BpMediaPlayerService: public BpInterface<IMediaPlayerService>
@@ -39,6 +42,15 @@
     {
     }
 
+    virtual sp<IMediaMetadataRetriever> createMetadataRetriever(pid_t pid)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
+        data.writeInt32(pid);
+        remote()->transact(CREATE_METADATA_RETRIEVER, data, &reply);
+        return interface_cast<IMediaMetadataRetriever>(reply.readStrongBinder());
+    }
+
     virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url)
     {
         Parcel data, reply;
@@ -50,6 +62,15 @@
         return interface_cast<IMediaPlayer>(reply.readStrongBinder());
     }
 
+    virtual sp<IMediaRecorder> createMediaRecorder(pid_t pid)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
+        data.writeInt32(pid);
+        remote()->transact(CREATE_MEDIA_RECORDER, data, &reply);
+        return interface_cast<IMediaRecorder>(reply.readStrongBinder());
+    }
+
     virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length)
     {
         Parcel data, reply;
@@ -63,7 +84,7 @@
         return interface_cast<IMediaPlayer>(reply.readStrongBinder());
     }
 
-    virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels)
+    virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
@@ -71,10 +92,11 @@
         remote()->transact(DECODE_URL, data, &reply);
         *pSampleRate = uint32_t(reply.readInt32());
         *pNumChannels = reply.readInt32();
+        *pFormat = reply.readInt32();
         return interface_cast<IMemory>(reply.readStrongBinder());
     }
 
-    virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels)
+    virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
@@ -84,6 +106,7 @@
         remote()->transact(DECODE_FD, data, &reply);
         *pSampleRate = uint32_t(reply.readInt32());
         *pNumChannels = reply.readInt32();
+        *pFormat = reply.readInt32();
         return interface_cast<IMemory>(reply.readStrongBinder());
     }
 };
@@ -127,9 +150,11 @@
             const char* url = data.readCString();
             uint32_t sampleRate;
             int numChannels;
-            sp<IMemory> player = decode(url, &sampleRate, &numChannels);
+            int format;
+            sp<IMemory> player = decode(url, &sampleRate, &numChannels, &format);
             reply->writeInt32(sampleRate);
             reply->writeInt32(numChannels);
+            reply->writeInt32(format);
             reply->writeStrongBinder(player->asBinder());
             return NO_ERROR;
         } break;
@@ -140,12 +165,28 @@
             int64_t length = data.readInt64();
             uint32_t sampleRate;
             int numChannels;
-            sp<IMemory> player = decode(fd, offset, length, &sampleRate, &numChannels);
+            int format;
+            sp<IMemory> player = decode(fd, offset, length, &sampleRate, &numChannels, &format);
             reply->writeInt32(sampleRate);
             reply->writeInt32(numChannels);
+            reply->writeInt32(format);
             reply->writeStrongBinder(player->asBinder());
             return NO_ERROR;
         } break;
+        case CREATE_MEDIA_RECORDER: {
+            CHECK_INTERFACE(IMediaPlayerService, data, reply);
+            pid_t pid = data.readInt32();
+            sp<IMediaRecorder> recorder = createMediaRecorder(pid);
+            reply->writeStrongBinder(recorder->asBinder());
+            return NO_ERROR;
+        } break;
+        case CREATE_METADATA_RETRIEVER: {
+            CHECK_INTERFACE(IMediaPlayerService, data, reply);
+            pid_t pid = data.readInt32();
+            sp<IMediaMetadataRetriever> retriever = createMetadataRetriever(pid);
+            reply->writeStrongBinder(retriever->asBinder());
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp
new file mode 100644
index 0000000..1f6d599
--- /dev/null
+++ b/media/libmedia/IMediaRecorder.cpp
@@ -0,0 +1,376 @@
+/*
+ **
+ ** Copyright 2008, HTC Inc.
+ **
+ ** 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 "IMediaRecorder"
+#include <utils/Log.h>
+#include <utils/Parcel.h>
+#include <ui/ISurface.h>
+#include <ui/ICamera.h>
+#include <media/IMediaRecorder.h>
+
+namespace android {
+
+enum {
+    RELEASE = IBinder::FIRST_CALL_TRANSACTION,
+    INIT,
+    CLOSE,
+    RESET,
+    STOP,
+    START,
+    PREPARE,
+    GET_MAX_AMPLITUDE,
+    SET_VIDEO_SOURCE,
+    SET_AUDIO_SOURCE,
+    SET_OUTPUT_FORMAT,
+    SET_VIDEO_ENCODER,
+    SET_AUDIO_ENCODER,
+    SET_OUTPUT_FILE,
+    SET_VIDEO_SIZE,
+    SET_VIDEO_FRAMERATE,
+    SET_PREVIEW_SURFACE,
+    SET_CAMERA
+};
+
+class BpMediaRecorder: public BpInterface<IMediaRecorder>
+{
+public:
+    BpMediaRecorder(const sp<IBinder>& impl)
+    : BpInterface<IMediaRecorder>(impl)
+    {
+    }
+
+    status_t setCamera(const sp<ICamera>& camera)
+    {
+        LOGV("setCamera(%p)", camera.get());
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        data.writeStrongBinder(camera->asBinder());
+        remote()->transact(SET_CAMERA, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t setPreviewSurface(const sp<ISurface>& surface)
+    {
+        LOGV("setPreviewSurface(%p)", surface.get());
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        data.writeStrongBinder(surface->asBinder());
+        remote()->transact(SET_PREVIEW_SURFACE, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t init()
+    {
+        LOGV("init");
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        remote()->transact(INIT, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t setVideoSource(int vs)
+    {
+        LOGV("setVideoSource(%d)", vs);
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        data.writeInt32(vs);
+        remote()->transact(SET_VIDEO_SOURCE, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t setAudioSource(int as)
+    {
+        LOGV("setAudioSource(%d)", as);
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        data.writeInt32(as);
+        remote()->transact(SET_AUDIO_SOURCE, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t setOutputFormat(int of)
+    {
+        LOGV("setOutputFormat(%d)", of);
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        data.writeInt32(of);
+        remote()->transact(SET_OUTPUT_FORMAT, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t setVideoEncoder(int ve)
+    {
+        LOGV("setVideoEncoder(%d)", ve);
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        data.writeInt32(ve);
+        remote()->transact(SET_VIDEO_ENCODER, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t setAudioEncoder(int ae)
+    {
+        LOGV("setAudioEncoder(%d)", ae);
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        data.writeInt32(ae);
+        remote()->transact(SET_AUDIO_ENCODER, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t setOutputFile(const char* path)
+    {
+        LOGV("setOutputFile(%s)", path);
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        data.writeCString(path);
+        remote()->transact(SET_OUTPUT_FILE, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t setVideoSize(int width, int height)
+    {
+        LOGV("setVideoSize(%dx%d)", width, height);
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        data.writeInt32(width);
+        data.writeInt32(height);
+        remote()->transact(SET_VIDEO_SIZE, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t setVideoFrameRate(int frames_per_second)
+    {
+        LOGV("setVideoFrameRate(%d)", frames_per_second);
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        data.writeInt32(frames_per_second);
+        remote()->transact(SET_VIDEO_FRAMERATE, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t prepare()
+    {
+        LOGV("prepare");
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        remote()->transact(PREPARE, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t getMaxAmplitude(int* max)
+    {
+        LOGV("getMaxAmplitude");
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        remote()->transact(GET_MAX_AMPLITUDE, data, &reply);
+        *max = reply.readInt32();
+        return reply.readInt32();
+    }
+
+    status_t start()
+    {
+        LOGV("start");
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        remote()->transact(START, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t stop()
+    {
+        LOGV("stop");
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        remote()->transact(STOP, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t reset()
+    {
+        LOGV("reset");
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        remote()->transact(RESET, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t close()
+    {
+        LOGV("close");
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        remote()->transact(CLOSE, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t release()
+    {
+        LOGV("release");
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        remote()->transact(RELEASE, data, &reply);
+        return reply.readInt32();
+    }
+};
+
+IMPLEMENT_META_INTERFACE(MediaRecorder, "android.hardware.IMediaRecorder");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+    do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+        LOGW("Call incorrectly routed to " #interface); \
+        return PERMISSION_DENIED; \
+    } } while (0)
+
+status_t BnMediaRecorder::onTransact(
+                                     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+        case RELEASE: {
+            LOGV("RELEASE");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            reply->writeInt32(release());
+            return NO_ERROR;
+        } break;
+        case INIT: {
+            LOGV("INIT");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            reply->writeInt32(init());
+            return NO_ERROR;
+        } break;
+        case CLOSE: {
+            LOGV("CLOSE");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            reply->writeInt32(close());
+            return NO_ERROR;
+        } break;
+        case RESET: {
+            LOGV("RESET");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            reply->writeInt32(reset());
+            return NO_ERROR;
+        } break;
+        case STOP: {
+            LOGV("STOP");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            reply->writeInt32(stop());
+            return NO_ERROR;
+        } break;
+        case START: {
+            LOGV("START");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            reply->writeInt32(start());
+            return NO_ERROR;
+        } break;
+        case PREPARE: {
+            LOGV("PREPARE");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            reply->writeInt32(prepare());
+            return NO_ERROR;
+        } break;
+        case GET_MAX_AMPLITUDE: {
+            LOGV("GET_MAX_AMPLITUDE");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            int max = 0;
+            status_t ret = getMaxAmplitude(&max);
+            reply->writeInt32(max);
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        } break;
+        case SET_VIDEO_SOURCE: {
+            LOGV("SET_VIDEO_SOURCE");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            int vs = data.readInt32();
+            reply->writeInt32(setVideoSource(vs));
+            return NO_ERROR;
+        } break;
+        case SET_AUDIO_SOURCE: {
+            LOGV("SET_AUDIO_SOURCE");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            int as = data.readInt32();
+            reply->writeInt32(setAudioSource(as));
+            return NO_ERROR;
+        } break;
+        case SET_OUTPUT_FORMAT: {
+            LOGV("SET_OUTPUT_FORMAT");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            int of = data.readInt32();
+            reply->writeInt32(setOutputFormat(of));
+            return NO_ERROR;
+        } break;
+        case SET_VIDEO_ENCODER: {
+            LOGV("SET_VIDEO_ENCODER");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            int ve = data.readInt32();
+            reply->writeInt32(setVideoEncoder(ve));
+            return NO_ERROR;
+        } break;
+        case SET_AUDIO_ENCODER: {
+            LOGV("SET_AUDIO_ENCODER");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            int ae = data.readInt32();
+            reply->writeInt32(setAudioEncoder(ae));
+            return NO_ERROR;
+
+        } break;
+        case SET_OUTPUT_FILE: {
+            LOGV("SET_OUTPUT_FILE");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            const char* path = data.readCString();
+            reply->writeInt32(setOutputFile(path));
+            return NO_ERROR;
+        } break;
+        case SET_VIDEO_SIZE: {
+            LOGV("SET_VIDEO_SIZE");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            int width = data.readInt32();
+            int height = data.readInt32();
+            reply->writeInt32(setVideoSize(width, height));
+            return NO_ERROR;
+        } break;
+        case SET_VIDEO_FRAMERATE: {
+            LOGV("SET_VIDEO_FRAMERATE");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            int frames_per_second = data.readInt32();
+            reply->writeInt32(setVideoFrameRate(frames_per_second));
+            return NO_ERROR;
+        } break;
+        case SET_PREVIEW_SURFACE: {
+            LOGV("SET_PREVIEW_SURFACE");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            sp<ISurface> surface = interface_cast<ISurface>(data.readStrongBinder());
+            reply->writeInt32(setPreviewSurface(surface));
+            return NO_ERROR;
+        } break;
+        case SET_CAMERA: {
+            LOGV("SET_CAMERA");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            sp<ICamera> camera = interface_cast<ICamera>(data.readStrongBinder());
+            reply->writeInt32(setCamera(camera));
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
index 89ab2be..0dee1f6 100644
--- a/media/libmedia/ToneGenerator.cpp
+++ b/media/libmedia/ToneGenerator.cpp
@@ -88,57 +88,35 @@
 //
 ////////////////////////////////////////////////////////////////////////////////
 ToneGenerator::ToneGenerator(int streamType, float volume) {
-    const sp<IAudioFlinger>& lpAudioFlinger = AudioSystem::get_audio_flinger();
 
     LOGV("ToneGenerator constructor: streamType=%d, volume=%f\n", streamType, volume);
 
     mState = TONE_IDLE;
+
+    if (AudioSystem::getOutputSamplingRate(&mSamplingRate) != NO_ERROR) {
+        LOGE("Unable to marshal AudioFlinger");
+        return;
+    }
+    if (AudioSystem::getOutputFrameCount(&mBufferSize) != NO_ERROR) {
+        LOGE("Unable to marshal AudioFlinger");
+        return;
+    }
+    mStreamType = streamType;
+    mVolume = volume;
     mpAudioTrack = 0;
     mpToneDesc = 0;
     mpNewToneDesc = 0;
 
-    if (lpAudioFlinger == 0) {
-        LOGE("Unable to marshal AudioFlinger");
-        goto ToneGenerator_exit;
+    if (initAudioTrack()) {
+        LOGV("ToneGenerator INIT OK, time: %d\n", (unsigned int)(systemTime()/1000000));
+    } else {
+        LOGV("!!!ToneGenerator INIT FAILED!!!\n");
     }
-
-    mSamplingRate = lpAudioFlinger->sampleRate();
-
-    mVolume = volume;
-    // Open audio track in mono, PCM 16bit, default sampling rate, 2 buffers
-    mpAudioTrack
-            = new AudioTrack(streamType, 0, AudioSystem::PCM_16_BIT, 1, NUM_PCM_BUFFERS, 0, audioCallback, this);
-
-    if (mpAudioTrack == 0) {
-        LOGE("AudioTrack allocation failed");
-        goto ToneGenerator_exit;
-    }
-    LOGV("Create Track: %p\n", mpAudioTrack);
-
-    if (mpAudioTrack->initCheck() != NO_ERROR) {
-        LOGE("AudioTrack->initCheck failed");
-        goto ToneGenerator_exit;
-    }
-
-    mpAudioTrack->setVolume(volume, volume);
-
-    LOGV("ToneGenerator INIT OK, time: %d\n", (unsigned int)(systemTime()/1000000));
-
-    mState = TONE_INIT;
-
-    return;
-
-ToneGenerator_exit:
-
-    // Cleanup
-    if (mpAudioTrack) {
-        LOGV("Delete Track I: %p\n", mpAudioTrack);
-        delete mpAudioTrack;
-    }
-
-    LOGV("!!!ToneGenerator INIT FAILED!!!\n");
 }
 
+
+
+
 ////////////////////////////////////////////////////////////////////////////////
 //
 //    Method:        ToneGenerator::~ToneGenerator()
@@ -179,9 +157,16 @@
 bool ToneGenerator::startTone(int toneType) {
     bool lResult = false;
 
-    if (mState == TONE_IDLE || toneType >= NUM_TONES)
+    if (toneType >= NUM_TONES)
         return lResult;
 
+    if (mState == TONE_IDLE) {
+        LOGV("startTone: try to re-init AudioTrack");
+        if (!initAudioTrack()) {
+            return lResult;
+        }
+    }
+
     LOGV("startTone\n");
 
     mLock.lock();
@@ -198,8 +183,10 @@
             mpAudioTrack->start();
             mLock.lock();
             if (mState == TONE_STARTING) {
-                if (mWaitCbkCond.waitRelative(mLock, seconds(1)) != NO_ERROR)
+                if (mWaitCbkCond.waitRelative(mLock, seconds(1)) != NO_ERROR) {
                     LOGE("--- timed out");
+                    mState = TONE_IDLE;
+                }
             }
 
             if (mState == TONE_PLAYING)
@@ -216,6 +203,7 @@
             LOGV("cond received");
         } else {
             LOGE("--- timed out");
+            mState = TONE_IDLE;
         }
     }
     mLock.unlock();
@@ -250,7 +238,8 @@
             LOGV("track stop complete, time %d", (unsigned int)(systemTime()/1000000));
         } else {
             LOGE("--- timed out");
-            mState = TONE_INIT;
+            mState = TONE_IDLE;
+            mpAudioTrack->stop();
         }
     }
 
@@ -262,6 +251,62 @@
 //---------------------------------- private methods ---------------------------
 
 
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+//    Method:        ToneGenerator::initAudioTrack()
+//
+//    Description:    Allocates and configures AudioTrack used for PCM output.
+//
+//    Input:
+//        none
+//
+//    Output:
+//        none
+//
+////////////////////////////////////////////////////////////////////////////////
+bool ToneGenerator::initAudioTrack() {
+
+    if (mpAudioTrack) {
+        delete mpAudioTrack;
+        mpAudioTrack = 0;
+    }
+
+   // Open audio track in mono, PCM 16bit, default sampling rate, 2 buffers of
+    mpAudioTrack
+            = new AudioTrack(mStreamType, 0, AudioSystem::PCM_16_BIT, 1, NUM_PCM_BUFFERS*mBufferSize, 0, audioCallback, this, mBufferSize);
+
+    if (mpAudioTrack == 0) {
+        LOGE("AudioTrack allocation failed");
+        goto initAudioTrack_exit;
+    }
+    LOGV("Create Track: %p\n", mpAudioTrack);
+
+    if (mpAudioTrack->initCheck() != NO_ERROR) {
+        LOGE("AudioTrack->initCheck failed");
+        goto initAudioTrack_exit;
+    }
+
+    mpAudioTrack->setVolume(mVolume, mVolume);
+
+    mState = TONE_INIT;
+
+    return true;
+
+initAudioTrack_exit:
+
+    // Cleanup
+    if (mpAudioTrack) {
+        LOGV("Delete Track I: %p\n", mpAudioTrack);
+        delete mpAudioTrack;
+        mpAudioTrack = 0;
+    }
+
+    return false;
+}
+
+
 ////////////////////////////////////////////////////////////////////////////////
 //
 //    Method:        ToneGenerator::audioCallback()
@@ -278,19 +323,24 @@
 //        returned value: always true.
 //
 ////////////////////////////////////////////////////////////////////////////////
-void ToneGenerator::audioCallback(void* user, const AudioTrack::Buffer& info) {
+void ToneGenerator::audioCallback(int event, void* user, void *info) {
+    
+    if (event != AudioTrack::EVENT_MORE_DATA) return;
+    
+    const AudioTrack::Buffer *buffer = static_cast<const AudioTrack::Buffer *>(info);
     ToneGenerator *lpToneGen = static_cast<ToneGenerator *>(user);
-    short *lpOut = info.i16;
-    unsigned int lReqSmp = info.size/sizeof(short);
+    short *lpOut = buffer->i16;
+    unsigned int lReqSmp = buffer->size/sizeof(short);
     unsigned int lGenSmp;
     unsigned int lWaveCmd = WaveGenerator::WAVEGEN_CONT;
     bool lSignal = false;
 
+    if (buffer->size == 0) return;
 
     lpToneGen->mLock.lock();
 
     // Clear output buffer: WaveGenerator accumulates into lpOut buffer
-    memset(lpOut, 0, info.size);
+    memset(lpOut, 0, buffer->size);
 
     // Update pcm frame count and end time (current time at the end of this process)
     lpToneGen->mTotalSmp += lReqSmp;
@@ -317,8 +367,11 @@
         goto audioCallback_Exit;
     }
 
-    // Exit if to sequence is over
+    // Exit if tone sequence is over
     if (lpToneGen->mpToneDesc->segments[lpToneGen->mCurSegment] == 0) {
+        if (lpToneGen->mState == TONE_PLAYING) {
+            lpToneGen->mState = TONE_STOPPING;            
+        }
         goto audioCallback_Exit;
     }
 
@@ -327,7 +380,7 @@
 
         LOGV("End Segment, time: %d\n", (unsigned int)(systemTime()/1000000));
 
-        lGenSmp = lReqSmp; 
+        lGenSmp = lReqSmp;
 
         if (lpToneGen->mCurSegment & 0x0001) {
             // If odd segment,  OFF -> ON transition : reset wave generator
diff --git a/media/libmedia/mediametadataretriever.cpp b/media/libmedia/mediametadataretriever.cpp
index 9cbafbc..09afc6c 100644
--- a/media/libmedia/mediametadataretriever.cpp
+++ b/media/libmedia/mediametadataretriever.cpp
@@ -15,168 +15,174 @@
 ** limitations under the License.
 */
 
-#include <media/mediametadataretriever.h>
-
-#ifdef LOG_TAG
-#undef LOG_TAG
+//#define LOG_NDEBUG 0
 #define LOG_TAG "MediaMetadataRetriever"
-#endif
 
+#include <utils/IServiceManager.h>
+#include <utils/IPCThreadState.h>
+#include <media/mediametadataretriever.h>
+#include <media/IMediaPlayerService.h>
 #include <utils/Log.h>
 #include <dlfcn.h>
 
 namespace android {
 
-// Factory class function in shared libpvplayer.so
-typedef MediaMetadataRetrieverImpl* (*createRetriever_f)();
+// client singleton for binder interface to service
+Mutex MediaMetadataRetriever::sServiceLock;
+sp<IMediaPlayerService> MediaMetadataRetriever::sService;
+sp<MediaMetadataRetriever::DeathNotifier> MediaMetadataRetriever::sDeathNotifier;
 
-MediaMetadataRetrieverImpl *MediaMetadataRetriever::mRetriever = NULL;
-void                       *MediaMetadataRetriever::mLibHandler = NULL;
-
-void MediaMetadataRetriever::create()
+const sp<IMediaPlayerService>& MediaMetadataRetriever::getService()
 {
-    // Load libpvplayer library once and only once.
-    if (!mLibHandler) {
-        mLibHandler = dlopen("libopencoreplayer.so", RTLD_NOW);
-        if (!mLibHandler) {
-            LOGE("setDataSource: dlopen failed on libopencoreplayer.so");
-            return;
+    Mutex::Autolock lock(sServiceLock);
+    if (sService.get() == 0) {
+        sp<IServiceManager> sm = defaultServiceManager();
+        sp<IBinder> binder;
+        do {
+            binder = sm->getService(String16("media.player"));
+            if (binder != 0) {
+                break;
+            }
+            LOGW("MediaPlayerService not published, waiting...");
+            usleep(500000); // 0.5 s
+        } while(true);
+        if (sDeathNotifier == NULL) {
+            sDeathNotifier = new DeathNotifier();
         }
+        binder->linkToDeath(sDeathNotifier);
+        sService = interface_cast<IMediaPlayerService>(binder);
     }
-    
-    // Each time create a new MediaMetadataRetrieverImpl object.
-    if (mRetriever) {
-        delete mRetriever;
-    }
-    createRetriever_f createRetriever = reinterpret_cast<createRetriever_f>(dlsym(mLibHandler, "createRetriever"));
-    if (!createRetriever) {
-        LOGE("setDataSource: dlsym failed on createRetriever in libpvplayer.so");
+    LOGE_IF(sService == 0, "no MediaPlayerService!?");
+    return sService;
+}
+
+MediaMetadataRetriever::MediaMetadataRetriever()
+{
+    LOGV("constructor");
+    const sp<IMediaPlayerService>& service(getService());
+    if (service == 0) {
+        LOGE("failed to obtain MediaMetadataRetrieverService");
         return;
     }
-    mRetriever = createRetriever();
-    if (!mRetriever) {
-        LOGE("setDataSource: createRetriever failed in libpvplayer.so");
+    sp<IMediaMetadataRetriever> retriever(service->createMetadataRetriever(getpid()));
+    if (retriever == 0) {
+        LOGE("failed to create IMediaMetadataRetriever object from server");
+    }
+    mRetriever = retriever;
+}
+
+MediaMetadataRetriever::~MediaMetadataRetriever()
+{
+    LOGV("destructor");
+    disconnect();
+    IPCThreadState::self()->flushCommands();
+}
+
+void MediaMetadataRetriever::disconnect()
+{
+    LOGV("disconnect");
+    sp<IMediaMetadataRetriever> retriever;
+    {
+        Mutex::Autolock _l(mLock);
+        retriever = mRetriever;
+        mRetriever.clear();
+    }
+    if (retriever != 0) {
+        retriever->disconnect();
     }
 }
 
 status_t MediaMetadataRetriever::setDataSource(const char* srcUrl)
 {
+    LOGV("setDataSource");
+    if (mRetriever == 0) {
+        LOGE("retriever is not initialized");
+        return INVALID_OPERATION;
+    }
     if (srcUrl == NULL) {
+        LOGE("data source is a null pointer");
         return UNKNOWN_ERROR;
     }
-    
-    if (mRetriever) {
-        return mRetriever->setDataSource(srcUrl);
+    LOGV("data source (%s)", srcUrl);
+    return mRetriever->setDataSource(srcUrl);
+}
+
+status_t MediaMetadataRetriever::setDataSource(int fd, int64_t offset, int64_t length)
+{
+    LOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
+    if (mRetriever == 0) {
+        LOGE("retriever is not initialized");
+        return INVALID_OPERATION;
     }
-    return UNKNOWN_ERROR;
+    if (fd < 0 || offset < 0 || length < 0) {
+        LOGE("Invalid negative argument");
+        return UNKNOWN_ERROR;
+    }
+    return mRetriever->setDataSource(fd, offset, length);
+}
+
+status_t MediaMetadataRetriever::setMode(int mode)
+{
+    LOGV("setMode(%d)", mode);
+    if (mRetriever == 0) {
+        LOGE("retriever is not initialized");
+        return INVALID_OPERATION;
+    }
+    return mRetriever->setMode(mode);
+}
+
+status_t MediaMetadataRetriever::getMode(int* mode)
+{
+    LOGV("getMode");
+    if (mRetriever == 0) {
+        LOGE("retriever is not initialized");
+        return INVALID_OPERATION;
+    }
+    return mRetriever->getMode(mode);
+}
+
+sp<IMemory> MediaMetadataRetriever::captureFrame()
+{
+    LOGV("captureFrame");
+    if (mRetriever == 0) {
+        LOGE("retriever is not initialized");
+        return NULL;
+    }
+    return mRetriever->captureFrame();
 }
 
 const char* MediaMetadataRetriever::extractMetadata(int keyCode)
 {
-    if (mRetriever) {
-        return mRetriever->extractMetadata(keyCode);
-    }
-    return NULL;
-}
-
-MediaAlbumArt* MediaMetadataRetriever::extractAlbumArt()
-{
-    if (mRetriever) {
-        return mRetriever->extractAlbumArt();
-    }
-    return NULL;
-}
-
-SkBitmap* MediaMetadataRetriever::captureFrame()
-{
-    if (mRetriever) {
-        return mRetriever->captureFrame();
-    }
-    return NULL;
-}
-
-void MediaMetadataRetriever::setMode(int mode)
-{
-    if (mRetriever) {
-        mRetriever->setMode(mode);
-    }
-}
-
-void MediaMetadataRetriever::release()
-{
-    if (!mLibHandler) {
-        dlclose(mLibHandler);
-        mLibHandler = NULL;
-    }
-    if (!mRetriever) {
-        delete mRetriever;
-        mRetriever = NULL;
-    }
-}
-
-void MediaAlbumArt::clearData() {
-    if (data != NULL) {
-        delete []data;
-        data = NULL;
-    }
-    length = 0;
-}
-
-
-MediaAlbumArt::MediaAlbumArt(const char* url)
-{
-    length = 0;
-    data = NULL;
-    FILE *in = fopen(url, "r");
-    if (!in) {
-        LOGE("extractExternalAlbumArt: Failed to open external album art url: %s.", url);
-        return;
-    }
-    fseek(in, 0, SEEK_END);
-    length = ftell(in);  // Allocating buffer of size equals to the external file size.
-    if (length == 0 || (data = new char[length]) == NULL) {
-        if (length == 0) {
-            LOGE("extractExternalAlbumArt: External album art url: %s has a size of 0.", url);
-        } else if (data == NULL) {
-            LOGE("extractExternalAlbumArt: No enough memory for storing the retrieved album art.");
-            length = 0;
-        }
-        fclose(in);
-        return;
-    }
-    rewind(in);
-    if (fread(data, 1, length, in) != length) {  // Read failed.
-        length = 0;
-        delete []data;
-        data = NULL;
-        LOGE("extractExternalAlbumArt: Failed to retrieve the contents of an external album art.");
-    }
-    fclose(in);
-}
-
-status_t MediaAlbumArt::setData(unsigned int len, const char* buf) {
-    clearData();
-    length = len;
-    data = copyData(len, buf);
-    return (data != NULL)? OK: UNKNOWN_ERROR;
-}
-
-char* MediaAlbumArt::copyData(unsigned int len, const char* buf) {
-    if (len == 0 || !buf) {
-        if (len == 0) {
-            LOGE("copyData: Length is 0.");
-        } else if (!buf) {
-            LOGE("copyData: buf is NULL pointer");
-        }
+    LOGV("extractMetadata(%d)", keyCode);
+    if (mRetriever == 0) {
+        LOGE("retriever is not initialized");
         return NULL;
     }
-    char* copy = new char[len];
-    if (!copy) {
-        LOGE("copyData: No enough memory to copy out the data.");
+    return mRetriever->extractMetadata(keyCode);
+}
+
+sp<IMemory> MediaMetadataRetriever::extractAlbumArt()
+{
+    LOGV("extractAlbumArt");
+    if (mRetriever == 0) {
+        LOGE("retriever is not initialized");
         return NULL;
     }
-    memcpy(copy, buf, len);
-    return copy;
+    return mRetriever->extractAlbumArt();
+}
+
+void MediaMetadataRetriever::DeathNotifier::binderDied(const wp<IBinder>& who) {
+    Mutex::Autolock lock(MediaMetadataRetriever::sServiceLock);
+    MediaMetadataRetriever::sService.clear();
+    LOGW("MediaMetadataRetriever server died!");
+}
+
+MediaMetadataRetriever::DeathNotifier::~DeathNotifier()
+{
+    Mutex::Autolock lock(sServiceLock);
+    if (sService != 0) {
+        sService->asBinder()->unlinkToDeath(this);
+    }
 }
 
 }; // namespace android
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 736d84a..ebdbda8 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -28,22 +28,23 @@
 #include <utils/IPCThreadState.h>
 
 #include <media/mediaplayer.h>
-#include <libsonivox/eas.h>
+#include <media/AudioTrack.h>
 
 #include <utils/MemoryBase.h>
 
 namespace android {
 
 // client singleton for binder interface to service
-Mutex MediaPlayer::mServiceLock;
-sp<IMediaPlayerService> MediaPlayer::mMediaPlayerService;
-sp<MediaPlayer::DeathNotifier> MediaPlayer::mDeathNotifier;
+Mutex MediaPlayer::sServiceLock;
+sp<IMediaPlayerService> MediaPlayer::sMediaPlayerService;
+sp<MediaPlayer::DeathNotifier> MediaPlayer::sDeathNotifier;
+SortedVector< wp<MediaPlayer> > MediaPlayer::sObitRecipients;
 
 // establish binder interface to service
 const sp<IMediaPlayerService>& MediaPlayer::getMediaPlayerService()
 {
-    Mutex::Autolock _l(mServiceLock);
-    if (mMediaPlayerService.get() == 0) {
+    Mutex::Autolock _l(sServiceLock);
+    if (sMediaPlayerService.get() == 0) {
         sp<IServiceManager> sm = defaultServiceManager();
         sp<IBinder> binder;
         do {
@@ -53,14 +54,26 @@
             LOGW("MediaPlayerService not published, waiting...");
             usleep(500000); // 0.5 s
         } while(true);
-        if (mDeathNotifier == NULL) {
-            mDeathNotifier = new DeathNotifier();
+        if (sDeathNotifier == NULL) {
+            sDeathNotifier = new DeathNotifier();
         }
-        binder->linkToDeath(mDeathNotifier);
-        mMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
+        binder->linkToDeath(sDeathNotifier);
+        sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
     }
-    LOGE_IF(mMediaPlayerService==0, "no MediaPlayerService!?");
-    return mMediaPlayerService;
+    LOGE_IF(sMediaPlayerService==0, "no MediaPlayerService!?");
+    return sMediaPlayerService;
+}
+
+void MediaPlayer::addObitRecipient(const wp<MediaPlayer>& recipient)
+{
+    Mutex::Autolock _l(sServiceLock);
+    sObitRecipients.add(recipient);
+}
+
+void MediaPlayer::removeObitRecipient(const wp<MediaPlayer>& recipient)
+{
+    Mutex::Autolock _l(sServiceLock);
+    sObitRecipients.remove(recipient);
 }
 
 MediaPlayer::MediaPlayer()
@@ -77,11 +90,18 @@
     mPrepareStatus = NO_ERROR;
     mLoop = false;
     mLeftVolume = mRightVolume = 1.0;
+    mVideoWidth = mVideoHeight = 0;
+}
+
+void MediaPlayer::onFirstRef()
+{
+    addObitRecipient(this);
 }
 
 MediaPlayer::~MediaPlayer()
 {
     LOGV("destructor");
+    removeObitRecipient(this);
     disconnect();
     IPCThreadState::self()->flushCommands();
 }
@@ -98,7 +118,6 @@
 
     if (p != 0) {
         p->disconnect();
-        p->asBinder()->unlinkToDeath(this);
     }
 }
 
@@ -108,6 +127,7 @@
     mDuration = -1;
     mCurrentPosition = -1;
     mSeekPosition = -1;
+    mVideoWidth = mVideoHeight = 0;
 }
 
 status_t MediaPlayer::setListener(const sp<MediaPlayerListener>& listener)
@@ -136,7 +156,6 @@
         mPlayer = player;
         if (player != 0) {
             mCurrentState = MEDIA_PLAYER_INITIALIZED;
-            player->asBinder()->linkToDeath(this);
             err = NO_ERROR;
         } else {
             LOGE("Unable to to create media player");
@@ -145,8 +164,8 @@
 
     if (p != 0) {
         p->disconnect();
-        p->asBinder()->unlinkToDeath(this);
     }
+
     return err;
 }
 
@@ -307,22 +326,18 @@
 {
     LOGV("getVideoWidth");
     Mutex::Autolock _l(mLock);
-    if (mPlayer != 0) {
-        int h;
-        return mPlayer->getVideoSize(w, &h);
-    }
-    return INVALID_OPERATION;
+    if (mPlayer == 0) return INVALID_OPERATION;
+    *w = mVideoWidth;
+    return NO_ERROR;
 }
 
 status_t MediaPlayer::getVideoHeight(int *h)
 {
     LOGV("getVideoHeight");
     Mutex::Autolock _l(mLock);
-    if (mPlayer != 0) {
-        int w;
-        return mPlayer->getVideoSize(&w, h);
-    }
-    return INVALID_OPERATION;
+    if (mPlayer == 0) return INVALID_OPERATION;
+    *h = mVideoHeight;
+    return NO_ERROR;
 }
 
 status_t MediaPlayer::getCurrentPosition(int *msec)
@@ -405,6 +420,7 @@
     if (mPlayer != 0) {
         status_t ret = mPlayer->reset();
         if (ret != NO_ERROR) {
+            LOGE("reset() failed with return code (%d)", ret);
             mCurrentState = MEDIA_PLAYER_STATE_ERROR;
             ret = UNKNOWN_ERROR;
         } else {
@@ -443,6 +459,16 @@
     return OK;
 }
 
+bool MediaPlayer::isLooping() {
+    LOGV("isLooping");
+    Mutex::Autolock _l(mLock);
+    if (mPlayer != 0) {
+        return mLoop;
+    }
+    LOGV("isLooping: no active player");
+    return false;
+}
+
 status_t MediaPlayer::setVolume(float leftVolume, float rightVolume)
 {
     LOGV("MediaPlayer::setVolume(%f, %f)", leftVolume, rightVolume);
@@ -466,6 +492,7 @@
     mLock.lock();
     if (mPlayer == 0) {
         LOGV("notify(%d, %d, %d) callback on disconnected mediaplayer", msg, ext1, ext2);
+        mLock.unlock();   // release the lock when done.
         return;
     }
 
@@ -489,7 +516,8 @@
         }
         break;
     case MEDIA_ERROR:
-        LOGV("error (%d, %d)", ext1, ext2);
+        // Always log errors
+        LOGE("error (%d, %d)", ext1, ext2);
         mCurrentState = MEDIA_PLAYER_STATE_ERROR;
         if (mPrepareSync)
         {
@@ -515,6 +543,11 @@
     case MEDIA_BUFFERING_UPDATE:
         LOGV("buffering %d", ext1);
         break;
+    case MEDIA_SET_VIDEO_SIZE:
+        LOGV("New video size %d x %d", ext1, ext2);
+        mVideoWidth = ext1;
+        mVideoHeight = ext2;
+        break;
     default:
         LOGV("unrecognized message: (%d, %d, %d)", msg, ext1, ext2);
         break;
@@ -532,32 +565,45 @@
     }
 }
 
-void MediaPlayer::binderDied(const wp<IBinder>& who) {
-    LOGW("IMediaplayer died");
-    notify(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED, 0);
-}
-
 void MediaPlayer::DeathNotifier::binderDied(const wp<IBinder>& who) {
-    Mutex::Autolock _l(MediaPlayer::mServiceLock);
-    MediaPlayer::mMediaPlayerService.clear();
     LOGW("MediaPlayer server died!");
+
+    // Need to do this with the lock held
+    SortedVector< wp<MediaPlayer> > list;
+    {
+        Mutex::Autolock _l(MediaPlayer::sServiceLock);
+        MediaPlayer::sMediaPlayerService.clear();
+        list = sObitRecipients;
+    }
+
+    // Notify application when media server dies.
+    // Don't hold the static lock during callback in case app
+    // makes a call that needs the lock.
+    size_t count = list.size();
+    for (size_t iter = 0; iter < count; ++iter) {
+        sp<MediaPlayer> player = list[iter].promote();
+        if ((player != 0) && (player->mPlayer != 0)) {
+            player->notify(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED, 0);
+        }
+    }
 }
 
 MediaPlayer::DeathNotifier::~DeathNotifier()
 {
-    Mutex::Autolock _l(mServiceLock);
-    if (mMediaPlayerService != 0) {
-        mMediaPlayerService->asBinder()->unlinkToDeath(this);
+    Mutex::Autolock _l(sServiceLock);
+    sObitRecipients.clear();
+    if (sMediaPlayerService != 0) {
+        sMediaPlayerService->asBinder()->unlinkToDeath(this);
     }
 }
 
-/*static*/ sp<IMemory> MediaPlayer::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels)
+/*static*/ sp<IMemory> MediaPlayer::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
 {
     LOGV("decode(%s)", url);
     sp<IMemory> p;
     const sp<IMediaPlayerService>& service = getMediaPlayerService();
     if (service != 0) {
-        p = mMediaPlayerService->decode(url, pSampleRate, pNumChannels);
+        p = sMediaPlayerService->decode(url, pSampleRate, pNumChannels, pFormat);
     } else {
         LOGE("Unable to locate media service");
     }
@@ -565,13 +611,13 @@
 
 }
 
-/*static*/ sp<IMemory> MediaPlayer::decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels)
+/*static*/ sp<IMemory> MediaPlayer::decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
 {
     LOGV("decode(%d, %lld, %lld)", fd, offset, length);
     sp<IMemory> p;
     const sp<IMediaPlayerService>& service = getMediaPlayerService();
     if (service != 0) {
-        p = mMediaPlayerService->decode(fd, offset, length, pSampleRate, pNumChannels);
+        p = sMediaPlayerService->decode(fd, offset, length, pSampleRate, pNumChannels, pFormat);
     } else {
         LOGE("Unable to locate media service");
     }
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
new file mode 100644
index 0000000..825e145
--- /dev/null
+++ b/media/libmedia/mediarecorder.cpp
@@ -0,0 +1,518 @@
+/*
+ **
+ ** Copyright (c) 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_NDEBUG 0
+#define LOG_TAG "MediaRecorder"
+#include <utils/Log.h>
+#include <ui/Surface.h>
+#include <media/mediarecorder.h>
+#include <utils/IServiceManager.h>
+#include <media/IMediaPlayerService.h>
+#include <media/IMediaRecorder.h>
+
+namespace android {
+
+status_t MediaRecorder::setCamera(const sp<ICamera>& camera)
+{
+    LOGV("setCamera(%p)", camera.get());
+    if(mMediaRecorder == NULL) {
+        LOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_IDLE)) {
+        LOGE("setCamera called in an invalid state(%d)", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setCamera(camera);
+    if (OK != ret) {
+        LOGV("setCamera failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    }
+    return ret;
+}
+
+status_t MediaRecorder::setPreviewSurface(const sp<Surface>& surface)
+{
+    LOGV("setPreviewSurface(%p)", surface.get());
+    if(mMediaRecorder == NULL) {
+        LOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+        LOGE("setPreviewSurface called in an invalid state(%d)", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setPreviewSurface(surface->getISurface());
+    if (OK != ret) {
+        LOGV("setPreviewSurface failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    }
+    return ret;
+}
+
+status_t MediaRecorder::init()
+{
+    LOGV("init");
+    if(mMediaRecorder == NULL) {
+        LOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_IDLE)) {
+        LOGE("init called in an invalid state(%d)", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->init();
+    if (OK != ret) {
+        LOGV("init failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    }
+    mCurrentState = MEDIA_RECORDER_INITIALIZED;
+    return ret;
+}
+
+status_t MediaRecorder::setVideoSource(int vs)
+{
+    LOGV("setVideoSource(%d)", vs);
+    if(mMediaRecorder == NULL) {
+        LOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (mIsVideoSourceSet) {
+        LOGE("video source has already been set");
+        return INVALID_OPERATION;
+    }
+    if (mCurrentState & MEDIA_RECORDER_IDLE) {
+        LOGV("Call init() since the media recorder is not initialized yet");
+        status_t ret = init();
+        if (OK != ret) {
+            return ret;
+        }
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_INITIALIZED)) {
+        LOGE("setVideoSource called in an invalid state(%d)", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setVideoSource(vs);
+    if (OK != ret) {
+        LOGV("setVideoSource failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    }
+    mIsVideoSourceSet = true;
+    return ret;
+}
+
+status_t MediaRecorder::setAudioSource(int as)
+{
+    LOGV("setAudioSource(%d)", as);
+    if(mMediaRecorder == NULL) {
+        LOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (mCurrentState & MEDIA_RECORDER_IDLE) {
+        LOGV("Call init() since the media recorder is not initialized yet");
+        status_t ret = init();
+        if (OK != ret) {
+            return ret;
+        }
+    }
+    if (mIsAudioSourceSet) {
+        LOGE("audio source has already been set");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_INITIALIZED)) {
+        LOGE("setAudioSource called in an invalid state(%d)", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setAudioSource(as);
+    if (OK != ret) {
+        LOGV("setAudioSource failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    }
+    mIsAudioSourceSet = true;
+    return ret;
+}
+
+status_t MediaRecorder::setOutputFormat(int of)
+{
+    LOGV("setOutputFormat(%d)", of);
+    if(mMediaRecorder == NULL) {
+        LOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_INITIALIZED)) {
+        LOGE("setOutputFormat called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setOutputFormat(of);
+    if (OK != ret) {
+        LOGE("setOutputFormat failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    }
+    mCurrentState = MEDIA_RECORDER_DATASOURCE_CONFIGURED;
+    return ret;
+}
+
+status_t MediaRecorder::setVideoEncoder(int ve)
+{
+    LOGV("setVideoEncoder(%d)", ve);
+    if(mMediaRecorder == NULL) {
+        LOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (mIsVideoEncoderSet) {
+        LOGE("video encoder has already been set");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+        LOGE("setVideoEncoder called in an invalid state(%d)", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setVideoEncoder(ve);
+    if (OK != ret) {
+        LOGV("setVideoEncoder failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    }
+    mIsVideoEncoderSet = true;
+    return ret;
+}
+
+status_t MediaRecorder::setAudioEncoder(int ae)
+{
+    LOGV("setAudioEncoder(%d)", ae);
+    if(mMediaRecorder == NULL) {
+        LOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (mIsAudioEncoderSet) {
+        LOGE("audio encoder has already been set");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+        LOGE("setAudioEncoder called in an invalid state(%d)", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setAudioEncoder(ae);
+    if (OK != ret) {
+        LOGV("setAudioEncoder failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    }
+    mIsAudioEncoderSet = true;
+    return ret;
+}
+
+status_t MediaRecorder::setOutputFile(const char* path)
+{
+    LOGV("setOutputFile(%s)", path);
+    if(mMediaRecorder == NULL) {
+        LOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (mIsOutputFileSet) {
+        LOGE("output file has already been set");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+        LOGE("setOutputFile called in an invalid state(%d)", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setOutputFile(path);
+    if (OK != ret) {
+        LOGV("setAudioEncoder failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    }
+    mIsOutputFileSet = true;
+    return ret;
+}
+
+status_t MediaRecorder::setVideoSize(int width, int height)
+{
+    LOGV("setVideoSize(%d, %d)", width, height);
+    if(mMediaRecorder == NULL) {
+        LOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+        LOGE("setVideoSize called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setVideoSize(width, height);
+    if (OK != ret) {
+        LOGE("setVideoSize failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    }
+    return ret;
+}
+
+status_t MediaRecorder::setVideoFrameRate(int frames_per_second)
+{
+    LOGV("setVideoFrameRate(%d)", frames_per_second);
+    if(mMediaRecorder == NULL) {
+        LOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+        LOGE("setVideoFrameRate called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->setVideoFrameRate(frames_per_second);
+    if (OK != ret) {
+        LOGE("setVideoFrameRate failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    }
+    return ret;
+}
+
+status_t MediaRecorder::prepare()
+{
+    LOGV("prepare");
+    if(mMediaRecorder == NULL) {
+        LOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+        LOGE("setVideoFrameRate called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->prepare();
+    if (OK != ret) {
+        LOGE("prepare failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    }
+    mCurrentState = MEDIA_RECORDER_PREPARED;
+    return ret;
+}
+
+status_t MediaRecorder::getMaxAmplitude(int* max)
+{
+    LOGV("getMaxAmplitude");
+    if(mMediaRecorder == NULL) {
+        LOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (mCurrentState & MEDIA_RECORDER_ERROR) {
+        LOGE("setVideoFrameRate called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->getMaxAmplitude(max);
+    if (OK != ret) {
+        LOGE("getMaxAmplitude failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    }
+    return ret;
+}
+
+status_t MediaRecorder::start()
+{
+    LOGV("start");
+    if (mMediaRecorder == NULL) {
+        LOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_PREPARED)) {
+        LOGE("start called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->start();
+    if (OK != ret) {
+        LOGE("start failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    }
+    mCurrentState = MEDIA_RECORDER_RECORDING;
+    return ret;
+}
+
+status_t MediaRecorder::stop()
+{
+    LOGV("stop");
+    if (mMediaRecorder == NULL) {
+        LOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_RECORDING)) {
+        LOGE("stop called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->stop();
+    if (OK != ret) {
+        LOGE("stop failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    }
+    mCurrentState = MEDIA_RECORDER_IDLE;
+    return ret;
+}
+
+// Reset should be OK in any state
+status_t MediaRecorder::reset()
+{
+    LOGV("reset");
+    if (mMediaRecorder == NULL) {
+        LOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    
+    doCleanUp();
+    status_t ret = UNKNOWN_ERROR;
+    switch(mCurrentState) {
+        case MEDIA_RECORDER_IDLE:
+            ret = OK;
+            break;
+
+        case MEDIA_RECORDER_RECORDING:
+        case MEDIA_RECORDER_DATASOURCE_CONFIGURED:
+        case MEDIA_RECORDER_PREPARED:
+        case MEDIA_RECORDER_ERROR: {
+            ret = doReset();
+            if (OK != ret) {
+               return ret;  // No need to continue
+            }
+        }  // Intentional fall through
+        case MEDIA_RECORDER_INITIALIZED:
+            ret = close();
+            break;
+
+        default: {
+            LOGE("Unexpected non-existing state: %d", mCurrentState);
+            break;
+        }
+    }
+    return ret;
+}
+
+status_t MediaRecorder::close()
+{
+    LOGV("close");
+    if (!(mCurrentState & MEDIA_RECORDER_INITIALIZED)) {
+        LOGE("close called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+    status_t ret = mMediaRecorder->close();
+    if (OK != ret) {
+        LOGE("close failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    } else {
+        mCurrentState = MEDIA_RECORDER_IDLE;
+    }
+    return ret;
+}
+
+status_t MediaRecorder::doReset()
+{
+    LOGV("doReset");
+    status_t ret = mMediaRecorder->reset();
+    if (OK != ret) {
+        LOGE("doReset failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return UNKNOWN_ERROR;
+    } else {
+        mCurrentState = MEDIA_RECORDER_INITIALIZED;
+    }
+    return ret;
+}
+
+void MediaRecorder::doCleanUp()
+{
+    LOGV("doCleanUp");
+    mIsAudioSourceSet  = false;
+    mIsVideoSourceSet  = false;
+    mIsAudioEncoderSet = false;
+    mIsVideoEncoderSet = false;
+    mIsOutputFileSet   = false;
+}
+
+// Release should be OK in any state
+status_t MediaRecorder::release()
+{
+    LOGV("release");
+    if (mMediaRecorder != NULL) {
+        return mMediaRecorder->release();
+    }
+    return INVALID_OPERATION;
+}
+
+MediaRecorder::MediaRecorder()
+{
+    LOGV("constructor");
+    sp<IServiceManager> sm = defaultServiceManager();
+    sp<IBinder> binder;
+
+    do {
+        binder = sm->getService(String16("media.player"));
+        if (binder != NULL) {
+            break;
+        }
+        LOGW("MediaPlayerService not published, waiting...");
+        usleep(500000); // 0.5 s
+    } while(true);
+
+    sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
+    if (service != NULL) {
+        mMediaRecorder = service->createMediaRecorder(getpid());
+    }
+
+    mMediaRecorder = service->createMediaRecorder(getpid());
+    if (mMediaRecorder != NULL) {
+        mCurrentState = MEDIA_RECORDER_IDLE;
+    }
+    doCleanUp();
+}
+
+status_t MediaRecorder::initCheck()
+{
+    return mMediaRecorder != 0 ? NO_ERROR : NO_INIT;
+}
+
+MediaRecorder::~MediaRecorder()
+{
+    LOGV("destructor");
+    if (mMediaRecorder != NULL) {
+        mMediaRecorder.clear();
+    }
+}
+
+}; // namespace android
+
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index b3a5747..f710921 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -7,7 +7,9 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=               \
+	MediaRecorderClient.cpp \
 	MediaPlayerService.cpp \
+	MetadataRetrieverClient.cpp \
 	VorbisPlayer.cpp \
 	MidiFile.cpp
 
@@ -21,6 +23,7 @@
 	libvorbisidec \
 	libsonivox \
 	libopencoreplayer \
+	libopencoreauthor \
 	libmedia \
 	libandroid_runtime
 
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index fd5f0ed..5383171 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -34,11 +34,17 @@
 #include <utils/IServiceManager.h>
 #include <utils/MemoryHeapBase.h>
 #include <utils/MemoryBase.h>
+#include <cutils/properties.h>
 
 #include <media/MediaPlayerInterface.h>
+#include <media/mediarecorder.h>
+#include <media/MediaMetadataRetrieverInterface.h>
 #include <media/AudioTrack.h>
 
+#include "MediaRecorderClient.h"
 #include "MediaPlayerService.h"
+#include "MetadataRetrieverClient.h"
+
 #include "MidiFile.h"
 #include "VorbisPlayer.h"
 #include <media/PVPlayer.h>
@@ -72,7 +78,7 @@
     restart continuously.
 */
 #define USE_SIGBUS_HANDLER 0
- 
+
 // TODO: Temp hack until we can register players
 static const char* MIDI_FILE_EXTS[] =
 {
@@ -87,8 +93,10 @@
 
 namespace android {
 
-// TODO: should come from audio driver
-/* static */ const uint32_t MediaPlayerService::AudioOutput::kDriverLatencyInMsecs = 150;
+// TODO: Find real cause of Audio/Video delay in PV framework and remove this workaround
+/* static */ const uint32_t MediaPlayerService::AudioOutput::kAudioVideoDelayMs = 96;
+/* static */ int MediaPlayerService::AudioOutput::mMinBufferCount = 4;
+/* static */ bool MediaPlayerService::AudioOutput::mIsOnEmulator = false;
 
 static struct sigaction oldact;
 static pthread_key_t sigbuskey;
@@ -172,7 +180,7 @@
 
     pthread_key_create(&sigbuskey, NULL);
 
-  
+
 #if USE_SIGBUS_HANDLER
     struct sigaction act;
     memset(&act,0, sizeof act);
@@ -191,6 +199,20 @@
     LOGV("MediaPlayerService destroyed");
 }
 
+sp<IMediaRecorder> MediaPlayerService::createMediaRecorder(pid_t pid)
+{
+    sp<MediaRecorderClient> recorder = new MediaRecorderClient(pid);
+    LOGV("Create new media recorder client from pid %d", pid);
+    return recorder;
+}
+
+sp<IMediaMetadataRetriever> MediaPlayerService::createMetadataRetriever(pid_t pid)
+{
+    sp<MetadataRetrieverClient> retriever = new MetadataRetrieverClient(pid);
+    LOGV("Create new media retriever from pid %d", pid);
+    return retriever;
+}
+
 sp<IMediaPlayer> MediaPlayerService::create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url)
 {
     int32_t connId = android_atomic_inc(&mNextConnId);
@@ -237,8 +259,8 @@
                 mHeap->getBase(), mHeap->getSize(), mHeap->getFlags(), mHeap->getDevice());
         result.append(buffer);
     }
-    snprintf(buffer, 255, "  msec per frame(%f), channel count(%ld), frame count(%ld)\n",
-            mMsecsPerFrame, mChannelCount, mFrameCount);
+    snprintf(buffer, 255, "  msec per frame(%f), channel count(%d), format(%d), frame count(%ld)\n",
+            mMsecsPerFrame, mChannelCount, mFormat, mFrameCount);
     result.append(buffer);
     snprintf(buffer, 255, "  sample rate(%d), size(%d), error(%d), command complete(%s)\n",
             mSampleRate, mSize, mError, mCommandComplete?"true":"false");
@@ -257,8 +279,8 @@
     snprintf(buffer, 255, "  stream type(%d), left - right volume(%f, %f)\n",
             mStreamType, mLeftVolume, mRightVolume);
     result.append(buffer);
-    snprintf(buffer, 255, "  msec per frame(%f), latency (%d), driver latency(%d)\n",
-            mMsecsPerFrame, mLatency, kDriverLatencyInMsecs);
+    snprintf(buffer, 255, "  msec per frame(%f), latency (%d)\n",
+            mMsecsPerFrame, mLatency);
     result.append(buffer);
     ::write(fd, result.string(), result.size());
     if (mTrack != 0) {
@@ -315,7 +337,7 @@
         if (f) {
             while (!feof(f)) {
                 fgets(buffer, SIZE, f);
-                if (strstr(buffer, " /sdcard/") || 
+                if (strstr(buffer, " /sdcard/") ||
                     strstr(buffer, " /system/sounds/") ||
                     strstr(buffer, " /system/media/")) {
                     result.append("  ");
@@ -334,7 +356,7 @@
         if (d) {
             struct dirent *ent;
             while((ent = readdir(d)) != NULL) {
-                if (strcmp(ent->d_name,".") && strcmp(ent->d_name,"..")) { 
+                if (strcmp(ent->d_name,".") && strcmp(ent->d_name,"..")) {
                     snprintf(buffer, SIZE, "/proc/%d/fd/%s", myTid(), ent->d_name);
                     struct stat s;
                     if (lstat(buffer, &s) == 0) {
@@ -350,7 +372,7 @@
                                 } else {
                                     linkto[len] = 0;
                                 }
-                                if (strstr(linkto, "/sdcard/") == linkto || 
+                                if (strstr(linkto, "/sdcard/") == linkto ||
                                     strstr(linkto, "/system/sounds/") == linkto ||
                                     strstr(linkto, "/system/media/") == linkto) {
                                     result.append("  ");
@@ -683,20 +705,6 @@
     return NO_ERROR;
 }
 
-status_t MediaPlayerService::Client::getVideoSize(int *w, int *h)
-{
-    sp<MediaPlayerBase> p = getPlayer();
-    if (p == 0) return UNKNOWN_ERROR;
-    status_t ret = p->getVideoWidth(w);
-    if (ret == NO_ERROR) ret = p->getVideoHeight(h);
-    if (ret == NO_ERROR) {
-        LOGV("[%d] getVideoWidth = (%d, %d)", mConnId, *w, *h);
-    } else {
-        LOGE("getVideoSize returned %d", ret);
-    }
-    return ret;
-}
-
 status_t MediaPlayerService::Client::getCurrentPosition(int *msec)
 {
     LOGV("getCurrentPosition");
@@ -812,7 +820,7 @@
 
 static size_t kDefaultHeapSize = 1024 * 1024; // 1MB
 
-sp<IMemory> MediaPlayerService::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels)
+sp<IMemory> MediaPlayerService::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
 {
     LOGV("decode(%s)", url);
     sp<MemoryBase> mem;
@@ -856,14 +864,15 @@
     mem = new MemoryBase(cache->getHeap(), 0, cache->size());
     *pSampleRate = cache->sampleRate();
     *pNumChannels = cache->channelCount();
-    LOGV("return memory @ %p, sampleRate=%u, channelCount = %d", mem->pointer(), *pSampleRate, *pNumChannels);
+    *pFormat = cache->format();
+    LOGV("return memory @ %p, sampleRate=%u, channelCount = %d, format = %d", mem->pointer(), *pSampleRate, *pNumChannels, *pFormat);
 
 Exit:
     if (player != 0) player->reset();
     return mem;
 }
 
-sp<IMemory> MediaPlayerService::decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels)
+sp<IMemory> MediaPlayerService::decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
 {
     LOGV("decode(%d, %lld, %lld)", fd, offset, length);
     sp<MemoryBase> mem;
@@ -898,7 +907,8 @@
     mem = new MemoryBase(cache->getHeap(), 0, cache->size());
     *pSampleRate = cache->sampleRate();
     *pNumChannels = cache->channelCount();
-    LOGV("return memory @ %p, sampleRate=%u, channelCount = %d", mem->pointer(), *pSampleRate, *pNumChannels);
+    *pFormat = cache->format();
+    LOGV("return memory @ %p, sampleRate=%u, channelCount = %d, format = %d", mem->pointer(), *pSampleRate, *pNumChannels, *pFormat);
 
 Exit:
     if (player != 0) player->reset();
@@ -916,6 +926,7 @@
     mRightVolume = 1.0;
     mLatency = 0;
     mMsecsPerFrame = 0;
+    setMinBufferCount();
 }
 
 MediaPlayerService::AudioOutput::~AudioOutput()
@@ -923,10 +934,31 @@
     close();
 }
 
+void MediaPlayerService::AudioOutput::setMinBufferCount()
+{
+    char value[PROPERTY_VALUE_MAX];
+    if (property_get("ro.kernel.qemu", value, 0)) {
+        mIsOnEmulator = true;
+        mMinBufferCount = 12;  // to prevent systematic buffer underrun for emulator
+    }
+}
+
+bool MediaPlayerService::AudioOutput::isOnEmulator()
+{
+    setMinBufferCount();
+    return mIsOnEmulator;
+}
+
+int MediaPlayerService::AudioOutput::getMinBufferCount()
+{
+    setMinBufferCount();
+    return mMinBufferCount;
+}
+
 ssize_t MediaPlayerService::AudioOutput::bufferSize() const
 {
     if (mTrack == 0) return NO_INIT;
-    return mTrack->frameCount() * mTrack->channelCount() * sizeof(int16_t);
+    return mTrack->frameCount() * frameSize();
 }
 
 ssize_t MediaPlayerService::AudioOutput::frameCount() const
@@ -944,7 +976,7 @@
 ssize_t MediaPlayerService::AudioOutput::frameSize() const
 {
     if (mTrack == 0) return NO_INIT;
-    return mTrack->channelCount() * sizeof(int16_t);
+    return mTrack->frameSize();
 }
 
 uint32_t MediaPlayerService::AudioOutput::latency () const
@@ -957,12 +989,29 @@
     return mMsecsPerFrame;
 }
 
-status_t MediaPlayerService::AudioOutput::open(uint32_t sampleRate, int channelCount, int bufferCount)
+status_t MediaPlayerService::AudioOutput::open(uint32_t sampleRate, int channelCount, int format, int bufferCount)
 {
-    LOGV("open(%u, %d, %d)", sampleRate, channelCount, bufferCount);
-    if (mTrack) close();
+    // Check argument "bufferCount" against the mininum buffer count
+    if (bufferCount < mMinBufferCount) {
+        LOGD("bufferCount (%d) is too small and increased to %d", bufferCount, mMinBufferCount);
+        bufferCount = mMinBufferCount;
 
-    AudioTrack *t = new AudioTrack(mStreamType, sampleRate, AudioSystem::PCM_16_BIT, channelCount, bufferCount);
+    }
+    LOGV("open(%u, %d, %d, %d)", sampleRate, channelCount, format, bufferCount);
+    if (mTrack) close();
+    int afSampleRate;
+    int afFrameCount;
+    int frameCount;
+
+    if (AudioSystem::getOutputFrameCount(&afFrameCount) != NO_ERROR) {
+        return NO_INIT;
+    }
+    if (AudioSystem::getOutputSamplingRate(&afSampleRate) != NO_ERROR) {
+        return NO_INIT;
+    }
+
+    frameCount = (sampleRate*afFrameCount)/afSampleRate;
+    AudioTrack *t = new AudioTrack(mStreamType, sampleRate, format, channelCount, frameCount*bufferCount);
     if ((t == 0) || (t->initCheck() != NO_ERROR)) {
         LOGE("Unable to create audio track");
         delete t;
@@ -972,7 +1021,7 @@
     LOGV("setVolume");
     t->setVolume(mLeftVolume, mRightVolume);
     mMsecsPerFrame = 1.e3 / (float) sampleRate;
-    mLatency = (mMsecsPerFrame * bufferCount * t->frameCount()) + kDriverLatencyInMsecs;
+    mLatency = t->latency() + kAudioVideoDelayMs;
     mTrack = t;
     return NO_ERROR;
 }
@@ -1031,7 +1080,7 @@
 #undef LOG_TAG
 #define LOG_TAG "AudioCache"
 MediaPlayerService::AudioCache::AudioCache(const char* name) :
-    mChannelCount(0), mFrameCount(0), mSampleRate(0), mSize(0),
+    mChannelCount(0), mFrameCount(1024), mSampleRate(0), mSize(0),
     mError(NO_ERROR), mCommandComplete(false)
 {
     // create ashmem heap
@@ -1048,12 +1097,13 @@
     return mMsecsPerFrame;
 }
 
-status_t MediaPlayerService::AudioCache::open(uint32_t sampleRate, int channelCount, int bufferCount)
+status_t MediaPlayerService::AudioCache::open(uint32_t sampleRate, int channelCount, int format, int bufferCount)
 {
-    LOGV("open(%u, %d, %d)", sampleRate, channelCount, bufferCount);
-   if (mHeap->getHeapID() < 0) return NO_INIT;
-   mSampleRate = sampleRate;
-   mChannelCount = channelCount;
+    LOGV("open(%u, %d, %d, %d)", sampleRate, channelCount, format, bufferCount);
+    if (mHeap->getHeapID() < 0) return NO_INIT;
+    mSampleRate = sampleRate;
+    mChannelCount = (uint16_t)channelCount;
+    mFormat = (uint16_t)format;
     mMsecsPerFrame = 1.e3 / (float) sampleRate;
     return NO_ERROR;
 }
@@ -1067,6 +1117,10 @@
     if (p == NULL) return NO_INIT;
     p += mSize;
     LOGV("memcpy(%p, %p, %u)", p, buffer, size);
+    if (mSize + size > mHeap->getSize()) {
+        LOGE("Heap size overflow! req size: %d, max size: %d", (mSize + size), mHeap->getSize());
+        size = mHeap->getSize() - mSize;
+    }
     memcpy(p, buffer, size);
     mSize += size;
     return size;
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index c2007cb..f138886 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -25,10 +25,11 @@
 #include <media/IMediaPlayerService.h>
 #include <media/MediaPlayerInterface.h>
 
-class SkBitmap;
-
 namespace android {
 
+class IMediaRecorder;
+class IMediaMetadataRetriever;
+
 #define CALLBACK_ANTAGONIZER 0
 #if CALLBACK_ANTAGONIZER
 class Antagonizer {
@@ -68,7 +69,7 @@
         virtual ssize_t         frameSize() const;
         virtual uint32_t        latency() const;
         virtual float           msecsPerFrame() const;
-        virtual status_t        open(uint32_t sampleRate, int channelCount, int bufferCount=4);
+        virtual status_t        open(uint32_t sampleRate, int channelCount, int format, int bufferCount=4);
         virtual void            start();
         virtual ssize_t         write(const void* buffer, size_t size);
         virtual void            stop();
@@ -78,14 +79,24 @@
                 void            setAudioStreamType(int streamType) { mStreamType = streamType; }
                 void            setVolume(float left, float right);
         virtual status_t        dump(int fd, const Vector<String16>& args) const;
+
+        static bool             isOnEmulator();
+        static int              getMinBufferCount();
     private:
+        static void             setMinBufferCount();
+
         AudioTrack*             mTrack;
         int                     mStreamType;
         float                   mLeftVolume;
         float                   mRightVolume;
         float                   mMsecsPerFrame;
         uint32_t                mLatency;
-        static const uint32_t   kDriverLatencyInMsecs;
+
+        // TODO: Find real cause of Audio/Video delay in PV framework and remove this workaround
+        static const uint32_t   kAudioVideoDelayMs;
+        static bool             mIsOnEmulator;
+        static int              mMinBufferCount;  // 12 for emulator; otherwise 4
+
     };
 
     class AudioCache : public MediaPlayerBase::AudioSink
@@ -96,13 +107,13 @@
 
         virtual bool            ready() const { return (mChannelCount > 0) && (mHeap->getHeapID() > 0); }
         virtual bool            realtime() const { return false; }
-        virtual ssize_t         bufferSize() const { return 4096; }
+        virtual ssize_t         bufferSize() const { return frameSize() * mFrameCount; }
         virtual ssize_t         frameCount() const { return mFrameCount; }
-        virtual ssize_t         channelCount() const { return mChannelCount; }
-        virtual ssize_t         frameSize() const { return ssize_t(mChannelCount * sizeof(int16_t)); }
+        virtual ssize_t         channelCount() const { return (ssize_t)mChannelCount; }
+        virtual ssize_t         frameSize() const { return ssize_t(mChannelCount * ((mFormat == AudioSystem::PCM_16_BIT)?sizeof(int16_t):sizeof(u_int8_t))); }
         virtual uint32_t        latency() const;
         virtual float           msecsPerFrame() const;
-        virtual status_t        open(uint32_t sampleRate, int channelCount, int bufferCount=1);
+        virtual status_t        open(uint32_t sampleRate, int channelCount, int format, int bufferCount=1);
         virtual void            start() {}
         virtual ssize_t         write(const void* buffer, size_t size);
         virtual void            stop() {}
@@ -112,6 +123,7 @@
                 void            setAudioStreamType(int streamType) {}
                 void            setVolume(float left, float right) {}
                 uint32_t        sampleRate() const { return mSampleRate; }
+                uint32_t        format() const { return (uint32_t)mFormat; }
                 size_t          size() const { return mSize; }
                 status_t        wait();
 
@@ -127,7 +139,8 @@
         Condition           mSignal;
         sp<MemoryHeapBase>  mHeap;
         float               mMsecsPerFrame;
-        ssize_t             mChannelCount;
+        uint16_t            mChannelCount;
+        uint16_t			mFormat;
         ssize_t             mFrameCount;
         uint32_t            mSampleRate;
         uint32_t            mSize;
@@ -139,10 +152,14 @@
     static  void                instantiate();
 
     // IMediaPlayerService interface
+    virtual sp<IMediaRecorder>  createMediaRecorder(pid_t pid);
+    virtual sp<IMediaMetadataRetriever> createMetadataRetriever(pid_t pid);
+
+    // House keeping for media player clients
     virtual sp<IMediaPlayer>    create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url);
     virtual sp<IMediaPlayer>    create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length);
-    virtual sp<IMemory>         decode(const char* url, uint32_t *pSampleRate, int* pNumChannels);
-    virtual sp<IMemory>         decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels);
+    virtual sp<IMemory>         decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
+    virtual sp<IMemory>         decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
 
     virtual status_t            dump(int fd, const Vector<String16>& args);
 
@@ -160,7 +177,6 @@
         virtual status_t        stop();
         virtual status_t        pause();
         virtual status_t        isPlaying(bool* state);
-        virtual status_t        getVideoSize(int* w, int* h);
         virtual status_t        seekTo(int msec);
         virtual status_t        getCurrentPosition(int* msec);
         virtual status_t        getDuration(int* msec);
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
new file mode 100644
index 0000000..f326a0e
--- /dev/null
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -0,0 +1,251 @@
+/*
+ ** Copyright 2008, HTC Inc.
+ **
+ ** 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 "MediaRecorderService"
+#include <utils/Log.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <string.h>
+#include <cutils/atomic.h>
+#include <android_runtime/ActivityManager.h>
+#include <utils/IPCThreadState.h>
+#include <utils/IServiceManager.h>
+#include <utils/MemoryHeapBase.h>
+#include <utils/MemoryBase.h>
+#include <media/PVMediaRecorder.h>
+
+#include "MediaRecorderClient.h"
+
+namespace android {
+
+status_t MediaRecorderClient::setCamera(const sp<ICamera>& camera)
+{
+    LOGV("setCamera");
+    Mutex::Autolock lock(mLock);
+    if (mRecorder == NULL) {
+        LOGE("recorder is not initialized");
+        return NO_INIT;
+    }
+    return mRecorder->setCamera(camera);
+}
+
+status_t MediaRecorderClient::setPreviewSurface(const sp<ISurface>& surface)
+{
+    LOGV("setPreviewSurface");
+    Mutex::Autolock lock(mLock);
+    if (mRecorder == NULL) {
+        LOGE("recorder is not initialized");
+        return NO_INIT;
+    }
+    return mRecorder->setPreviewSurface(surface);
+}
+
+status_t MediaRecorderClient::setVideoSource(int vs)
+{
+    LOGV("setVideoSource(%d)", vs);
+    Mutex::Autolock lock(mLock);
+    if (mRecorder == NULL)	{
+        LOGE("recorder is not initialized");
+    }
+    return mRecorder->setVideoSource((video_source)vs);
+}
+
+status_t MediaRecorderClient::setAudioSource(int as)
+{
+    LOGV("setAudioSource(%d)", as);
+    Mutex::Autolock lock(mLock);
+    if (mRecorder == NULL)  {
+        LOGE("recorder is not initialized");
+    }
+    return mRecorder->setAudioSource((audio_source)as);
+}
+
+status_t MediaRecorderClient::setOutputFormat(int of)
+{
+    LOGV("setOutputFormat(%d)", of);
+    Mutex::Autolock lock(mLock);
+    if (mRecorder == NULL) {
+        LOGE("recorder is not initialized");
+        return NO_INIT;
+    }
+    return mRecorder->setOutputFormat((output_format)of);
+}
+
+status_t MediaRecorderClient::setVideoEncoder(int ve)
+{
+    LOGV("setVideoEncoder(%d)", ve);
+    Mutex::Autolock lock(mLock);
+    if (mRecorder == NULL) {
+        LOGE("recorder is not initialized");
+        return NO_INIT;
+    }
+    return mRecorder->setVideoEncoder((video_encoder)ve);
+}
+
+status_t MediaRecorderClient::setAudioEncoder(int ae)
+{
+    LOGV("setAudioEncoder(%d)", ae);
+    Mutex::Autolock lock(mLock);
+    if (mRecorder == NULL) {
+        LOGE("recorder is not initialized");
+        return NO_INIT;
+    }
+    return mRecorder->setAudioEncoder((audio_encoder)ae);
+}
+
+status_t MediaRecorderClient::setOutputFile(const char* path)
+{
+    LOGV("setOutputFile(%s)", path);
+    Mutex::Autolock lock(mLock);
+    if (mRecorder == NULL) {
+        LOGE("recorder is not initialized");
+        return NO_INIT;
+    }
+    return mRecorder->setOutputFile(path);
+}
+
+status_t MediaRecorderClient::setVideoSize(int width, int height)
+{
+    LOGV("setVideoSize(%dx%d)", width, height);
+    Mutex::Autolock lock(mLock);
+    if (mRecorder == NULL) {
+        LOGE("recorder is not initialized");
+        return NO_INIT;
+    }
+    return mRecorder->setVideoSize(width, height);
+}
+
+status_t MediaRecorderClient::setVideoFrameRate(int frames_per_second)
+{
+    LOGV("setVideoFrameRate(%d)", frames_per_second);
+    Mutex::Autolock lock(mLock);
+    if (mRecorder == NULL) {
+        LOGE("recorder is not initialized");
+        return NO_INIT;
+    }
+    return mRecorder->setVideoFrameRate(frames_per_second);
+}
+
+status_t MediaRecorderClient::prepare()
+{
+    LOGV("prepare");
+    Mutex::Autolock lock(mLock);
+    if (mRecorder == NULL) {
+        LOGE("recorder is not initialized");
+        return NO_INIT;
+    }
+    return mRecorder->prepare();
+}
+
+
+status_t MediaRecorderClient::getMaxAmplitude(int* max)
+{
+    LOGV("getMaxAmplitude");
+    Mutex::Autolock lock(mLock);
+    if (mRecorder == NULL) {
+        LOGE("recorder is not initialized");
+        return NO_INIT;
+    }
+    return mRecorder->getMaxAmplitude(max);
+}
+
+status_t MediaRecorderClient::start()
+{
+    LOGV("start");
+    Mutex::Autolock lock(mLock);
+    if (mRecorder == NULL) {
+        LOGE("recorder is not initialized");
+        return NO_INIT;
+    }
+    return mRecorder->start();
+
+}
+
+status_t MediaRecorderClient::stop()
+{
+    LOGV("stop");
+    Mutex::Autolock lock(mLock);
+    if (mRecorder == NULL) {
+        LOGE("recorder is not initialized");
+        return NO_INIT;
+    }
+    return mRecorder->stop();
+}
+
+status_t MediaRecorderClient::init()
+{
+    LOGV("init");
+    Mutex::Autolock lock(mLock);
+    if (mRecorder == NULL) {
+        LOGE("recorder is not initialized");
+        return NO_INIT;
+    }
+    return mRecorder->init();
+}
+
+status_t MediaRecorderClient::close()
+{
+    LOGV("close");
+    Mutex::Autolock lock(mLock);
+    if (mRecorder == NULL) {
+        LOGE("recorder is not initialized");
+        return NO_INIT;
+    }
+    return mRecorder->close();
+}
+
+
+status_t MediaRecorderClient::reset()
+{
+    LOGV("reset");
+    Mutex::Autolock lock(mLock);
+    if (mRecorder == NULL) {
+        LOGE("recorder is not initialized");
+        return NO_INIT;
+    }
+    return mRecorder->reset();
+}
+
+status_t MediaRecorderClient::release()
+{
+    LOGV("release");
+    Mutex::Autolock lock(mLock);
+    if (mRecorder != NULL) {
+        delete mRecorder;
+        mRecorder = NULL;
+    }
+    return NO_ERROR;
+}
+
+MediaRecorderClient::MediaRecorderClient(pid_t pid)
+{
+    LOGV("Client constructor");
+    mPid = pid;
+    mRecorder = new PVMediaRecorder();
+}
+
+MediaRecorderClient::~MediaRecorderClient()
+{
+    LOGV("Client destructor");
+    release();
+}
+
+}; // namespace android
+
diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h
new file mode 100644
index 0000000..3158017
--- /dev/null
+++ b/media/libmediaplayerservice/MediaRecorderClient.h
@@ -0,0 +1,64 @@
+/*
+ **
+ ** Copyright 2008, HTC Inc.
+ **
+ ** 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_MEDIARECORDERCLIENT_H
+#define ANDROID_MEDIARECORDERCLIENT_H
+
+#include <media/IMediaRecorder.h>
+
+namespace android {
+
+class PVMediaRecorder;
+class ISurface;
+
+class MediaRecorderClient : public BnMediaRecorder
+{
+public:
+    virtual	    status_t		setCamera(const sp<ICamera>& camera);
+    virtual     status_t        setPreviewSurface(const sp<ISurface>& surface);
+    virtual     status_t        setVideoSource(int vs);
+    virtual     status_t        setAudioSource(int as);
+    virtual     status_t        setOutputFormat(int of);
+    virtual     status_t        setVideoEncoder(int ve);
+    virtual     status_t        setAudioEncoder(int ae);
+    virtual     status_t        setOutputFile(const char* path);
+    virtual     status_t        setVideoSize(int width, int height);
+    virtual     status_t        setVideoFrameRate(int frames_per_second);
+    virtual     status_t        prepare();
+    virtual     status_t        getMaxAmplitude(int* max);
+    virtual     status_t        start();
+    virtual     status_t        stop();
+    virtual	    status_t        reset();
+    virtual     status_t        init();
+    virtual     status_t        close();
+    virtual     status_t        release();
+
+private:
+    friend class                 MediaPlayerService;  // for accessing private constructor
+
+                                 MediaRecorderClient(pid_t pid);
+    virtual 		         ~MediaRecorderClient();
+
+    pid_t			 mPid;
+    Mutex			 mLock;
+    PVMediaRecorder              *mRecorder;
+};
+
+}; // namespace android
+
+#endif // ANDROID_MEDIARECORDERCLIENT_H
+
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
new file mode 100644
index 0000000..a320bd5
--- /dev/null
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -0,0 +1,250 @@
+/*
+**
+** Copyright (C) 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_NDEBUG 0
+#define LOG_TAG "MetadataRetrieverClient"
+#include <utils/Log.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <unistd.h>
+
+#include <string.h>
+#include <cutils/atomic.h>
+#include <utils/MemoryDealer.h>
+#include <android_runtime/ActivityManager.h>
+#include <utils/IPCThreadState.h>
+#include <utils/IServiceManager.h>
+#include <media/MediaMetadataRetrieverInterface.h>
+#include <media/MediaPlayerInterface.h>
+#include <media/PVMetadataRetriever.h>
+#include <private/media/VideoFrame.h>
+
+#include "MetadataRetrieverClient.h"
+
+
+namespace android {
+
+MetadataRetrieverClient::MetadataRetrieverClient(pid_t pid)
+{
+    LOGV("MetadataRetrieverClient constructor pid(%d)", pid);
+    mPid = pid;
+    mThumbnailDealer = NULL;
+    mAlbumArtDealer = NULL;
+    mThumbnail = NULL;
+    mAlbumArt = NULL;
+
+    mRetriever = new PVMetadataRetriever();
+    if (mRetriever == NULL) {
+        LOGE("failed to initialize the retriever");
+    }
+}
+
+MetadataRetrieverClient::~MetadataRetrieverClient()
+{
+    LOGV("MetadataRetrieverClient destructor");
+    disconnect();
+}
+
+status_t MetadataRetrieverClient::dump(int fd, const Vector<String16>& args) const
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    result.append(" MetadataRetrieverClient\n");
+    snprintf(buffer, 255, "  pid(%d)\n", mPid);
+    result.append(buffer);
+    write(fd, result.string(), result.size());
+    write(fd, "\n", 1);
+    return NO_ERROR;
+}
+
+void MetadataRetrieverClient::disconnect()
+{
+    LOGV("disconnect from pid %d", mPid);
+    Mutex::Autolock lock(mLock);
+    mRetriever.clear();
+    mThumbnailDealer.clear();
+    mAlbumArtDealer.clear();
+    mThumbnail.clear();
+    mAlbumArt.clear();
+    IPCThreadState::self()->flushCommands();
+}
+
+status_t MetadataRetrieverClient::setDataSource(const char *url)
+{
+    LOGV("setDataSource(%s)", url);
+    Mutex::Autolock lock(mLock);
+    if (url == NULL) {
+        return UNKNOWN_ERROR;
+    }
+    if (mRetriever == NULL) {
+        LOGE("retriever is not initialized");
+        return NO_INIT;
+    }
+    return mRetriever->setDataSource(url);
+}
+
+status_t MetadataRetrieverClient::setDataSource(int fd, int64_t offset, int64_t length)
+{
+    LOGV("setDataSource fd=%d, offset=%lld, length=%lld", fd, offset, length);
+    Mutex::Autolock lock(mLock);
+    if (mRetriever == NULL) {
+        LOGE("retriever is not initialized");
+        ::close(fd);
+        return NO_INIT;
+    }
+
+    struct stat sb;
+    int ret = fstat(fd, &sb);
+    if (ret != 0) {
+        LOGE("fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
+        return UNKNOWN_ERROR;
+    }
+    LOGV("st_dev  = %llu", sb.st_dev);
+    LOGV("st_mode = %u", sb.st_mode);
+    LOGV("st_uid  = %lu", sb.st_uid);
+    LOGV("st_gid  = %lu", sb.st_gid);
+    LOGV("st_size = %llu", sb.st_size);
+
+    if (offset >= sb.st_size) {
+        LOGE("offset (%lld) bigger than file size (%llu)", offset, sb.st_size);
+        ::close(fd);
+        return UNKNOWN_ERROR;
+    }
+    if (offset + length > sb.st_size) {
+        length = sb.st_size - offset;
+        LOGE("calculated length = %lld", length);
+    }
+    status_t status = mRetriever->setDataSource(fd, offset, length);
+    ::close(fd);
+    return status;
+}
+
+status_t MetadataRetrieverClient::setMode(int mode)
+{
+    LOGV("setMode");
+    Mutex::Autolock lock(mLock);
+    if (mRetriever == NULL) {
+        LOGE("retriever is not initialized");
+        return NO_INIT;
+    }
+    return mRetriever->setMode(mode);
+}
+
+status_t MetadataRetrieverClient::getMode(int* mode) const
+{
+    LOGV("getMode");
+    Mutex::Autolock lock(mLock);
+    if (mRetriever == NULL) {
+        LOGE("retriever is not initialized");
+        return NO_INIT;
+    }
+    return mRetriever->getMode(mode);
+}
+
+sp<IMemory> MetadataRetrieverClient::captureFrame()
+{
+    LOGV("captureFrame");
+    Mutex::Autolock lock(mLock);
+    mThumbnail.clear();
+    mThumbnailDealer.clear();
+    if (mRetriever == NULL) {
+        LOGE("retriever is not initialized");
+        return NULL;
+    }
+    VideoFrame *frame = mRetriever->captureFrame();
+    if (frame == NULL) {
+        LOGE("failed to capture a video frame");
+        return NULL;
+    }
+    size_t size = sizeof(VideoFrame) + frame->mSize;
+    mThumbnailDealer = new MemoryDealer(size);
+    if (mThumbnailDealer == NULL) {
+        LOGE("failed to create MemoryDealer");
+        delete frame;
+        return NULL;
+    }
+    mThumbnail = mThumbnailDealer->allocate(size);
+    if (mThumbnail == NULL) {
+        LOGE("not enough memory for VideoFrame size=%u", size);
+        mThumbnailDealer.clear();
+        delete frame;
+        return NULL;
+    }
+    VideoFrame *frameCopy = static_cast<VideoFrame *>(mThumbnail->pointer());
+    frameCopy->mWidth = frame->mWidth;
+    frameCopy->mHeight = frame->mHeight;
+    frameCopy->mDisplayWidth = frame->mDisplayWidth;
+    frameCopy->mDisplayHeight = frame->mDisplayHeight;
+    frameCopy->mSize = frame->mSize;
+    frameCopy->mData = (uint8_t *)frameCopy + sizeof(VideoFrame);
+    memcpy(frameCopy->mData, frame->mData, frame->mSize);
+    delete frame;  // Fix memory leakage
+    return mThumbnail;
+}
+
+sp<IMemory> MetadataRetrieverClient::extractAlbumArt()
+{
+    LOGV("extractAlbumArt");
+    Mutex::Autolock lock(mLock);
+    mAlbumArt.clear();
+    mAlbumArtDealer.clear();
+    if (mRetriever == NULL) {
+        LOGE("retriever is not initialized");
+        return NULL;
+    }
+    MediaAlbumArt *albumArt = mRetriever->extractAlbumArt();
+    if (albumArt == NULL) {
+        LOGE("failed to extract an album art");
+        return NULL;
+    }
+    size_t size = sizeof(MediaAlbumArt) + albumArt->mSize;
+    mAlbumArtDealer = new MemoryDealer(size);
+    if (mAlbumArtDealer == NULL) {
+        LOGE("failed to create MemoryDealer object");
+        delete albumArt;
+        return NULL;
+    }
+    mAlbumArt = mAlbumArtDealer->allocate(size);
+    if (mAlbumArt == NULL) {
+        LOGE("not enough memory for MediaAlbumArt size=%u", size);
+        mAlbumArtDealer.clear();
+        delete albumArt;
+        return NULL;
+    }
+    MediaAlbumArt *albumArtCopy = static_cast<MediaAlbumArt *>(mAlbumArt->pointer());
+    albumArtCopy->mSize = albumArt->mSize;
+    albumArtCopy->mData = (uint8_t *)albumArtCopy + sizeof(MediaAlbumArt);
+    memcpy(albumArtCopy->mData, albumArt->mData, albumArt->mSize);
+    delete albumArt;  // Fix memory leakage
+    return mAlbumArt;
+}
+
+const char* MetadataRetrieverClient::extractMetadata(int keyCode)
+{
+    LOGV("extractMetadata");
+    Mutex::Autolock lock(mLock);
+    if (mRetriever == NULL) {
+        LOGE("retriever is not initialized");
+        return NULL;
+    }
+    return mRetriever->extractMetadata(keyCode);
+}
+
+}; // namespace android
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.h b/media/libmediaplayerservice/MetadataRetrieverClient.h
new file mode 100644
index 0000000..ce29c98
--- /dev/null
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.h
@@ -0,0 +1,71 @@
+/*
+**
+** Copyright (C) 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_MEDIAMETADATARETRIEVERSERVICE_H
+#define ANDROID_MEDIAMETADATARETRIEVERSERVICE_H
+
+#include <utils.h>
+#include <utils/KeyedVector.h>
+#include <utils/IMemory.h>
+
+#include <media/MediaMetadataRetrieverInterface.h>
+
+
+namespace android {
+
+class IMediaPlayerService;
+class MemoryDealer;
+
+class MetadataRetrieverClient : public BnMediaMetadataRetriever
+{
+public:
+    MetadataRetrieverClient(const sp<IMediaPlayerService>& service, pid_t pid, int32_t connId);
+
+    // Implements IMediaMetadataRetriever interface
+    // These methods are called in IMediaMetadataRetriever.cpp?
+    virtual void                    disconnect();
+    virtual status_t                setDataSource(const char *url);
+    virtual status_t                setDataSource(int fd, int64_t offset, int64_t length);
+    virtual status_t                setMode(int mode);
+    virtual status_t                getMode(int* mode) const;
+    virtual sp<IMemory>             captureFrame();
+    virtual sp<IMemory>             extractAlbumArt();
+    virtual const char*             extractMetadata(int keyCode);
+
+    virtual status_t                dump(int fd, const Vector<String16>& args) const;
+
+private:
+    friend class MediaPlayerService;
+
+    explicit MetadataRetrieverClient(pid_t pid);
+    virtual ~MetadataRetrieverClient();
+
+    mutable Mutex                          mLock;
+    sp<MediaMetadataRetrieverBase>         mRetriever;
+    pid_t                                  mPid;
+
+    // Keep the shared memory copy of album art and capture frame (for thumbnail)
+    sp<MemoryDealer>                       mAlbumArtDealer;
+    sp<MemoryDealer>                       mThumbnailDealer;
+    sp<IMemory>                            mAlbumArt;
+    sp<IMemory>                            mThumbnail;
+};
+
+}; // namespace android
+
+#endif // ANDROID_MEDIAMETADATARETRIEVERSERVICE_H
+
diff --git a/media/libmediaplayerservice/MidiFile.cpp b/media/libmediaplayerservice/MidiFile.cpp
index 538f7d4..cfad66c 100644
--- a/media/libmediaplayerservice/MidiFile.cpp
+++ b/media/libmediaplayerservice/MidiFile.cpp
@@ -431,7 +431,7 @@
 }
 
 status_t MidiFile::createOutputTrack() {
-    if (mAudioSink->open(pLibConfig->sampleRate,pLibConfig->numChannels, 2) != NO_ERROR) {
+    if (mAudioSink->open(pLibConfig->sampleRate, pLibConfig->numChannels, AudioSystem::PCM_16_BIT, 2) != NO_ERROR) {
         LOGE("mAudioSink open failed");
         return ERROR_OPEN_FAILED;
     }
diff --git a/media/libmediaplayerservice/VorbisPlayer.cpp b/media/libmediaplayerservice/VorbisPlayer.cpp
index a0e0f39..9a64403 100644
--- a/media/libmediaplayerservice/VorbisPlayer.cpp
+++ b/media/libmediaplayerservice/VorbisPlayer.cpp
@@ -385,7 +385,7 @@
 
     LOGV("Create AudioTrack object: rate=%ld, channels=%d\n",
             vi->rate, vi->channels);
-    if (mAudioSink->open(vi->rate, vi->channels, DEFAULT_AUDIOSINK_BUFFERCOUNT) != NO_ERROR) {
+    if (mAudioSink->open(vi->rate, vi->channels, AudioSystem::PCM_16_BIT, DEFAULT_AUDIOSINK_BUFFERCOUNT) != NO_ERROR) {
         LOGE("mAudioSink open failed");
         return ERROR_OPEN_FAILED;
     }