Code drop from //branches/cupcake/...@124589
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
+