am be806fe8: am cc8f87e9: am f664d6f9: am b083d3b8: Merge "Initialize resampling buffer per track."

* commit 'be806fe8c1c7bb3ae70ae27dce41d672410af26a':
  Initialize resampling buffer per track.
diff --git a/cmds/stagefright/sf2.cpp b/cmds/stagefright/sf2.cpp
index 1dc08ea..74649a9 100644
--- a/cmds/stagefright/sf2.cpp
+++ b/cmds/stagefright/sf2.cpp
@@ -170,6 +170,7 @@
                     mCodec->signalResume();
 
                     (new AMessage(kWhatSeek, id()))->post(5000000ll);
+                } else if (what == ACodec::kWhatOutputFormatChanged) {
                 } else {
                     CHECK_EQ(what, (int32_t)ACodec::kWhatShutdownCompleted);
 
diff --git a/drm/common/Android.mk b/drm/common/Android.mk
index c79a91a..f1136c9 100644
--- a/drm/common/Android.mk
+++ b/drm/common/Android.mk
@@ -26,7 +26,6 @@
     DrmInfoStatus.cpp \
     DrmRights.cpp \
     DrmSupportInfo.cpp \
-    IDrmIOService.cpp \
     IDrmManagerService.cpp \
     IDrmServiceListener.cpp \
     DrmInfoEvent.cpp \
diff --git a/drm/common/IDrmIOService.cpp b/drm/common/IDrmIOService.cpp
deleted file mode 100644
index e44ca55..0000000
--- a/drm/common/IDrmIOService.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <binder/Parcel.h>
-#include <binder/IPCThreadState.h>
-#include <drm/drm_framework_common.h>
-#include "IDrmIOService.h"
-
-using namespace android;
-
-void BpDrmIOService::writeToFile(const String8& filePath, const String8& dataBuffer) {
-    Parcel data, reply;
-
-    data.writeInterfaceToken(IDrmIOService::getInterfaceDescriptor());
-    data.writeString8(filePath);
-    data.writeString8(dataBuffer);
-
-    remote()->transact(WRITE_TO_FILE, data, &reply);
-}
-
-String8 BpDrmIOService::readFromFile(const String8& filePath) {
-
-    Parcel data, reply;
-
-    data.writeInterfaceToken(IDrmIOService::getInterfaceDescriptor());
-    data.writeString8(filePath);
-
-    remote()->transact(READ_FROM_FILE, data, &reply);
-    return reply.readString8();
-}
-
-IMPLEMENT_META_INTERFACE(DrmIOService, "drm.IDrmIOService");
-
-status_t BnDrmIOService::onTransact(
-    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
-
-    switch (code) {
-    case WRITE_TO_FILE:
-    {
-        CHECK_INTERFACE(IDrmIOService, data, reply);
-
-        writeToFile(data.readString8(), data.readString8());
-        return DRM_NO_ERROR;
-    }
-
-    case READ_FROM_FILE:
-    {
-        CHECK_INTERFACE(IDrmIOService, data, reply);
-
-        String8 dataBuffer = readFromFile(data.readString8());
-        reply->writeString8(dataBuffer);
-        return DRM_NO_ERROR;
-    }
-
-    default:
-        return BBinder::onTransact(code, data, reply, flags);
-    }
-}
-
diff --git a/drm/drmserver/DrmManager.cpp b/drm/drmserver/DrmManager.cpp
index b6e0c30..ef7d274 100644
--- a/drm/drmserver/DrmManager.cpp
+++ b/drm/drmserver/DrmManager.cpp
@@ -87,7 +87,7 @@
 }
 
 status_t DrmManager::loadPlugIns() {
-    String8 pluginDirPath("/system/lib/drm/plugins/native");
+    String8 pluginDirPath("/system/lib/drm");
     return loadPlugIns(pluginDirPath);
 }
 
diff --git a/drm/libdrmframework/include/DrmIOService.h b/drm/libdrmframework/include/DrmIOService.h
deleted file mode 100644
index 244124e..0000000
--- a/drm/libdrmframework/include/DrmIOService.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __DRM_IO_SERVICE_H__
-#define __DRM_IO_SERVICE_H__
-
-#include "IDrmIOService.h"
-
-namespace android {
-
-/**
- * This is the implementation class for DRM IO service.
- *
- * The instance of this class is created while starting the DRM IO service.
- *
- */
-class DrmIOService : public BnDrmIOService {
-public:
-    static void instantiate();
-
-private:
-    DrmIOService();
-    virtual ~DrmIOService();
-
-public:
-    void writeToFile(const String8& filePath, const String8& dataBuffer);
-    String8 readFromFile(const String8& filePath);
-};
-
-};
-
-#endif /* __DRM_IO_SERVICE_H__ */
-
diff --git a/drm/libdrmframework/include/IDrmIOService.h b/drm/libdrmframework/include/IDrmIOService.h
deleted file mode 100644
index 5e0d907..0000000
--- a/drm/libdrmframework/include/IDrmIOService.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __IDRM_IO_SERVICE_H__
-#define __IDRM_IO_SERVICE_H__
-
-#include <utils/RefBase.h>
-#include <binder/IInterface.h>
-#include <binder/Parcel.h>
-
-namespace android {
-
-/**
- * This is the interface class for DRM IO service.
- *
- */
-class IDrmIOService : public IInterface
-{
-public:
-    enum {
-        WRITE_TO_FILE = IBinder::FIRST_CALL_TRANSACTION,
-        READ_FROM_FILE
-    };
-
-public:
-    DECLARE_META_INTERFACE(DrmIOService);
-
-public:
-    /**
-     * Writes the data into the file path provided
-     *
-     * @param[in] filePath Path of the file
-     * @param[in] dataBuffer Data to write
-     */
-    virtual void writeToFile(const String8& filePath, const String8& dataBuffer) = 0;
-
-    /**
-     * Reads the data from the file path provided
-     *
-     * @param[in] filePath Path of the file
-     * @return Data read from the file
-     */
-    virtual String8 readFromFile(const String8& filePath) = 0;
-};
-
-/**
- * This is the Binder implementation class for DRM IO service.
- */
-class BpDrmIOService: public BpInterface<IDrmIOService>
-{
-public:
-    BpDrmIOService(const sp<IBinder>& impl)
-            : BpInterface<IDrmIOService>(impl) {}
-
-    virtual void writeToFile(const String8& filePath, const String8& dataBuffer);
-
-    virtual String8 readFromFile(const String8& filePath);
-};
-
-/**
- * This is the Binder implementation class for DRM IO service.
- */
-class BnDrmIOService: public BnInterface<IDrmIOService>
-{
-public:
-    virtual status_t onTransact(
-            uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);
-};
-
-};
-
-#endif /* __IDRM_IO_SERVICE_H__ */
-
diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk
index d4a6f18..af67aa3 100644
--- a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk
+++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk
@@ -60,7 +60,7 @@
     $(LOCAL_PATH)/include \
     external/openssl/include
 
-LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/drm/plugins/native
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/drm
 
 LOCAL_MODULE_TAGS := optional
 
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index 4599d70..a969796 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -109,7 +109,7 @@
 
     status_t allocateOutputBuffersFromNativeWindow();
     status_t cancelBufferToNativeWindow(BufferInfo *info);
-    status_t freeOutputBuffersOwnedByNativeWindow();
+    status_t freeOutputBuffersNotOwnedByComponent();
     BufferInfo *dequeueBufferFromNativeWindow();
 
     BufferInfo *findBufferByID(
diff --git a/include/media/stagefright/MediaDefs.h b/include/media/stagefright/MediaDefs.h
index 2d50ca5..31a549c 100644
--- a/include/media/stagefright/MediaDefs.h
+++ b/include/media/stagefright/MediaDefs.h
@@ -37,6 +37,7 @@
 extern const char *MEDIA_MIMETYPE_AUDIO_G711_ALAW;
 extern const char *MEDIA_MIMETYPE_AUDIO_G711_MLAW;
 extern const char *MEDIA_MIMETYPE_AUDIO_RAW;
+extern const char *MEDIA_MIMETYPE_AUDIO_FLAC;
 
 extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG4;
 extern const char *MEDIA_MIMETYPE_CONTAINER_WAV;
diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
index 26c5aca..9097e20 100755
--- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
@@ -166,7 +166,7 @@
     REVERB_VOLUME_RAMP,
 };
 
-#define REVERB_DEFAULT_PRESET REVERB_PRESET_MEDIUMROOM
+#define REVERB_DEFAULT_PRESET REVERB_PRESET_NONE
 
 
 #define REVERB_SEND_LEVEL   (0x0C00) // 0.75 in 4.12 format
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index dfb4e00..505d9d4 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -197,6 +197,9 @@
     // to fill with data.
     void resume();
 
+    // Returns true iff input and output buffers are in play.
+    bool active() const { return mActive; }
+
 protected:
     virtual PortMode getPortMode(OMX_U32 portIndex);
     virtual bool onMessageReceived(const sp<AMessage> &msg);
@@ -205,6 +208,8 @@
     virtual bool onOMXEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2);
 
 private:
+    bool mActive;
+
     DISALLOW_EVIL_CONSTRUCTORS(ExecutingState);
 };
 
@@ -564,13 +569,17 @@
     return OK;
 }
 
-status_t ACodec::freeOutputBuffersOwnedByNativeWindow() {
+status_t ACodec::freeOutputBuffersNotOwnedByComponent() {
     for (size_t i = mBuffers[kPortIndexOutput].size(); i-- > 0;) {
         BufferInfo *info =
             &mBuffers[kPortIndexOutput].editItemAt(i);
 
-        if (info->mStatus ==
-                BufferInfo::OWNED_BY_NATIVE_WINDOW) {
+        if (info->mStatus !=
+                BufferInfo::OWNED_BY_COMPONENT) {
+            // We shouldn't have sent out any buffers to the client at this
+            // point.
+            CHECK_NE((int)info->mStatus, (int)BufferInfo::OWNED_BY_DOWNSTREAM);
+
             CHECK_EQ((status_t)OK, freeBuffer(kPortIndexOutput, i));
         }
     }
@@ -1195,6 +1204,9 @@
 }
 
 bool ACodec::BaseState::onOMXEmptyBufferDone(IOMX::buffer_id bufferID) {
+    LOGV("[%s] onOMXEmptyBufferDone %p",
+         mCodec->mComponentName.c_str(), bufferID);
+
     BufferInfo *info =
         mCodec->findBufferByID(kPortIndexInput, bufferID);
 
@@ -1295,7 +1307,7 @@
                 }
 
                 if (buffer != info->mData) {
-                    if (!(flags & OMX_BUFFERFLAG_CODECCONFIG)) {
+                    if (0 && !(flags & OMX_BUFFERFLAG_CODECCONFIG)) {
                         LOGV("[%s] Needs to copy input data.",
                              mCodec->mComponentName.c_str());
                     }
@@ -1304,6 +1316,9 @@
                     memcpy(info->mData->data(), buffer->data(), buffer->size());
                 }
 
+                LOGV("[%s] calling emptyBuffer %p",
+                     mCodec->mComponentName.c_str(), bufferID);
+
                 CHECK_EQ(mCodec->mOMX->emptyBuffer(
                             mCodec->mNode,
                             bufferID,
@@ -1320,6 +1335,9 @@
                 LOGV("[%s] Signalling EOS on the input port",
                      mCodec->mComponentName.c_str());
 
+                LOGV("[%s] calling emptyBuffer %p",
+                     mCodec->mComponentName.c_str(), bufferID);
+
                 CHECK_EQ(mCodec->mOMX->emptyBuffer(
                             mCodec->mNode,
                             bufferID,
@@ -1378,6 +1396,9 @@
         int64_t timeUs,
         void *platformPrivate,
         void *dataPtr) {
+    LOGV("[%s] onOMXFillBufferDone %p",
+         mCodec->mComponentName.c_str(), bufferID);
+
     ssize_t index;
     BufferInfo *info =
         mCodec->findBufferByID(kPortIndexOutput, bufferID, &index);
@@ -1396,6 +1417,9 @@
         {
             if (rangeLength == 0) {
                 if (!(flags & OMX_BUFFERFLAG_EOS)) {
+                    LOGV("[%s] calling fillBuffer %p",
+                         mCodec->mComponentName.c_str(), info->mBufferID);
+
                     CHECK_EQ(mCodec->mOMX->fillBuffer(
                                 mCodec->mNode, info->mBufferID),
                              (status_t)OK);
@@ -1503,6 +1527,9 @@
                     info = mCodec->dequeueBufferFromNativeWindow();
                 }
 
+                LOGV("[%s] calling fillBuffer %p",
+                     mCodec->mComponentName.c_str(), info->mBufferID);
+
                 CHECK_EQ(mCodec->mOMX->fillBuffer(mCodec->mNode, info->mBufferID),
                          (status_t)OK);
 
@@ -1600,6 +1627,9 @@
     mCodec->mOMX = omx;
     mCodec->mNode = node;
 
+    mCodec->mPortEOS[kPortIndexInput] =
+        mCodec->mPortEOS[kPortIndexOutput] = false;
+
     mCodec->configureCodec(mime.c_str(), msg);
 
     sp<RefBase> obj;
@@ -1717,7 +1747,8 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 ACodec::ExecutingState::ExecutingState(ACodec *codec)
-    : BaseState(codec) {
+    : BaseState(codec),
+      mActive(false) {
 }
 
 ACodec::BaseState::PortMode ACodec::ExecutingState::getPortMode(
@@ -1745,6 +1776,9 @@
             CHECK_EQ((int)info->mStatus, (int)BufferInfo::OWNED_BY_US);
         }
 
+        LOGV("[%s] calling fillBuffer %p",
+             mCodec->mComponentName.c_str(), info->mBufferID);
+
         CHECK_EQ(mCodec->mOMX->fillBuffer(mCodec->mNode, info->mBufferID),
                  (status_t)OK);
 
@@ -1753,6 +1787,13 @@
 }
 
 void ACodec::ExecutingState::resume() {
+    if (mActive) {
+        LOGV("[%s] We're already active, no need to resume.",
+             mCodec->mComponentName.c_str());
+
+        return;
+    }
+
     submitOutputBuffers();
 
     // Post the first input buffer.
@@ -1760,6 +1801,8 @@
     BufferInfo *info = &mCodec->mBuffers[kPortIndexInput].editItemAt(0);
 
     postFillThisBuffer(info);
+
+    mActive = true;
 }
 
 void ACodec::ExecutingState::stateEntered() {
@@ -1774,6 +1817,8 @@
     switch (msg->what()) {
         case kWhatShutdown:
         {
+            mActive = false;
+
             CHECK_EQ(mCodec->mOMX->sendCommand(
                         mCodec->mNode, OMX_CommandStateSet, OMX_StateIdle),
                      (status_t)OK);
@@ -1786,6 +1831,8 @@
 
         case kWhatFlush:
         {
+            mActive = false;
+
             CHECK_EQ(mCodec->mOMX->sendCommand(
                         mCodec->mNode, OMX_CommandFlush, OMX_ALL),
                      (status_t)OK);
@@ -1825,10 +1872,7 @@
                             OMX_CommandPortDisable, kPortIndexOutput),
                          (status_t)OK);
 
-                if (mCodec->mNativeWindow != NULL) {
-                    CHECK_EQ((status_t)OK,
-                             mCodec->freeOutputBuffersOwnedByNativeWindow());
-                }
+                mCodec->freeOutputBuffersNotOwnedByComponent();
 
                 mCodec->changeState(mCodec->mOutputPortSettingsChangedState);
             } else if (data2 == OMX_IndexConfigCommonOutputCrop) {
@@ -1876,7 +1920,12 @@
     switch (msg->what()) {
         case kWhatFlush:
         case kWhatShutdown:
+        case kWhatResume:
         {
+            if (msg->what() == kWhatResume) {
+                LOGV("[%s] Deferring resume", mCodec->mComponentName.c_str());
+            }
+
             mCodec->deferMessage(msg);
             handled = true;
             break;
@@ -1925,7 +1974,10 @@
                 LOGV("[%s] Output port now reenabled.",
                         mCodec->mComponentName.c_str());
 
-                mCodec->mExecutingState->submitOutputBuffers();
+                if (mCodec->mExecutingState->active()) {
+                    mCodec->mExecutingState->submitOutputBuffers();
+                }
+
                 mCodec->changeState(mCodec->mExecutingState);
 
                 return true;
@@ -1992,6 +2044,13 @@
             return true;
         }
 
+        case OMX_EventPortSettingsChanged:
+        case OMX_EventBufferFlag:
+        {
+            // We're shutting down and don't care about this anymore.
+            return true;
+        }
+
         default:
             return BaseState::onOMXEvent(event, data1, data2);
     }
@@ -2170,6 +2229,23 @@
             return true;
         }
 
+        case OMX_EventPortSettingsChanged:
+        {
+            sp<AMessage> msg = new AMessage(kWhatOMXMessage, mCodec->id());
+            msg->setInt32("type", omx_message::EVENT);
+            msg->setPointer("node", mCodec->mNode);
+            msg->setInt32("event", event);
+            msg->setInt32("data1", data1);
+            msg->setInt32("data2", data2);
+
+            LOGV("[%s] Deferring OMX_EventPortSettingsChanged",
+                 mCodec->mComponentName.c_str());
+
+            mCodec->deferMessage(msg);
+
+            return true;
+        }
+
         default:
             return BaseState::onOMXEvent(event, data1, data2);
     }
diff --git a/media/libstagefright/AMRExtractor.cpp b/media/libstagefright/AMRExtractor.cpp
index ac87c29..7eca5e4 100644
--- a/media/libstagefright/AMRExtractor.cpp
+++ b/media/libstagefright/AMRExtractor.cpp
@@ -35,8 +35,9 @@
 public:
     AMRSource(const sp<DataSource> &source,
               const sp<MetaData> &meta,
-              size_t frameSize,
-              bool isWide);
+              bool isWide,
+              const off64_t *offset_table,
+              size_t offset_table_length);
 
     virtual status_t start(MetaData *params = NULL);
     virtual status_t stop();
@@ -52,7 +53,6 @@
 private:
     sp<DataSource> mDataSource;
     sp<MetaData> mMeta;
-    size_t mFrameSize;
     bool mIsWide;
 
     off64_t mOffset;
@@ -60,6 +60,9 @@
     bool mStarted;
     MediaBufferGroup *mGroup;
 
+    off64_t mOffsetTable[OFFSET_TABLE_LEN];
+    size_t mOffsetTableLength;
+
     AMRSource(const AMRSource &);
     AMRSource &operator=(const AMRSource &);
 };
@@ -67,13 +70,25 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 static size_t getFrameSize(bool isWide, unsigned FT) {
-    static const size_t kFrameSizeNB[8] = {
-        95, 103, 118, 134, 148, 159, 204, 244
+    static const size_t kFrameSizeNB[16] = {
+        95, 103, 118, 134, 148, 159, 204, 244,
+        39, 43, 38, 37, // SID
+        0, 0, 0, // future use
+        0 // no data
     };
-    static const size_t kFrameSizeWB[9] = {
-        132, 177, 253, 285, 317, 365, 397, 461, 477
+    static const size_t kFrameSizeWB[16] = {
+        132, 177, 253, 285, 317, 365, 397, 461, 477,
+        40, // SID
+        0, 0, 0, 0, // future use
+        0, // speech lost
+        0 // no data
     };
 
+    if (FT > 15 || (isWide && FT > 9 && FT < 14) || (!isWide && FT > 11 && FT < 15)) {
+        LOGE("illegal AMR frame type %d", FT);
+        return 0;
+    }
+
     size_t frameSize = isWide ? kFrameSizeWB[FT] : kFrameSizeNB[FT];
 
     // Round up bits to bytes and add 1 for the header byte.
@@ -82,9 +97,26 @@
     return frameSize;
 }
 
+static status_t getFrameSizeByOffset(const sp<DataSource> &source,
+        off64_t offset, bool isWide, size_t *frameSize) {
+    uint8_t header;
+    if (source->readAt(offset, &header, 1) < 1) {
+        return ERROR_IO;
+    }
+
+    unsigned FT = (header >> 3) & 0x0f;
+
+    *frameSize = getFrameSize(isWide, FT);
+    if (*frameSize == 0) {
+        return ERROR_MALFORMED;
+    }
+    return OK;
+}
+
 AMRExtractor::AMRExtractor(const sp<DataSource> &source)
     : mDataSource(source),
-      mInitCheck(NO_INIT) {
+      mInitCheck(NO_INIT),
+      mOffsetTableLength(0) {
     String8 mimeType;
     float confidence;
     if (!SniffAMR(mDataSource, &mimeType, &confidence, NULL)) {
@@ -101,25 +133,29 @@
     mMeta->setInt32(kKeyChannelCount, 1);
     mMeta->setInt32(kKeySampleRate, mIsWide ? 16000 : 8000);
 
-    size_t offset = mIsWide ? 9 : 6;
-    uint8_t header;
-    if (mDataSource->readAt(offset, &header, 1) != 1) {
-        return;
-    }
-
-    unsigned FT = (header >> 3) & 0x0f;
-
-    if (FT > 8 || (!mIsWide && FT > 7)) {
-        return;
-    }
-
-    mFrameSize = getFrameSize(mIsWide, FT);
-
+    off64_t offset = mIsWide ? 9 : 6;
     off64_t streamSize;
-    if (mDataSource->getSize(&streamSize) == OK) {
-        off64_t numFrames = streamSize / mFrameSize;
+    size_t frameSize, numFrames = 0;
+    int64_t duration = 0;
 
-        mMeta->setInt64(kKeyDuration, 20000ll * numFrames);
+    if (mDataSource->getSize(&streamSize) == OK) {
+         while (offset < streamSize) {
+            if (getFrameSizeByOffset(source, offset, mIsWide, &frameSize) != OK) {
+                return;
+            }
+
+            if ((numFrames % 50 == 0) && (numFrames / 50 < OFFSET_TABLE_LEN)) {
+                CHECK_EQ(mOffsetTableLength, numFrames / 50);
+                mOffsetTable[mOffsetTableLength] = offset - (mIsWide ? 9: 6);
+                mOffsetTableLength ++;
+            }
+
+            offset += frameSize;
+            duration += 20000;  // Each frame is 20ms
+            numFrames ++;
+        }
+
+        mMeta->setInt64(kKeyDuration, duration);
     }
 
     mInitCheck = OK;
@@ -149,7 +185,8 @@
         return NULL;
     }
 
-    return new AMRSource(mDataSource, mMeta, mFrameSize, mIsWide);
+    return new AMRSource(mDataSource, mMeta, mIsWide,
+            mOffsetTable, mOffsetTableLength);
 }
 
 sp<MetaData> AMRExtractor::getTrackMetaData(size_t index, uint32_t flags) {
@@ -164,15 +201,18 @@
 
 AMRSource::AMRSource(
         const sp<DataSource> &source, const sp<MetaData> &meta,
-        size_t frameSize, bool isWide)
+        bool isWide, const off64_t *offset_table, size_t offset_table_length)
     : mDataSource(source),
       mMeta(meta),
-      mFrameSize(frameSize),
       mIsWide(isWide),
       mOffset(mIsWide ? 9 : 6),
       mCurrentTimeUs(0),
       mStarted(false),
-      mGroup(NULL) {
+      mGroup(NULL),
+      mOffsetTableLength(offset_table_length) {
+    if (mOffsetTableLength > 0 && mOffsetTableLength <= OFFSET_TABLE_LEN) {
+        memcpy ((char*)mOffsetTable, (char*)offset_table, sizeof(off64_t) * mOffsetTableLength);
+    }
 }
 
 AMRSource::~AMRSource() {
@@ -214,9 +254,25 @@
     int64_t seekTimeUs;
     ReadOptions::SeekMode mode;
     if (options && options->getSeekTo(&seekTimeUs, &mode)) {
+        size_t size;
         int64_t seekFrame = seekTimeUs / 20000ll;  // 20ms per frame.
         mCurrentTimeUs = seekFrame * 20000ll;
-        mOffset = seekFrame * mFrameSize + (mIsWide ? 9 : 6);
+
+        int index = seekFrame / 50;
+        if (index >= mOffsetTableLength) {
+            index = mOffsetTableLength - 1;
+        }
+
+        mOffset = mOffsetTable[index] + (mIsWide ? 9 : 6);
+
+        for (int i = 0; i< seekFrame - index * 50; i++) {
+            status_t err;
+            if ((err = getFrameSizeByOffset(mDataSource, mOffset,
+                            mIsWide, &size)) != OK) {
+                return err;
+            }
+            mOffset += size;
+        }
     }
 
     uint8_t header;
@@ -236,16 +292,11 @@
 
     unsigned FT = (header >> 3) & 0x0f;
 
-    if (FT > 8 || (!mIsWide && FT > 7)) {
-
-        LOGE("illegal AMR frame type %d", FT);
-
+    size_t frameSize = getFrameSize(mIsWide, FT);
+    if (frameSize == 0) {
         return ERROR_MALFORMED;
     }
 
-    size_t frameSize = getFrameSize(mIsWide, FT);
-    CHECK_EQ(frameSize, mFrameSize);
-
     MediaBuffer *buffer;
     status_t err = mGroup->acquire_buffer(&buffer);
     if (err != OK) {
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 2d486e3..029b238 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -17,6 +17,7 @@
         DRMExtractor.cpp                  \
         ESDS.cpp                          \
         FileSource.cpp                    \
+        FLACExtractor.cpp                 \
         HTTPStream.cpp                    \
         JPEGSource.cpp                    \
         MP3Extractor.cpp                  \
@@ -54,6 +55,7 @@
 LOCAL_C_INCLUDES:= \
 	$(JNI_H_INCLUDE) \
         $(TOP)/frameworks/base/include/media/stagefright/openmax \
+        $(TOP)/external/flac/include \
         $(TOP)/external/tremolo \
         $(TOP)/frameworks/base/media/libstagefright/rtsp
 
@@ -93,6 +95,7 @@
         libstagefright_rtsp \
         libstagefright_id3 \
         libstagefright_g711dec \
+        libFLAC \
 
 LOCAL_SHARED_LIBRARIES += \
         libstagefright_amrnb_common \
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 89b3dab..99a047a 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -378,11 +378,14 @@
 }
 
 void AwesomePlayer::reset() {
+    LOGI("reset");
+
     Mutex::Autolock autoLock(mLock);
     reset_l();
 }
 
 void AwesomePlayer::reset_l() {
+    LOGI("reset_l");
     mDisplayWidth = 0;
     mDisplayHeight = 0;
 
@@ -408,6 +411,10 @@
         }
     }
 
+    if (mFlags & PREPARING) {
+        LOGI("waiting until preparation is completes.");
+    }
+
     while (mFlags & PREPARING) {
         mPreparedCondition.wait(mLock);
     }
@@ -431,6 +438,8 @@
     }
     mAudioSource.clear();
 
+    LOGI("audio source cleared");
+
     mTimeSource = NULL;
 
     delete mAudioPlayer;
@@ -471,6 +480,8 @@
         IPCThreadState::self()->flushCommands();
     }
 
+    LOGI("video source cleared");
+
     mDurationUs = -1;
     mFlags = 0;
     mExtractorFlags = 0;
@@ -487,6 +498,8 @@
     mFileSource.clear();
 
     mBitrate = -1;
+
+    LOGI("reset_l completed");
 }
 
 void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
@@ -753,6 +766,8 @@
 }
 
 status_t AwesomePlayer::play_l() {
+    mFlags &= ~SEEK_PREVIEW;
+
     if (mFlags & PLAYING) {
         return OK;
     }
@@ -1066,6 +1081,11 @@
 
         notifyListener_l(MEDIA_SEEK_COMPLETE);
         mSeekNotificationSent = true;
+
+        if ((mFlags & PREPARED) && mVideoSource != NULL) {
+            mFlags |= SEEK_PREVIEW;
+            postVideoEvent_l();
+        }
     }
 
     return OK;
@@ -1168,7 +1188,7 @@
 }
 
 void AwesomePlayer::finishSeekIfNecessary(int64_t videoTimeUs) {
-    if (!mSeeking) {
+    if (!mSeeking || (mFlags & SEEK_PREVIEW)) {
         return;
     }
 
@@ -1215,7 +1235,8 @@
             mVideoBuffer = NULL;
         }
 
-        if (mCachedSource != NULL && mAudioSource != NULL) {
+        if (mCachedSource != NULL && mAudioSource != NULL
+                && !(mFlags & SEEK_PREVIEW)) {
             // We're going to seek the video source first, followed by
             // the audio source.
             // In order to avoid jumps in the DataSource offset caused by
@@ -1309,43 +1330,38 @@
         mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
     }
 
-    int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
-
-    int64_t latenessUs = nowUs - timeUs;
-
-    if (wasSeeking) {
+    if (!wasSeeking && mRTPSession == NULL) {
         // Let's display the first frame after seeking right away.
-        latenessUs = 0;
-    }
-
-    if (mRTPSession != NULL) {
         // We'll completely ignore timestamps for gtalk videochat
         // and we'll play incoming video as fast as we get it.
-        latenessUs = 0;
-    }
 
-    if (latenessUs > 40000) {
-        // We're more than 40ms late.
-        LOGV("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6);
-        if ( mSinceLastDropped > FRAME_DROP_FREQ)
-        {
-            LOGV("we're late by %lld us (%.2f secs) dropping one after %d frames", latenessUs, latenessUs / 1E6, mSinceLastDropped);
-            mSinceLastDropped = 0;
-            mVideoBuffer->release();
-            mVideoBuffer = NULL;
+        int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
 
-            postVideoEvent_l();
+        int64_t latenessUs = nowUs - timeUs;
+
+        if (latenessUs > 40000) {
+            // We're more than 40ms late.
+            LOGV("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6);
+            if ( mSinceLastDropped > FRAME_DROP_FREQ)
+            {
+                LOGV("we're late by %lld us (%.2f secs) dropping one after %d frames", latenessUs, latenessUs / 1E6, mSinceLastDropped);
+                mSinceLastDropped = 0;
+                mVideoBuffer->release();
+                mVideoBuffer = NULL;
+
+                postVideoEvent_l();
+                return;
+            }
+        }
+
+        if (latenessUs < -10000) {
+            // We're more than 10ms early.
+
+            postVideoEvent_l(10000);
             return;
         }
     }
 
-    if (latenessUs < -10000) {
-        // We're more than 10ms early.
-
-        postVideoEvent_l(10000);
-        return;
-    }
-
     if (mVideoRendererIsPreview || mVideoRenderer == NULL) {
         mVideoRendererIsPreview = false;
 
@@ -1360,6 +1376,11 @@
     mVideoBuffer->release();
     mVideoBuffer = NULL;
 
+    if (wasSeeking && (mFlags & SEEK_PREVIEW)) {
+        mFlags &= ~SEEK_PREVIEW;
+        return;
+    }
+
     postVideoEvent_l();
 }
 
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index ee0d792..e06fa81 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -23,6 +23,7 @@
 #include "include/NuCachedSource2.h"
 #include "include/NuHTTPDataSource.h"
 #include "include/DRMExtractor.h"
+#include "include/FLACExtractor.h"
 
 #include "matroska/MatroskaExtractor.h"
 
@@ -104,6 +105,7 @@
     RegisterSniffer(SniffMatroska);
     RegisterSniffer(SniffOgg);
     RegisterSniffer(SniffWAV);
+    RegisterSniffer(SniffFLAC);
     RegisterSniffer(SniffAMR);
     RegisterSniffer(SniffMPEG2TS);
     RegisterSniffer(SniffMP3);
diff --git a/media/libstagefright/FLACExtractor.cpp b/media/libstagefright/FLACExtractor.cpp
new file mode 100644
index 0000000..8ba5a2d
--- /dev/null
+++ b/media/libstagefright/FLACExtractor.cpp
@@ -0,0 +1,813 @@
+/*
+ * Copyright (C) 2011 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 "FLACExtractor"
+#include <utils/Log.h>
+
+#include "include/FLACExtractor.h"
+// Vorbis comments
+#include "include/OggExtractor.h"
+// libFLAC parser
+#include "FLAC/stream_decoder.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MediaBuffer.h>
+
+namespace android {
+
+class FLACParser;
+
+class FLACSource : public MediaSource {
+
+public:
+    FLACSource(
+            const sp<DataSource> &dataSource,
+            const sp<MetaData> &trackMetadata);
+
+    virtual status_t start(MetaData *params);
+    virtual status_t stop();
+    virtual sp<MetaData> getFormat();
+
+    virtual status_t read(
+            MediaBuffer **buffer, const ReadOptions *options = NULL);
+
+protected:
+    virtual ~FLACSource();
+
+private:
+    sp<DataSource> mDataSource;
+    sp<MetaData> mTrackMetadata;
+    sp<FLACParser> mParser;
+    bool mInitCheck;
+    bool mStarted;
+
+    status_t init();
+
+    // no copy constructor or assignment
+    FLACSource(const FLACSource &);
+    FLACSource &operator=(const FLACSource &);
+
+};
+
+// FLACParser wraps a C libFLAC parser aka stream decoder
+
+class FLACParser : public RefBase {
+
+public:
+    FLACParser(
+        const sp<DataSource> &dataSource,
+        // If metadata pointers aren't provided, we don't fill them
+        const sp<MetaData> &fileMetadata = 0,
+        const sp<MetaData> &trackMetadata = 0);
+
+    status_t initCheck() const {
+        return mInitCheck;
+    }
+
+    // stream properties
+    unsigned getMaxBlockSize() const {
+        return mStreamInfo.max_blocksize;
+    }
+    unsigned getSampleRate() const {
+        return mStreamInfo.sample_rate;
+    }
+    unsigned getChannels() const {
+        return mStreamInfo.channels;
+    }
+    unsigned getBitsPerSample() const {
+        return mStreamInfo.bits_per_sample;
+    }
+    FLAC__uint64 getTotalSamples() const {
+        return mStreamInfo.total_samples;
+    }
+
+    // media buffers
+    void allocateBuffers();
+    void releaseBuffers();
+    MediaBuffer *readBuffer() {
+        return readBuffer(false, 0LL);
+    }
+    MediaBuffer *readBuffer(FLAC__uint64 sample) {
+        return readBuffer(true, sample);
+    }
+
+protected:
+    virtual ~FLACParser();
+
+private:
+    sp<DataSource> mDataSource;
+    sp<MetaData> mFileMetadata;
+    sp<MetaData> mTrackMetadata;
+    bool mInitCheck;
+
+    // media buffers
+    size_t mMaxBufferSize;
+    MediaBufferGroup *mGroup;
+    void (*mCopy)(short *dst, const int *const *src, unsigned nSamples);
+
+    // handle to underlying libFLAC parser
+    FLAC__StreamDecoder *mDecoder;
+
+    // current position within the data source
+    off64_t mCurrentPos;
+    bool mEOF;
+
+    // cached when the STREAMINFO metadata is parsed by libFLAC
+    FLAC__StreamMetadata_StreamInfo mStreamInfo;
+    bool mStreamInfoValid;
+
+    // cached when a decoded PCM block is "written" by libFLAC parser
+    bool mWriteRequested;
+    bool mWriteCompleted;
+    FLAC__FrameHeader mWriteHeader;
+    const FLAC__int32 * const *mWriteBuffer;
+
+    // most recent error reported by libFLAC parser
+    FLAC__StreamDecoderErrorStatus mErrorStatus;
+
+    status_t init();
+    MediaBuffer *readBuffer(bool doSeek, FLAC__uint64 sample);
+
+    // no copy constructor or assignment
+    FLACParser(const FLACParser &);
+    FLACParser &operator=(const FLACParser &);
+
+    // FLAC parser callbacks as C++ instance methods
+    FLAC__StreamDecoderReadStatus readCallback(
+            FLAC__byte buffer[], size_t *bytes);
+    FLAC__StreamDecoderSeekStatus seekCallback(
+            FLAC__uint64 absolute_byte_offset);
+    FLAC__StreamDecoderTellStatus tellCallback(
+            FLAC__uint64 *absolute_byte_offset);
+    FLAC__StreamDecoderLengthStatus lengthCallback(
+            FLAC__uint64 *stream_length);
+    FLAC__bool eofCallback();
+    FLAC__StreamDecoderWriteStatus writeCallback(
+            const FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
+    void metadataCallback(const FLAC__StreamMetadata *metadata);
+    void errorCallback(FLAC__StreamDecoderErrorStatus status);
+
+    // FLAC parser callbacks as C-callable functions
+    static FLAC__StreamDecoderReadStatus read_callback(
+            const FLAC__StreamDecoder *decoder,
+            FLAC__byte buffer[], size_t *bytes,
+            void *client_data);
+    static FLAC__StreamDecoderSeekStatus seek_callback(
+            const FLAC__StreamDecoder *decoder,
+            FLAC__uint64 absolute_byte_offset,
+            void *client_data);
+    static FLAC__StreamDecoderTellStatus tell_callback(
+            const FLAC__StreamDecoder *decoder,
+            FLAC__uint64 *absolute_byte_offset,
+            void *client_data);
+    static FLAC__StreamDecoderLengthStatus length_callback(
+            const FLAC__StreamDecoder *decoder,
+            FLAC__uint64 *stream_length,
+            void *client_data);
+    static FLAC__bool eof_callback(
+            const FLAC__StreamDecoder *decoder,
+            void *client_data);
+    static FLAC__StreamDecoderWriteStatus write_callback(
+            const FLAC__StreamDecoder *decoder,
+            const FLAC__Frame *frame, const FLAC__int32 * const buffer[],
+            void *client_data);
+    static void metadata_callback(
+            const FLAC__StreamDecoder *decoder,
+            const FLAC__StreamMetadata *metadata,
+            void *client_data);
+    static void error_callback(
+            const FLAC__StreamDecoder *decoder,
+            FLAC__StreamDecoderErrorStatus status,
+            void *client_data);
+
+};
+
+// The FLAC parser calls our C++ static callbacks using C calling conventions,
+// inside FLAC__stream_decoder_process_until_end_of_metadata
+// and FLAC__stream_decoder_process_single.
+// We immediately then call our corresponding C++ instance methods
+// with the same parameter list, but discard redundant information.
+
+FLAC__StreamDecoderReadStatus FLACParser::read_callback(
+        const FLAC__StreamDecoder *decoder, FLAC__byte buffer[],
+        size_t *bytes, void *client_data)
+{
+    return ((FLACParser *) client_data)->readCallback(buffer, bytes);
+}
+
+FLAC__StreamDecoderSeekStatus FLACParser::seek_callback(
+        const FLAC__StreamDecoder *decoder,
+        FLAC__uint64 absolute_byte_offset, void *client_data)
+{
+    return ((FLACParser *) client_data)->seekCallback(absolute_byte_offset);
+}
+
+FLAC__StreamDecoderTellStatus FLACParser::tell_callback(
+        const FLAC__StreamDecoder *decoder,
+        FLAC__uint64 *absolute_byte_offset, void *client_data)
+{
+    return ((FLACParser *) client_data)->tellCallback(absolute_byte_offset);
+}
+
+FLAC__StreamDecoderLengthStatus FLACParser::length_callback(
+        const FLAC__StreamDecoder *decoder,
+        FLAC__uint64 *stream_length, void *client_data)
+{
+    return ((FLACParser *) client_data)->lengthCallback(stream_length);
+}
+
+FLAC__bool FLACParser::eof_callback(
+        const FLAC__StreamDecoder *decoder, void *client_data)
+{
+    return ((FLACParser *) client_data)->eofCallback();
+}
+
+FLAC__StreamDecoderWriteStatus FLACParser::write_callback(
+        const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame,
+        const FLAC__int32 * const buffer[], void *client_data)
+{
+    return ((FLACParser *) client_data)->writeCallback(frame, buffer);
+}
+
+void FLACParser::metadata_callback(
+        const FLAC__StreamDecoder *decoder,
+        const FLAC__StreamMetadata *metadata, void *client_data)
+{
+    ((FLACParser *) client_data)->metadataCallback(metadata);
+}
+
+void FLACParser::error_callback(
+        const FLAC__StreamDecoder *decoder,
+        FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+    ((FLACParser *) client_data)->errorCallback(status);
+}
+
+// These are the corresponding callbacks with C++ calling conventions
+
+FLAC__StreamDecoderReadStatus FLACParser::readCallback(
+        FLAC__byte buffer[], size_t *bytes)
+{
+    size_t requested = *bytes;
+    ssize_t actual = mDataSource->readAt(mCurrentPos, buffer, requested);
+    if (0 > actual) {
+        *bytes = 0;
+        return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+    } else if (0 == actual) {
+        *bytes = 0;
+        mEOF = true;
+        return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+    } else {
+        assert(actual <= requested);
+        *bytes = actual;
+        mCurrentPos += actual;
+        return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+    }
+}
+
+FLAC__StreamDecoderSeekStatus FLACParser::seekCallback(
+        FLAC__uint64 absolute_byte_offset)
+{
+    mCurrentPos = absolute_byte_offset;
+    mEOF = false;
+    return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
+}
+
+FLAC__StreamDecoderTellStatus FLACParser::tellCallback(
+        FLAC__uint64 *absolute_byte_offset)
+{
+    *absolute_byte_offset = mCurrentPos;
+    return FLAC__STREAM_DECODER_TELL_STATUS_OK;
+}
+
+FLAC__StreamDecoderLengthStatus FLACParser::lengthCallback(
+        FLAC__uint64 *stream_length)
+{
+    off64_t size;
+    if (OK == mDataSource->getSize(&size)) {
+        *stream_length = size;
+        return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
+    } else {
+        return FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED;
+    }
+}
+
+FLAC__bool FLACParser::eofCallback()
+{
+    return mEOF;
+}
+
+FLAC__StreamDecoderWriteStatus FLACParser::writeCallback(
+        const FLAC__Frame *frame, const FLAC__int32 * const buffer[])
+{
+    if (mWriteRequested) {
+        mWriteRequested = false;
+        // FLAC parser doesn't free or realloc buffer until next frame or finish
+        mWriteHeader = frame->header;
+        mWriteBuffer = buffer;
+        mWriteCompleted = true;
+        return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+    } else {
+        LOGE("FLACParser::writeCallback unexpected");
+        return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+    }
+}
+
+void FLACParser::metadataCallback(const FLAC__StreamMetadata *metadata)
+{
+    switch (metadata->type) {
+    case FLAC__METADATA_TYPE_STREAMINFO:
+        if (!mStreamInfoValid) {
+            mStreamInfo = metadata->data.stream_info;
+            mStreamInfoValid = true;
+        } else {
+            LOGE("FLACParser::metadataCallback unexpected STREAMINFO");
+        }
+        break;
+    case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+        {
+        const FLAC__StreamMetadata_VorbisComment *vc;
+        vc = &metadata->data.vorbis_comment;
+        for (FLAC__uint32 i = 0; i < vc->num_comments; ++i) {
+            FLAC__StreamMetadata_VorbisComment_Entry *vce;
+            vce = &vc->comments[i];
+            if (mFileMetadata != 0) {
+                parseVorbisComment(mFileMetadata, (const char *) vce->entry,
+                        vce->length);
+            }
+        }
+        }
+        break;
+    case FLAC__METADATA_TYPE_PICTURE:
+        if (mFileMetadata != 0) {
+            const FLAC__StreamMetadata_Picture *p = &metadata->data.picture;
+            mFileMetadata->setData(kKeyAlbumArt,
+                    MetaData::TYPE_NONE, p->data, p->data_length);
+            mFileMetadata->setCString(kKeyAlbumArtMIME, p->mime_type);
+        }
+        break;
+    default:
+        LOGW("FLACParser::metadataCallback unexpected type %u", metadata->type);
+        break;
+    }
+}
+
+void FLACParser::errorCallback(FLAC__StreamDecoderErrorStatus status)
+{
+    LOGE("FLACParser::errorCallback status=%d", status);
+    mErrorStatus = status;
+}
+
+// Copy samples from FLAC native 32-bit non-interleaved to 16-bit interleaved.
+// These are candidates for optimization if needed.
+
+static void copyMono8(short *dst, const int *const *src, unsigned nSamples)
+{
+    for (unsigned i = 0; i < nSamples; ++i) {
+        *dst++ = src[0][i] << 8;
+    }
+}
+
+static void copyStereo8(short *dst, const int *const *src, unsigned nSamples)
+{
+    for (unsigned i = 0; i < nSamples; ++i) {
+        *dst++ = src[0][i] << 8;
+        *dst++ = src[1][i] << 8;
+    }
+}
+
+static void copyMono16(short *dst, const int *const *src, unsigned nSamples)
+{
+    for (unsigned i = 0; i < nSamples; ++i) {
+        *dst++ = src[0][i];
+    }
+}
+
+static void copyStereo16(short *dst, const int *const *src, unsigned nSamples)
+{
+    for (unsigned i = 0; i < nSamples; ++i) {
+        *dst++ = src[0][i];
+        *dst++ = src[1][i];
+    }
+}
+
+// 24-bit versions should do dithering or noise-shaping, here or in AudioFlinger
+
+static void copyMono24(short *dst, const int *const *src, unsigned nSamples)
+{
+    for (unsigned i = 0; i < nSamples; ++i) {
+        *dst++ = src[0][i] >> 8;
+    }
+}
+
+static void copyStereo24(short *dst, const int *const *src, unsigned nSamples)
+{
+    for (unsigned i = 0; i < nSamples; ++i) {
+        *dst++ = src[0][i] >> 8;
+        *dst++ = src[1][i] >> 8;
+    }
+}
+
+static void copyTrespass(short *dst, const int *const *src, unsigned nSamples)
+{
+    TRESPASS();
+}
+
+// FLACParser
+
+FLACParser::FLACParser(
+        const sp<DataSource> &dataSource,
+        const sp<MetaData> &fileMetadata,
+        const sp<MetaData> &trackMetadata)
+    : mDataSource(dataSource),
+      mFileMetadata(fileMetadata),
+      mTrackMetadata(trackMetadata),
+      mInitCheck(false),
+      mMaxBufferSize(0),
+      mGroup(NULL),
+      mCopy(copyTrespass),
+      mDecoder(NULL),
+      mCurrentPos(0LL),
+      mEOF(false),
+      mStreamInfoValid(false),
+      mWriteRequested(false),
+      mWriteCompleted(false),
+      mWriteBuffer(NULL),
+      mErrorStatus((FLAC__StreamDecoderErrorStatus) -1)
+{
+    LOGV("FLACParser::FLACParser");
+    memset(&mStreamInfo, 0, sizeof(mStreamInfo));
+    memset(&mWriteHeader, 0, sizeof(mWriteHeader));
+    mInitCheck = init();
+}
+
+FLACParser::~FLACParser()
+{
+    LOGV("FLACParser::~FLACParser");
+    if (mDecoder != NULL) {
+        FLAC__stream_decoder_delete(mDecoder);
+        mDecoder = NULL;
+    }
+}
+
+status_t FLACParser::init()
+{
+    // setup libFLAC parser
+    mDecoder = FLAC__stream_decoder_new();
+    if (mDecoder == NULL) {
+        // The new should succeed, since probably all it does is a malloc
+        // that always succeeds in Android.  But to avoid dependence on the
+        // libFLAC internals, we check and log here.
+        LOGE("new failed");
+        return NO_INIT;
+    }
+    FLAC__stream_decoder_set_md5_checking(mDecoder, false);
+    FLAC__stream_decoder_set_metadata_ignore_all(mDecoder);
+    FLAC__stream_decoder_set_metadata_respond(
+            mDecoder, FLAC__METADATA_TYPE_STREAMINFO);
+    FLAC__stream_decoder_set_metadata_respond(
+            mDecoder, FLAC__METADATA_TYPE_PICTURE);
+    FLAC__stream_decoder_set_metadata_respond(
+            mDecoder, FLAC__METADATA_TYPE_VORBIS_COMMENT);
+    FLAC__StreamDecoderInitStatus initStatus;
+    initStatus = FLAC__stream_decoder_init_stream(
+            mDecoder,
+            read_callback, seek_callback, tell_callback,
+            length_callback, eof_callback, write_callback,
+            metadata_callback, error_callback, (void *) this);
+    if (initStatus != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+        // A failure here probably indicates a programming error and so is
+        // unlikely to happen. But we check and log here similarly to above.
+        LOGE("init_stream failed %d", initStatus);
+        return NO_INIT;
+    }
+    // parse all metadata
+    if (!FLAC__stream_decoder_process_until_end_of_metadata(mDecoder)) {
+        LOGE("end_of_metadata failed");
+        return NO_INIT;
+    }
+    if (mStreamInfoValid) {
+        // check channel count
+        switch (getChannels()) {
+        case 1:
+        case 2:
+            break;
+        default:
+            LOGE("unsupported channel count %u", getChannels());
+            return NO_INIT;
+        }
+        // check bit depth
+        switch (getBitsPerSample()) {
+        case 8:
+        case 16:
+        case 24:
+            break;
+        default:
+            LOGE("unsupported bits per sample %u", getBitsPerSample());
+            return NO_INIT;
+        }
+        // check sample rate
+        switch (getSampleRate()) {
+        case  8000:
+        case 11025:
+        case 12000:
+        case 16000:
+        case 22050:
+        case 24000:
+        case 32000:
+        case 44100:
+        case 48000:
+            break;
+        default:
+            // 96000 would require a proper downsampler in AudioFlinger
+            LOGE("unsupported sample rate %u", getSampleRate());
+            return NO_INIT;
+        }
+        // configure the appropriate copy function, defaulting to trespass
+        static const struct {
+            unsigned mChannels;
+            unsigned mBitsPerSample;
+            void (*mCopy)(short *dst, const int *const *src, unsigned nSamples);
+        } table[] = {
+            { 1,  8, copyMono8    },
+            { 2,  8, copyStereo8  },
+            { 1, 16, copyMono16   },
+            { 2, 16, copyStereo16 },
+            { 1, 24, copyMono24   },
+            { 2, 24, copyStereo24 },
+        };
+        for (unsigned i = 0; i < sizeof(table)/sizeof(table[0]); ++i) {
+            if (table[i].mChannels == getChannels() &&
+                    table[i].mBitsPerSample == getBitsPerSample()) {
+                mCopy = table[i].mCopy;
+                break;
+            }
+        }
+        // populate track metadata
+        if (mTrackMetadata != 0) {
+            mTrackMetadata->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
+            mTrackMetadata->setInt32(kKeyChannelCount, getChannels());
+            mTrackMetadata->setInt32(kKeySampleRate, getSampleRate());
+            // sample rate is non-zero, so division by zero not possible
+            mTrackMetadata->setInt64(kKeyDuration,
+                    (getTotalSamples() * 1000000LL) / getSampleRate());
+        }
+    } else {
+        LOGE("missing STREAMINFO");
+        return NO_INIT;
+    }
+    if (mFileMetadata != 0) {
+        mFileMetadata->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_FLAC);
+    }
+    return OK;
+}
+
+void FLACParser::allocateBuffers()
+{
+    CHECK(mGroup == NULL);
+    mGroup = new MediaBufferGroup;
+    mMaxBufferSize = getMaxBlockSize() * getChannels() * sizeof(short);
+    mGroup->add_buffer(new MediaBuffer(mMaxBufferSize));
+}
+
+void FLACParser::releaseBuffers()
+{
+    CHECK(mGroup != NULL);
+    delete mGroup;
+    mGroup = NULL;
+}
+
+MediaBuffer *FLACParser::readBuffer(bool doSeek, FLAC__uint64 sample)
+{
+    mWriteRequested = true;
+    mWriteCompleted = false;
+    if (doSeek) {
+        // We implement the seek callback, so this works without explicit flush
+        if (!FLAC__stream_decoder_seek_absolute(mDecoder, sample)) {
+            LOGE("FLACParser::readBuffer seek to sample %llu failed", sample);
+            return NULL;
+        }
+        LOGV("FLACParser::readBuffer seek to sample %llu succeeded", sample);
+    } else {
+        if (!FLAC__stream_decoder_process_single(mDecoder)) {
+            LOGE("FLACParser::readBuffer process_single failed");
+            return NULL;
+        }
+    }
+    if (!mWriteCompleted) {
+        LOGV("FLACParser::readBuffer write did not complete");
+        return NULL;
+    }
+    // verify that block header keeps the promises made by STREAMINFO
+    unsigned blocksize = mWriteHeader.blocksize;
+    if (blocksize == 0 || blocksize > getMaxBlockSize()) {
+        LOGE("FLACParser::readBuffer write invalid blocksize %u", blocksize);
+        return NULL;
+    }
+    if (mWriteHeader.sample_rate != getSampleRate() ||
+        mWriteHeader.channels != getChannels() ||
+        mWriteHeader.bits_per_sample != getBitsPerSample()) {
+        LOGE("FLACParser::readBuffer write changed parameters mid-stream");
+    }
+    // acquire a media buffer
+    CHECK(mGroup != NULL);
+    MediaBuffer *buffer;
+    status_t err = mGroup->acquire_buffer(&buffer);
+    if (err != OK) {
+        return NULL;
+    }
+    size_t bufferSize = blocksize * getChannels() * sizeof(short);
+    CHECK(bufferSize <= mMaxBufferSize);
+    short *data = (short *) buffer->data();
+    buffer->set_range(0, bufferSize);
+    // copy PCM from FLAC write buffer to our media buffer, with interleaving
+    (*mCopy)(data, mWriteBuffer, blocksize);
+    // fill in buffer metadata
+    CHECK(mWriteHeader.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
+    FLAC__uint64 sampleNumber = mWriteHeader.number.sample_number;
+    int64_t timeUs = (1000000LL * sampleNumber) / getSampleRate();
+    buffer->meta_data()->setInt64(kKeyTime, timeUs);
+    buffer->meta_data()->setInt32(kKeyIsSyncFrame, 1);
+    return buffer;
+}
+
+// FLACsource
+
+FLACSource::FLACSource(
+        const sp<DataSource> &dataSource,
+        const sp<MetaData> &trackMetadata)
+    : mDataSource(dataSource),
+      mTrackMetadata(trackMetadata),
+      mParser(0),
+      mInitCheck(false),
+      mStarted(false)
+{
+    LOGV("FLACSource::FLACSource");
+    mInitCheck = init();
+}
+
+FLACSource::~FLACSource()
+{
+    LOGV("~FLACSource::FLACSource");
+    if (mStarted) {
+        stop();
+    }
+}
+
+status_t FLACSource::start(MetaData *params)
+{
+    LOGV("FLACSource::start");
+
+    CHECK(!mStarted);
+    mParser->allocateBuffers();
+    mStarted = true;
+
+    return OK;
+}
+
+status_t FLACSource::stop()
+{
+    LOGV("FLACSource::stop");
+
+    CHECK(mStarted);
+    mParser->releaseBuffers();
+    mStarted = false;
+
+    return OK;
+}
+
+sp<MetaData> FLACSource::getFormat()
+{
+    return mTrackMetadata;
+}
+
+status_t FLACSource::read(
+        MediaBuffer **outBuffer, const ReadOptions *options)
+{
+    MediaBuffer *buffer;
+    // process an optional seek request
+    int64_t seekTimeUs;
+    ReadOptions::SeekMode mode;
+    if ((NULL != options) && options->getSeekTo(&seekTimeUs, &mode)) {
+        FLAC__uint64 sample;
+        if (seekTimeUs <= 0LL) {
+            sample = 0LL;
+        } else {
+            // sample and total samples are both zero-based, and seek to EOF ok
+            sample = (seekTimeUs * mParser->getSampleRate()) / 1000000LL;
+            if (sample >= mParser->getTotalSamples()) {
+                sample = mParser->getTotalSamples();
+            }
+        }
+        buffer = mParser->readBuffer(sample);
+    // otherwise read sequentially
+    } else {
+        buffer = mParser->readBuffer();
+    }
+    *outBuffer = buffer;
+    return buffer != NULL ? (status_t) OK : (status_t) ERROR_END_OF_STREAM;
+}
+
+status_t FLACSource::init()
+{
+    LOGV("FLACSource::init");
+    // re-use the same track metadata passed into constructor from FLACExtractor
+    mParser = new FLACParser(mDataSource);
+    return mParser->initCheck();
+}
+
+// FLACExtractor
+
+FLACExtractor::FLACExtractor(
+        const sp<DataSource> &dataSource)
+    : mDataSource(dataSource),
+      mInitCheck(false)
+{
+    LOGV("FLACExtractor::FLACExtractor");
+    mInitCheck = init();
+}
+
+FLACExtractor::~FLACExtractor()
+{
+    LOGV("~FLACExtractor::FLACExtractor");
+}
+
+size_t FLACExtractor::countTracks()
+{
+    return mInitCheck == OK ? 1 : 0;
+}
+
+sp<MediaSource> FLACExtractor::getTrack(size_t index)
+{
+    if (mInitCheck != OK || index > 0) {
+        return NULL;
+    }
+    return new FLACSource(mDataSource, mTrackMetadata);
+}
+
+sp<MetaData> FLACExtractor::getTrackMetaData(
+        size_t index, uint32_t flags)
+{
+    if (mInitCheck != OK || index > 0) {
+        return NULL;
+    }
+    return mTrackMetadata;
+}
+
+status_t FLACExtractor::init()
+{
+    mFileMetadata = new MetaData;
+    mTrackMetadata = new MetaData;
+    // FLACParser will fill in the metadata for us
+    mParser = new FLACParser(mDataSource, mFileMetadata, mTrackMetadata);
+    return mParser->initCheck();
+}
+
+sp<MetaData> FLACExtractor::getMetaData()
+{
+    return mFileMetadata;
+}
+
+// Sniffer
+
+bool SniffFLAC(
+        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        sp<AMessage> *)
+{
+    // first 4 is the signature word
+    // second 4 is the sizeof STREAMINFO
+    // 042 is the mandatory STREAMINFO
+    // no need to read rest of the header, as a premature EOF will be caught later
+    uint8_t header[4+4];
+    if (source->readAt(0, header, sizeof(header)) != sizeof(header)
+            || memcmp("fLaC\0\0\0\042", header, 4+4))
+    {
+        return false;
+    }
+
+    *mimeType = MEDIA_MIMETYPE_AUDIO_FLAC;
+    *confidence = 0.5;
+
+    return true;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index e6e98aa..108a1d1 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -1074,6 +1074,20 @@
             break;
         }
 
+        case FOURCC('c', 't', 't', 's'):
+        {
+            status_t err =
+                mLastTrack->sampleTable->setCompositionTimeToSampleParams(
+                        data_offset, chunk_data_size);
+
+            if (err != OK) {
+                return err;
+            }
+
+            *offset += chunk_size;
+            break;
+        }
+
         case FOURCC('s', 't', 's', 's'):
         {
             status_t err =
diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp
index 4599fca..b50af89 100644
--- a/media/libstagefright/MediaDefs.cpp
+++ b/media/libstagefright/MediaDefs.cpp
@@ -35,6 +35,7 @@
 const char *MEDIA_MIMETYPE_AUDIO_G711_ALAW = "audio/g711-alaw";
 const char *MEDIA_MIMETYPE_AUDIO_G711_MLAW = "audio/g711-mlaw";
 const char *MEDIA_MIMETYPE_AUDIO_RAW = "audio/raw";
+const char *MEDIA_MIMETYPE_AUDIO_FLAC = "audio/flac";
 
 const char *MEDIA_MIMETYPE_CONTAINER_MPEG4 = "video/mpeg4";
 const char *MEDIA_MIMETYPE_CONTAINER_WAV = "audio/wav";
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index d12ac64..08ed206 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -26,6 +26,7 @@
 #include "include/MPEG2TSExtractor.h"
 #include "include/DRMExtractor.h"
 #include "include/WVMExtractor.h"
+#include "include/FLACExtractor.h"
 
 #include "matroska/MatroskaExtractor.h"
 
@@ -85,6 +86,8 @@
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)
             || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) {
         return new AMRExtractor(source);
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC)) {
+        return new FLACExtractor(source);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WAV)) {
         return new WAVExtractor(source);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_OGG)) {
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 2a19b25..247ace7 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -3269,7 +3269,7 @@
 }
 
 status_t OMXCodec::stop() {
-    CODEC_LOGV("stop mState=%d", mState);
+    CODEC_LOGI("stop mState=%d", mState);
 
     Mutex::Autolock autoLock(mLock);
 
diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
index cf622af..0e51caf 100644
--- a/media/libstagefright/OggExtractor.cpp
+++ b/media/libstagefright/OggExtractor.cpp
@@ -114,7 +114,6 @@
             MediaBuffer *buffer, uint8_t type);
 
     void parseFileMetaData();
-    void extractAlbumArt(const void *data, size_t size);
 
     uint64_t findPrevGranulePosition(off64_t pageOffset);
 
@@ -122,6 +121,9 @@
     MyVorbisExtractor &operator=(const MyVorbisExtractor &);
 };
 
+static void extractAlbumArt(
+        const sp<MetaData> &fileMeta, const void *data, size_t size);
+
 ////////////////////////////////////////////////////////////////////////////////
 
 OggSource::OggSource(const sp<OggExtractor> &extractor)
@@ -654,6 +656,17 @@
     mFileMeta = new MetaData;
     mFileMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_OGG);
 
+    for (int i = 0; i < mVc.comments; ++i) {
+        const char *comment = mVc.user_comments[i];
+        size_t commentLength = mVc.comment_lengths[i];
+        parseVorbisComment(mFileMeta, comment, commentLength);
+        //LOGI("comment #%d: '%s'", i + 1, mVc.user_comments[i]);
+    }
+}
+
+void parseVorbisComment(
+        const sp<MetaData> &fileMeta, const char *comment, size_t commentLength)
+{
     struct {
         const char *const mTag;
         uint32_t mKey;
@@ -675,33 +688,25 @@
         { "ANDROID_LOOP", kKeyAutoLoop },
     };
 
-    for (int i = 0; i < mVc.comments; ++i) {
-        const char *comment = mVc.user_comments[i];
-
         for (size_t j = 0; j < sizeof(kMap) / sizeof(kMap[0]); ++j) {
             size_t tagLen = strlen(kMap[j].mTag);
             if (!strncasecmp(kMap[j].mTag, comment, tagLen)
                     && comment[tagLen] == '=') {
                 if (kMap[j].mKey == kKeyAlbumArt) {
                     extractAlbumArt(
+                            fileMeta,
                             &comment[tagLen + 1],
-                            mVc.comment_lengths[i] - tagLen - 1);
+                            commentLength - tagLen - 1);
                 } else if (kMap[j].mKey == kKeyAutoLoop) {
                     if (!strcasecmp(&comment[tagLen + 1], "true")) {
-                        mFileMeta->setInt32(kKeyAutoLoop, true);
+                        fileMeta->setInt32(kKeyAutoLoop, true);
                     }
                 } else {
-                    mFileMeta->setCString(kMap[j].mKey, &comment[tagLen + 1]);
+                    fileMeta->setCString(kMap[j].mKey, &comment[tagLen + 1]);
                 }
             }
         }
-    }
 
-#if 0
-    for (int i = 0; i < mVc.comments; ++i) {
-        LOGI("comment #%d: '%s'", i + 1, mVc.user_comments[i]);
-    }
-#endif
 }
 
 // The returned buffer should be free()d.
@@ -769,7 +774,8 @@
     return (uint8_t *)buffer;
 }
 
-void MyVorbisExtractor::extractAlbumArt(const void *data, size_t size) {
+static void extractAlbumArt(
+        const sp<MetaData> &fileMeta, const void *data, size_t size) {
     LOGV("extractAlbumArt from '%s'", (const char *)data);
 
     size_t flacSize;
@@ -833,10 +839,10 @@
     LOGV("got image data, %d trailing bytes",
          flacSize - 32 - typeLen - descLen - dataLen);
 
-    mFileMeta->setData(
+    fileMeta->setData(
             kKeyAlbumArt, 0, &flac[8 + typeLen + 4 + descLen + 20], dataLen);
 
-    mFileMeta->setCString(kKeyAlbumArtMIME, type);
+    fileMeta->setCString(kKeyAlbumArtMIME, type);
 
 exit:
     free(flac);
diff --git a/media/libstagefright/SampleIterator.cpp b/media/libstagefright/SampleIterator.cpp
index 062ab9b..c7b00b1 100644
--- a/media/libstagefright/SampleIterator.cpp
+++ b/media/libstagefright/SampleIterator.cpp
@@ -307,6 +307,8 @@
 
     *time = mTTSSampleTime + mTTSDuration * (sampleIndex - mTTSSampleIndex);
 
+    *time += mTable->getCompositionTimeOffset(sampleIndex);
+
     return OK;
 }
 
diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
index a9163fc..423df70 100644
--- a/media/libstagefright/SampleTable.cpp
+++ b/media/libstagefright/SampleTable.cpp
@@ -53,6 +53,8 @@
       mNumSampleSizes(0),
       mTimeToSampleCount(0),
       mTimeToSample(NULL),
+      mCompositionTimeDeltaEntries(NULL),
+      mNumCompositionTimeDeltaEntries(0),
       mSyncSampleOffset(-1),
       mNumSyncSamples(0),
       mSyncSamples(NULL),
@@ -68,6 +70,9 @@
     delete[] mSyncSamples;
     mSyncSamples = NULL;
 
+    delete[] mCompositionTimeDeltaEntries;
+    mCompositionTimeDeltaEntries = NULL;
+
     delete[] mTimeToSample;
     mTimeToSample = NULL;
 
@@ -260,6 +265,51 @@
     return OK;
 }
 
+status_t SampleTable::setCompositionTimeToSampleParams(
+        off64_t data_offset, size_t data_size) {
+    LOGI("There are reordered frames present.");
+
+    if (mCompositionTimeDeltaEntries != NULL || data_size < 8) {
+        return ERROR_MALFORMED;
+    }
+
+    uint8_t header[8];
+    if (mDataSource->readAt(
+                data_offset, header, sizeof(header))
+            < (ssize_t)sizeof(header)) {
+        return ERROR_IO;
+    }
+
+    if (U32_AT(header) != 0) {
+        // Expected version = 0, flags = 0.
+        return ERROR_MALFORMED;
+    }
+
+    size_t numEntries = U32_AT(&header[4]);
+
+    if (data_size != (numEntries + 1) * 8) {
+        return ERROR_MALFORMED;
+    }
+
+    mNumCompositionTimeDeltaEntries = numEntries;
+    mCompositionTimeDeltaEntries = new uint32_t[2 * numEntries];
+
+    if (mDataSource->readAt(
+                data_offset + 8, mCompositionTimeDeltaEntries, numEntries * 8)
+            < (ssize_t)numEntries * 8) {
+        delete[] mCompositionTimeDeltaEntries;
+        mCompositionTimeDeltaEntries = NULL;
+
+        return ERROR_IO;
+    }
+
+    for (size_t i = 0; i < 2 * numEntries; ++i) {
+        mCompositionTimeDeltaEntries[i] = ntohl(mCompositionTimeDeltaEntries[i]);
+    }
+
+    return OK;
+}
+
 status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size) {
     if (mSyncSampleOffset >= 0 || data_size < 8) {
         return ERROR_MALFORMED;
@@ -333,6 +383,8 @@
 
 status_t SampleTable::findSampleAtTime(
         uint32_t req_time, uint32_t *sample_index, uint32_t flags) {
+    // XXX this currently uses decoding time, instead of composition time.
+
     *sample_index = 0;
 
     Mutex::Autolock autoLock(mLock);
@@ -607,5 +659,26 @@
     return OK;
 }
 
+uint32_t SampleTable::getCompositionTimeOffset(uint32_t sampleIndex) const {
+    if (mCompositionTimeDeltaEntries == NULL) {
+        return 0;
+    }
+
+    uint32_t curSample = 0;
+    for (size_t i = 0; i < mNumCompositionTimeDeltaEntries; ++i) {
+        uint32_t sampleCount = mCompositionTimeDeltaEntries[2 * i];
+
+        if (sampleIndex < curSample + sampleCount) {
+            uint32_t sampleDelta = mCompositionTimeDeltaEntries[2 * i + 1];
+
+            return sampleDelta;
+        }
+
+        curSample += sampleCount;
+    }
+
+    return 0;
+}
+
 }  // namespace android
 
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index be3df7c..84f65ff 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -37,7 +37,7 @@
         ".mp3", ".mp4", ".m4a", ".3gp", ".3gpp", ".3g2", ".3gpp2",
         ".mpeg", ".ogg", ".mid", ".smf", ".imy", ".wma", ".aac",
         ".wav", ".amr", ".midi", ".xmf", ".rtttl", ".rtx", ".ota",
-        ".mkv", ".mka", ".webm", ".ts", ".fl"
+        ".mkv", ".mka", ".webm", ".ts", ".fl", ".flac"
     };
     static const size_t kNumValidExtensions =
         sizeof(kValidExtensions) / sizeof(kValidExtensions[0]);
diff --git a/media/libstagefright/include/AMRExtractor.h b/media/libstagefright/include/AMRExtractor.h
index 1cdf36d..589d837 100644
--- a/media/libstagefright/include/AMRExtractor.h
+++ b/media/libstagefright/include/AMRExtractor.h
@@ -24,6 +24,7 @@
 
 struct AMessage;
 class String8;
+#define OFFSET_TABLE_LEN    300
 
 class AMRExtractor : public MediaExtractor {
 public:
@@ -42,9 +43,11 @@
     sp<DataSource> mDataSource;
     sp<MetaData> mMeta;
     status_t mInitCheck;
-    size_t mFrameSize;
     bool mIsWide;
 
+    off64_t mOffsetTable[OFFSET_TABLE_LEN]; //5 min
+    size_t mOffsetTableLength;
+
     AMRExtractor(const AMRExtractor &);
     AMRExtractor &operator=(const AMRExtractor &);
 };
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 41ef181..3021359 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -119,6 +119,10 @@
         // sufficient data to begin playback and finish the preparation phase
         // for good.
         PREPARING_CONNECTED = 2048,
+
+        // We're triggering a single video event to display the first frame
+        // after the seekpoint.
+        SEEK_PREVIEW        = 4096,
     };
 
     mutable Mutex mLock;
diff --git a/media/libstagefright/include/FLACExtractor.h b/media/libstagefright/include/FLACExtractor.h
new file mode 100644
index 0000000..ded91c2
--- /dev/null
+++ b/media/libstagefright/include/FLACExtractor.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FLAC_EXTRACTOR_H_
+#define FLAC_EXTRACTOR_H_
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <utils/String8.h>
+
+namespace android {
+
+class FLACParser;
+
+class FLACExtractor : public MediaExtractor {
+
+public:
+    // Extractor assumes ownership of source
+    FLACExtractor(const sp<DataSource> &source);
+
+    virtual size_t countTracks();
+    virtual sp<MediaSource> getTrack(size_t index);
+    virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
+
+    virtual sp<MetaData> getMetaData();
+
+protected:
+    virtual ~FLACExtractor();
+
+private:
+    sp<DataSource> mDataSource;
+    sp<FLACParser> mParser;
+    status_t mInitCheck;
+    sp<MetaData> mFileMetadata;
+
+    // There is only one track
+    sp<MetaData> mTrackMetadata;
+
+    status_t init();
+
+    FLACExtractor(const FLACExtractor &);
+    FLACExtractor &operator=(const FLACExtractor &);
+
+};
+
+bool SniffFLAC(const sp<DataSource> &source, String8 *mimeType,
+        float *confidence, sp<AMessage> *);
+
+}  // namespace android
+
+#endif  // FLAC_EXTRACTOR_H_
diff --git a/media/libstagefright/include/OggExtractor.h b/media/libstagefright/include/OggExtractor.h
index 1eda025..a41f681 100644
--- a/media/libstagefright/include/OggExtractor.h
+++ b/media/libstagefright/include/OggExtractor.h
@@ -57,6 +57,9 @@
         const sp<DataSource> &source, String8 *mimeType, float *confidence,
         sp<AMessage> *);
 
+void parseVorbisComment(
+        const sp<MetaData> &fileMeta, const char *comment, size_t commentLength);
+
 }  // namespace android
 
 #endif  // OGG_EXTRACTOR_H_
diff --git a/media/libstagefright/include/SampleTable.h b/media/libstagefright/include/SampleTable.h
index c5e8136..2f95de9 100644
--- a/media/libstagefright/include/SampleTable.h
+++ b/media/libstagefright/include/SampleTable.h
@@ -46,6 +46,9 @@
 
     status_t setTimeToSampleParams(off64_t data_offset, size_t data_size);
 
+    status_t setCompositionTimeToSampleParams(
+            off64_t data_offset, size_t data_size);
+
     status_t setSyncSampleParams(off64_t data_offset, size_t data_size);
 
     ////////////////////////////////////////////////////////////////////////////
@@ -104,6 +107,9 @@
     uint32_t mTimeToSampleCount;
     uint32_t *mTimeToSample;
 
+    uint32_t *mCompositionTimeDeltaEntries;
+    size_t mNumCompositionTimeDeltaEntries;
+
     off64_t mSyncSampleOffset;
     uint32_t mNumSyncSamples;
     uint32_t *mSyncSamples;
@@ -122,6 +128,8 @@
 
     status_t getSampleSize_l(uint32_t sample_index, size_t *sample_size);
 
+    uint32_t getCompositionTimeOffset(uint32_t sampleIndex) const;
+
     SampleTable(const SampleTable &);
     SampleTable &operator=(const SampleTable &);
 };
diff --git a/media/mtp/Android.mk b/media/mtp/Android.mk
index 70dc340..c25285e 100644
--- a/media/mtp/Android.mk
+++ b/media/mtp/Android.mk
@@ -21,7 +21,6 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=                                       \
-                  MtpClient.cpp                         \
                   MtpDataPacket.cpp                     \
                   MtpDebug.cpp                          \
                   MtpDevice.cpp                         \
@@ -53,7 +52,6 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=                                       \
-                  MtpClient.cpp                         \
                   MtpDataPacket.cpp                     \
                   MtpDebug.cpp                          \
                   MtpDevice.cpp                         \
diff --git a/media/mtp/MtpClient.cpp b/media/mtp/MtpClient.cpp
deleted file mode 100644
index c830540..0000000
--- a/media/mtp/MtpClient.cpp
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "MtpClient"
-
-#include "MtpDebug.h"
-#include "MtpClient.h"
-#include "MtpDevice.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <errno.h>
-
-#include <usbhost/usbhost.h>
-
-struct usb_device;
-
-namespace android {
-
-static bool isMtpDevice(uint16_t vendor, uint16_t product) {
-    // Sandisk Sansa Fuze
-    if (vendor == 0x0781 && product == 0x74c2)
-        return true;
-    // Samsung YP-Z5
-    if (vendor == 0x04e8 && product == 0x503c)
-        return true;
-    return false;
-}
-
-class MtpClientThread : public Thread {
-private:
-    MtpClient*   mClient;
-
-public:
-    MtpClientThread(MtpClient* client)
-        : mClient(client)
-    {
-    }
-
-    virtual bool threadLoop() {
-        return mClient->threadLoop();
-    }
-};
-
-
-MtpClient::MtpClient()
-    :   mThread(NULL),
-        mUsbHostContext(NULL),
-        mDone(false)
-{
-}
-
-MtpClient::~MtpClient() {
-    usb_host_cleanup(mUsbHostContext);
-}
-
-bool MtpClient::start() {
-    Mutex::Autolock autoLock(mMutex);
-
-    if (mThread)
-        return true;
-
-    mUsbHostContext = usb_host_init();
-    if (!mUsbHostContext)
-        return false;
-
-    mThread = new MtpClientThread(this);
-    mThread->run("MtpClientThread");
-    // wait for the thread to do initial device discovery before returning
-    mThreadStartCondition.wait(mMutex);
-
-    return true;
-}
-
-void MtpClient::stop() {
-    mDone = true;
-}
-
-MtpDevice* MtpClient::getDevice(int id) {
-    for (int i = 0; i < mDeviceList.size(); i++) {
-        MtpDevice* device = mDeviceList[i];
-        if (device->getID() == id)
-            return device;
-    }
-    return NULL;
-}
-
-bool MtpClient::usbDeviceAdded(const char *devname) {
-    struct usb_descriptor_header* desc;
-    struct usb_descriptor_iter iter;
-
-    struct usb_device *device = usb_device_open(devname);
-    if (!device) {
-        LOGE("usb_device_open failed\n");
-        return mDone;
-    }
-
-    usb_descriptor_iter_init(device, &iter);
-
-    while ((desc = usb_descriptor_iter_next(&iter)) != NULL) {
-        if (desc->bDescriptorType == USB_DT_INTERFACE) {
-            struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)desc;
-
-            if (interface->bInterfaceClass == USB_CLASS_STILL_IMAGE &&
-                interface->bInterfaceSubClass == 1 && // Still Image Capture
-                interface->bInterfaceProtocol == 1)     // Picture Transfer Protocol (PIMA 15470)
-            {
-                LOGD("Found camera: \"%s\" \"%s\"\n", usb_device_get_manufacturer_name(device),
-                        usb_device_get_product_name(device));
-            } else if (interface->bInterfaceClass == 0xFF &&
-                    interface->bInterfaceSubClass == 0xFF &&
-                    interface->bInterfaceProtocol == 0) {
-                char* interfaceName = usb_device_get_string(device, interface->iInterface);
-                if (!interfaceName || strcmp(interfaceName, "MTP"))
-                    continue;
-                // Looks like an android style MTP device
-                LOGD("Found MTP device: \"%s\" \"%s\"\n", usb_device_get_manufacturer_name(device),
-                        usb_device_get_product_name(device));
-            } else {
-                // look for special cased devices based on vendor/product ID
-                // we are doing this mainly for testing purposes
-                uint16_t vendor = usb_device_get_vendor_id(device);
-                uint16_t product = usb_device_get_product_id(device);
-                if (!isMtpDevice(vendor, product)) {
-                    // not an MTP or PTP device
-                    continue;
-                }
-                // request MTP OS string and descriptor
-                // some music players need to see this before entering MTP mode.
-                char buffer[256];
-                memset(buffer, 0, sizeof(buffer));
-                int ret = usb_device_send_control(device,
-                        USB_DIR_IN|USB_RECIP_DEVICE|USB_TYPE_STANDARD,
-                        USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) | 0xEE,
-                        0, sizeof(buffer), buffer);
-                printf("usb_device_send_control returned %d errno: %d\n", ret, errno);
-                if (ret > 0) {
-                    printf("got MTP string %s\n", buffer);
-                    ret = usb_device_send_control(device,
-                            USB_DIR_IN|USB_RECIP_DEVICE|USB_TYPE_VENDOR, 1,
-                            0, 4, sizeof(buffer), buffer);
-                    printf("OS descriptor got %d\n", ret);
-                } else {
-                    printf("no MTP string\n");
-                }
-            }
-
-            // if we got here, then we have a likely MTP or PTP device
-
-            // interface should be followed by three endpoints
-            struct usb_endpoint_descriptor *ep;
-            struct usb_endpoint_descriptor *ep_in_desc = NULL;
-            struct usb_endpoint_descriptor *ep_out_desc = NULL;
-            struct usb_endpoint_descriptor *ep_intr_desc = NULL;
-            for (int i = 0; i < 3; i++) {
-                ep = (struct usb_endpoint_descriptor *)usb_descriptor_iter_next(&iter);
-                if (!ep || ep->bDescriptorType != USB_DT_ENDPOINT) {
-                    LOGE("endpoints not found\n");
-                    return mDone;
-                }
-                if (ep->bmAttributes == USB_ENDPOINT_XFER_BULK) {
-                    if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
-                        ep_in_desc = ep;
-                    else
-                        ep_out_desc = ep;
-                } else if (ep->bmAttributes == USB_ENDPOINT_XFER_INT &&
-                    ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
-                    ep_intr_desc = ep;
-                }
-            }
-            if (!ep_in_desc || !ep_out_desc || !ep_intr_desc) {
-                LOGE("endpoints not found\n");
-                return mDone;
-            }
-
-            if (usb_device_claim_interface(device, interface->bInterfaceNumber)) {
-                LOGE("usb_device_claim_interface failed errno: %d\n", errno);
-                return mDone;
-            }
-
-            MtpDevice* mtpDevice = new MtpDevice(device, interface->bInterfaceNumber,
-                        ep_in_desc, ep_out_desc, ep_intr_desc);
-            mDeviceList.add(mtpDevice);
-            mtpDevice->initialize();
-            deviceAdded(mtpDevice);
-            return mDone;
-        }
-    }
-
-    usb_device_close(device);
-    return mDone;
-}
-
-bool MtpClient::usbDeviceRemoved(const char *devname) {
-    for (int i = 0; i < mDeviceList.size(); i++) {
-        MtpDevice* device = mDeviceList[i];
-        if (!strcmp(devname, device->getDeviceName())) {
-            deviceRemoved(device);
-            mDeviceList.removeAt(i);
-            delete device;
-            LOGD("Camera removed!\n");
-            break;
-        }
-    }
-    return mDone;
-}
-
-bool MtpClient::usbDiscoveryDone() {
-    Mutex::Autolock autoLock(mMutex);
-    mThreadStartCondition.signal();
-    return mDone;
-}
-
-bool MtpClient::threadLoop() {
-    usb_host_run(mUsbHostContext, usb_device_added, usb_device_removed, usb_discovery_done, this);
-    return false;
-}
-
-int MtpClient::usb_device_added(const char *devname, void* client_data) {
-    LOGD("usb_device_added %s\n", devname);
-    return ((MtpClient *)client_data)->usbDeviceAdded(devname);
-}
-
-int MtpClient::usb_device_removed(const char *devname, void* client_data) {
-    LOGD("usb_device_removed %s\n", devname);
-    return ((MtpClient *)client_data)->usbDeviceRemoved(devname);
-}
-
-int MtpClient::usb_discovery_done(void* client_data) {
-    LOGD("usb_discovery_done\n");
-    return ((MtpClient *)client_data)->usbDiscoveryDone();
-}
-
-}  // namespace android
diff --git a/media/mtp/MtpClient.h b/media/mtp/MtpClient.h
deleted file mode 100644
index fa5c527..0000000
--- a/media/mtp/MtpClient.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _MTP_CLIENT_H
-#define _MTP_CLIENT_H
-
-#include "MtpTypes.h"
-
-#include <utils/threads.h>
-
-struct usb_host_context;
-
-namespace android {
-
-class MtpClientThread;
-
-class MtpClient {
-private:
-    MtpDeviceList               mDeviceList;
-    MtpClientThread*            mThread;
-    Condition                   mThreadStartCondition;
-    Mutex                       mMutex;
-    struct usb_host_context*    mUsbHostContext;
-    bool                        mDone;
-
-public:
-                            MtpClient();
-    virtual                 ~MtpClient();
-
-    bool                    start();
-    void                    stop();
-
-    inline MtpDeviceList&   getDeviceList() { return mDeviceList; }
-    MtpDevice*              getDevice(int id);
-
-
-    virtual void            deviceAdded(MtpDevice *device) = 0;
-    virtual void            deviceRemoved(MtpDevice *device) = 0;
-
-private:
-    // these return true if we should stop monitoring USB and clean up
-    bool                    usbDeviceAdded(const char *devname);
-    bool                    usbDeviceRemoved(const char *devname);
-    bool                    usbDiscoveryDone();
-
-    friend class MtpClientThread;
-    bool                    threadLoop();
-    static int              usb_device_added(const char *devname, void* client_data);
-    static int              usb_device_removed(const char *devname, void* client_data);
-    static int              usb_discovery_done(void* client_data);
-};
-
-}; // namespace android
-
-#endif // _MTP_CLIENT_H
diff --git a/media/mtp/MtpDevice.cpp b/media/mtp/MtpDevice.cpp
index d22c72f..fb1b073 100644
--- a/media/mtp/MtpDevice.cpp
+++ b/media/mtp/MtpDevice.cpp
@@ -38,6 +38,136 @@
 
 namespace android {
 
+static bool isMtpDevice(uint16_t vendor, uint16_t product) {
+    // Sandisk Sansa Fuze
+    if (vendor == 0x0781 && product == 0x74c2)
+        return true;
+    // Samsung YP-Z5
+    if (vendor == 0x04e8 && product == 0x503c)
+        return true;
+    return false;
+}
+
+MtpDevice* MtpDevice::open(const char* deviceName, int fd) {
+    struct usb_device *device = usb_device_new(deviceName, fd);
+    if (!device) {
+        LOGE("usb_device_new failed for %s", deviceName);
+        return NULL;
+    }
+
+    struct usb_descriptor_header* desc;
+    struct usb_descriptor_iter iter;
+
+    usb_descriptor_iter_init(device, &iter);
+
+    while ((desc = usb_descriptor_iter_next(&iter)) != NULL) {
+        if (desc->bDescriptorType == USB_DT_INTERFACE) {
+            struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)desc;
+
+            if (interface->bInterfaceClass == USB_CLASS_STILL_IMAGE &&
+                interface->bInterfaceSubClass == 1 && // Still Image Capture
+                interface->bInterfaceProtocol == 1)     // Picture Transfer Protocol (PIMA 15470)
+            {
+                char* manufacturerName = usb_device_get_manufacturer_name(device);
+                char* productName = usb_device_get_product_name(device);
+                LOGD("Found camera: \"%s\" \"%s\"\n", manufacturerName, productName);
+                free(manufacturerName);
+                free(productName);
+            } else if (interface->bInterfaceClass == 0xFF &&
+                    interface->bInterfaceSubClass == 0xFF &&
+                    interface->bInterfaceProtocol == 0) {
+                char* interfaceName = usb_device_get_string(device, interface->iInterface);
+                if (!interfaceName) {
+                    continue;
+                } else if (strcmp(interfaceName, "MTP")) {
+                    free(interfaceName);
+                    continue;
+                }
+                free(interfaceName);
+
+                // Looks like an android style MTP device
+                char* manufacturerName = usb_device_get_manufacturer_name(device);
+                char* productName = usb_device_get_product_name(device);
+                LOGD("Found MTP device: \"%s\" \"%s\"\n", manufacturerName, productName);
+                free(manufacturerName);
+                free(productName);
+            } else {
+                // look for special cased devices based on vendor/product ID
+                // we are doing this mainly for testing purposes
+                uint16_t vendor = usb_device_get_vendor_id(device);
+                uint16_t product = usb_device_get_product_id(device);
+                if (!isMtpDevice(vendor, product)) {
+                    // not an MTP or PTP device
+                    continue;
+                }
+                // request MTP OS string and descriptor
+                // some music players need to see this before entering MTP mode.
+                char buffer[256];
+                memset(buffer, 0, sizeof(buffer));
+                int ret = usb_device_control_transfer(device,
+                        USB_DIR_IN|USB_RECIP_DEVICE|USB_TYPE_STANDARD,
+                        USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) | 0xEE,
+                        0, buffer, sizeof(buffer), 0);
+                printf("usb_device_control_transfer returned %d errno: %d\n", ret, errno);
+                if (ret > 0) {
+                    printf("got MTP string %s\n", buffer);
+                    ret = usb_device_control_transfer(device,
+                            USB_DIR_IN|USB_RECIP_DEVICE|USB_TYPE_VENDOR, 1,
+                            0, 4, buffer, sizeof(buffer), 0);
+                    printf("OS descriptor got %d\n", ret);
+                } else {
+                    printf("no MTP string\n");
+                }
+            }
+
+            // if we got here, then we have a likely MTP or PTP device
+
+            // interface should be followed by three endpoints
+            struct usb_endpoint_descriptor *ep;
+            struct usb_endpoint_descriptor *ep_in_desc = NULL;
+            struct usb_endpoint_descriptor *ep_out_desc = NULL;
+            struct usb_endpoint_descriptor *ep_intr_desc = NULL;
+            for (int i = 0; i < 3; i++) {
+                ep = (struct usb_endpoint_descriptor *)usb_descriptor_iter_next(&iter);
+                if (!ep || ep->bDescriptorType != USB_DT_ENDPOINT) {
+                    LOGE("endpoints not found\n");
+                    usb_device_close(device);
+                    return NULL;
+                }
+                if (ep->bmAttributes == USB_ENDPOINT_XFER_BULK) {
+                    if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+                        ep_in_desc = ep;
+                    else
+                        ep_out_desc = ep;
+                } else if (ep->bmAttributes == USB_ENDPOINT_XFER_INT &&
+                    ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
+                    ep_intr_desc = ep;
+                }
+            }
+            if (!ep_in_desc || !ep_out_desc || !ep_intr_desc) {
+                LOGE("endpoints not found\n");
+                usb_device_close(device);
+                return NULL;
+            }
+
+            if (usb_device_claim_interface(device, interface->bInterfaceNumber)) {
+                LOGE("usb_device_claim_interface failed errno: %d\n", errno);
+                usb_device_close(device);
+                return NULL;
+            }
+
+            MtpDevice* mtpDevice = new MtpDevice(device, interface->bInterfaceNumber,
+                        ep_in_desc, ep_out_desc, ep_intr_desc);
+            mtpDevice->initialize();
+            return mtpDevice;
+        }
+    }
+
+    usb_device_close(device);
+    LOGE("device not found");
+    return NULL;
+}
+
 MtpDevice::MtpDevice(struct usb_device* device, int interface,
             const struct usb_endpoint_descriptor *ep_in,
             const struct usb_endpoint_descriptor *ep_out,
@@ -49,7 +179,6 @@
         mRequestOut(NULL),
         mRequestIntr(NULL),
         mDeviceInfo(NULL),
-        mID(usb_device_get_unique_id(device)),
         mSessionID(0),
         mTransactionID(0),
         mReceivedResponse(false)
@@ -106,6 +235,7 @@
                 MtpProperty* property = getDevicePropDesc(propCode);
                 if (property) {
                     property->print();
+                    delete property;
                 }
             }
         }
@@ -122,11 +252,13 @@
                 for (int j = 0; j < props->size(); j++) {
                     MtpObjectProperty prop = (*props)[j];
                     MtpProperty* property = getObjectPropDesc(prop, format);
-                    if (property)
+                    if (property) {
                         property->print();
-                    else
+                        delete property;
+                    } else {
                         LOGE("could not fetch property: %s",
                                 MtpDebug::getObjectPropCodeName(prop));
+                    }
                 }
             }
         }
@@ -362,18 +494,24 @@
 
 MtpObjectHandle MtpDevice::getParent(MtpObjectHandle handle) {
     MtpObjectInfo* info = getObjectInfo(handle);
-    if (info)
-        return info->mParent;
-    else
+    if (info) {
+        MtpObjectHandle parent = info->mParent;
+        delete info;
+        return parent;
+    } else {
         return -1;
+    }
 }
 
 MtpObjectHandle MtpDevice::getStorageID(MtpObjectHandle handle) {
     MtpObjectInfo* info = getObjectInfo(handle);
-    if (info)
-        return info->mStorageID;
-    else
+    if (info) {
+        MtpObjectHandle storageId = info->mStorageID;
+        delete info;
+        return storageId;
+    } else {
         return -1;
+    }
 }
 
 MtpObjectPropertyList* MtpDevice::getObjectPropsSupported(MtpObjectFormat format) {
@@ -430,6 +568,98 @@
     return NULL;
 }
 
+bool MtpDevice::readObject(MtpObjectHandle handle,
+        bool (* callback)(void* data, int offset, int length, void* clientData),
+        int objectSize, void* clientData) {
+    Mutex::Autolock autoLock(mMutex);
+    bool result = false;
+
+    mRequest.reset();
+    mRequest.setParameter(1, handle);
+    if (sendRequest(MTP_OPERATION_GET_OBJECT)
+            && mData.readDataHeader(mRequestIn1)) {
+        uint32_t length = mData.getContainerLength();
+        if (length - MTP_CONTAINER_HEADER_SIZE != objectSize) {
+            LOGE("readObject error objectSize: %d, length: %d",
+                    objectSize, length);
+            goto fail;
+        }
+        length -= MTP_CONTAINER_HEADER_SIZE;
+        uint32_t remaining = length;
+        int offset = 0;
+
+        int initialDataLength = 0;
+        void* initialData = mData.getData(initialDataLength);
+        if (initialData) {
+            if (initialDataLength > 0) {
+                if (!callback(initialData, 0, initialDataLength, clientData))
+                    goto fail;
+                remaining -= initialDataLength;
+                offset += initialDataLength;
+            }
+            free(initialData);
+        }
+
+        // USB reads greater than 16K don't work
+        char buffer1[16384], buffer2[16384];
+        mRequestIn1->buffer = buffer1;
+        mRequestIn2->buffer = buffer2;
+        struct usb_request* req = mRequestIn1;
+        void* writeBuffer = NULL;
+        int writeLength = 0;
+
+        while (remaining > 0 || writeBuffer) {
+            if (remaining > 0) {
+                // queue up a read request
+                req->buffer_length = (remaining > sizeof(buffer1) ? sizeof(buffer1) : remaining);
+                if (mData.readDataAsync(req)) {
+                    LOGE("readDataAsync failed");
+                    goto fail;
+                }
+            } else {
+                req = NULL;
+            }
+
+            if (writeBuffer) {
+                // write previous buffer
+                if (!callback(writeBuffer, offset, writeLength, clientData)) {
+                    LOGE("write failed");
+                    // wait for pending read before failing
+                    if (req)
+                        mData.readDataWait(mDevice);
+                    goto fail;
+                }
+                offset += writeLength;
+                writeBuffer = NULL;
+            }
+
+            // wait for read to complete
+            if (req) {
+                int read = mData.readDataWait(mDevice);
+                if (read < 0)
+                    goto fail;
+
+                if (read > 0) {
+                    writeBuffer = req->buffer;
+                    writeLength = read;
+                    remaining -= read;
+                    req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1);
+                } else {
+                    writeBuffer = NULL;
+                }
+            }
+        }
+
+        MtpResponseCode response = readResponse();
+        if (response == MTP_RESPONSE_OK)
+            result = true;
+    }
+
+fail:
+    return result;
+}
+
+
 // reads the object's data and writes it to the specified file path
 bool MtpDevice::readObject(MtpObjectHandle handle, const char* destPath, int group, int perm) {
     LOGD("readObject: %s", destPath);
@@ -462,8 +692,10 @@
         void* initialData = mData.getData(initialDataLength);
         if (initialData) {
             if (initialDataLength > 0) {
-                if (write(fd, initialData, initialDataLength) != initialDataLength)
+                if (write(fd, initialData, initialDataLength) != initialDataLength) {
+                    free(initialData);
                     goto fail;
+                }
                 remaining -= initialDataLength;
             }
             free(initialData);
@@ -507,10 +739,14 @@
                 if (read < 0)
                     goto fail;
 
-                writeBuffer = req->buffer;
-                writeLength = read;
-                remaining -= read;
-                req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1);
+                if (read > 0) {
+                    writeBuffer = req->buffer;
+                    writeLength = read;
+                    remaining -= read;
+                    req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1);
+                } else {
+                    writeBuffer = NULL;
+                }
             }
         }
 
diff --git a/media/mtp/MtpDevice.h b/media/mtp/MtpDevice.h
index d0a0fb3..b69203e 100644
--- a/media/mtp/MtpDevice.h
+++ b/media/mtp/MtpDevice.h
@@ -45,9 +45,6 @@
     MtpDeviceInfo*          mDeviceInfo;
     MtpPropertyList         mDeviceProperties;
 
-    // a unique ID for the device
-    int                     mID;
-
     // current session ID
     MtpSessionID            mSessionID;
     // current transaction ID
@@ -67,9 +64,10 @@
                                     const struct usb_endpoint_descriptor *ep_in,
                                     const struct usb_endpoint_descriptor *ep_out,
                                     const struct usb_endpoint_descriptor *ep_intr);
-    virtual                 ~MtpDevice();
 
-    inline int              getID() const { return mID; }
+    static MtpDevice*       open(const char* deviceName, int fd);
+
+    virtual                 ~MtpDevice();
 
     void                    initialize();
     void                    close();
@@ -97,7 +95,11 @@
     MtpProperty*            getDevicePropDesc(MtpDeviceProperty code);
     MtpProperty*            getObjectPropDesc(MtpObjectProperty code, MtpObjectFormat format);
 
-    bool                   readObject(MtpObjectHandle handle, const char* destPath, int group,
+    bool                    readObject(MtpObjectHandle handle,
+                                    bool (* callback)(void* data, int offset,
+                                            int length, void* clientData),
+                                    int objectSize, void* clientData);
+    bool                    readObject(MtpObjectHandle handle, const char* destPath, int group,
                                     int perm);
 
 private:
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index be004d2..853a5af 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -343,8 +343,9 @@
     mData.putAUInt16(deviceProperties); // Device Properties Supported
     mData.putAUInt16(captureFormats); // Capture Formats
     mData.putAUInt16(playbackFormats);  // Playback Formats
-    // FIXME
-    string.set("Google, Inc.");
+
+    property_get("ro.product.manufacturer", prop_value, "unknown manufacturer");
+    string.set(prop_value);
     mData.putString(string);   // Manufacturer
 
     property_get("ro.product.model", prop_value, "MTP Device");
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 22ecc54..69a4adc 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -120,12 +120,4 @@
     endif
 endif
 
-ifeq ($(BOARD_USE_LVMX),true)
-    LOCAL_CFLAGS += -DLVMX
-    LOCAL_C_INCLUDES += vendor/nxp
-    LOCAL_STATIC_LIBRARIES += liblifevibes
-    LOCAL_SHARED_LIBRARIES += liblvmxservice
-#    LOCAL_SHARED_LIBRARIES += liblvmxipc
-endif
-
 include $(BUILD_SHARED_LIBRARY)
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 4ec16c1..704da72 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -47,10 +47,6 @@
 #include "A2dpAudioInterface.h"
 #endif
 
-#ifdef LVMX
-#include "lifevibes.h"
-#endif
-
 #include <media/EffectsFactoryApi.h>
 #include <media/EffectVisualizerApi.h>
 
@@ -149,10 +145,6 @@
     } else {
         LOGE("Couldn't even initialize the stubbed audio hardware!");
     }
-#ifdef LVMX
-    LifeVibes::init();
-    mLifeVibesClientPid = -1;
-#endif
 }
 
 AudioFlinger::~AudioFlinger()
@@ -485,9 +477,6 @@
         mMode = mode;
         for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
            mPlaybackThreads.valueAt(i)->setMode(mode);
-#ifdef LVMX
-        LifeVibes::setMode(mode);
-#endif
     }
 
     return ret;
@@ -635,39 +624,11 @@
         return PERMISSION_DENIED;
     }
 
-#ifdef LVMX
-    AudioParameter param = AudioParameter(keyValuePairs);
-    LifeVibes::setParameters(ioHandle,keyValuePairs);
-    String8 key = String8(AudioParameter::keyRouting);
-    int device;
-    if (NO_ERROR != param.getInt(key, device)) {
-        device = -1;
-    }
-
-    key = String8(LifevibesTag);
-    String8 value;
-    int musicEnabled = -1;
-    if (NO_ERROR == param.get(key, value)) {
-        if (value == LifevibesEnable) {
-            mLifeVibesClientPid = IPCThreadState::self()->getCallingPid();
-            musicEnabled = 1;
-        } else if (value == LifevibesDisable) {
-            mLifeVibesClientPid = -1;
-            musicEnabled = 0;
-        }
-    }
-#endif
-
     // ioHandle == 0 means the parameters are global to the audio hardware interface
     if (ioHandle == 0) {
         AutoMutex lock(mHardwareLock);
         mHardwareStatus = AUDIO_SET_PARAMETER;
         result = mAudioHardware->setParameters(keyValuePairs);
-#ifdef LVMX
-        if (musicEnabled != -1) {
-            LifeVibes::enableMusic((bool) musicEnabled);
-        }
-#endif
         mHardwareStatus = AUDIO_HW_IDLE;
         return result;
     }
@@ -684,11 +645,6 @@
     }
     if (thread != NULL) {
         result = thread->setParameters(keyValuePairs);
-#ifdef LVMX
-        if ((NO_ERROR == result) && (device != -1)) {
-            LifeVibes::setDevice(LifeVibes::threadIdToAudioOutputType(thread->id()), device);
-        }
-#endif
         return result;
     }
     return BAD_VALUE;
@@ -802,13 +758,6 @@
     if (index >= 0) {
         sp <NotificationClient> client = mNotificationClients.valueFor(pid);
         LOGV("removeNotificationClient() %p, pid %d", client.get(), pid);
-#ifdef LVMX
-        if (pid == mLifeVibesClientPid) {
-            LOGV("Disabling lifevibes");
-            LifeVibes::enableMusic(false);
-            mLifeVibesClientPid = -1;
-        }
-#endif
         mNotificationClients.removeItem(pid);
     }
 }
@@ -1214,24 +1163,12 @@
 
 status_t AudioFlinger::PlaybackThread::setMasterVolume(float value)
 {
-#ifdef LVMX
-    int audioOutputType = LifeVibes::getMixerType(mId, mType);
-    if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) {
-        LifeVibes::setMasterVolume(audioOutputType, value);
-    }
-#endif
     mMasterVolume = value;
     return NO_ERROR;
 }
 
 status_t AudioFlinger::PlaybackThread::setMasterMute(bool muted)
 {
-#ifdef LVMX
-    int audioOutputType = LifeVibes::getMixerType(mId, mType);
-    if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) {
-        LifeVibes::setMasterMute(audioOutputType, muted);
-    }
-#endif
     mMasterMute = muted;
     return NO_ERROR;
 }
@@ -1248,24 +1185,12 @@
 
 status_t AudioFlinger::PlaybackThread::setStreamVolume(int stream, float value)
 {
-#ifdef LVMX
-    int audioOutputType = LifeVibes::getMixerType(mId, mType);
-    if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) {
-        LifeVibes::setStreamVolume(audioOutputType, stream, value);
-    }
-#endif
     mStreamTypes[stream].volume = value;
     return NO_ERROR;
 }
 
 status_t AudioFlinger::PlaybackThread::setStreamMute(int stream, bool muted)
 {
-#ifdef LVMX
-    int audioOutputType = LifeVibes::getMixerType(mId, mType);
-    if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) {
-        LifeVibes::setStreamMute(audioOutputType, stream, muted);
-    }
-#endif
     mStreamTypes[stream].mute = muted;
     return NO_ERROR;
 }
@@ -1593,12 +1518,6 @@
              }
              // enable changes in effect chain
              unlockEffectChains(effectChains);
-#ifdef LVMX
-            int audioOutputType = LifeVibes::getMixerType(mId, mType);
-            if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) {
-               LifeVibes::process(audioOutputType, mMixBuffer, mixBufferSize);
-            }
-#endif
             mLastWriteTime = systemTime();
             mInWrite = true;
             mBytesWritten += mixBufferSize;
@@ -1661,24 +1580,6 @@
     if (masterMute) {
         masterVolume = 0;
     }
-#ifdef LVMX
-    bool tracksConnectedChanged = false;
-    bool stateChanged = false;
-
-    int audioOutputType = LifeVibes::getMixerType(mId, mType);
-    if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType))
-    {
-        int activeTypes = 0;
-        for (size_t i=0 ; i<count ; i++) {
-            sp<Track> t = activeTracks[i].promote();
-            if (t == 0) continue;
-            Track* const track = t.get();
-            int iTracktype=track->type();
-            activeTypes |= 1<<track->type();
-        }
-        LifeVibes::computeVolumes(audioOutputType, activeTypes, tracksConnectedChanged, stateChanged, masterVolume, masterMute);
-    }
-#endif
     // Delegate master volume control to effect in output mix effect chain if needed
     sp<EffectChain> chain = getEffectChain_l(AudioSystem::SESSION_OUTPUT_MIX);
     if (chain != 0) {
@@ -1746,17 +1647,6 @@
 
                 // read original volumes with volume control
                 float typeVolume = mStreamTypes[track->type()].volume;
-#ifdef LVMX
-                bool streamMute=false;
-                // read the volume from the LivesVibes audio engine.
-                if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType))
-                {
-                    LifeVibes::getStreamVolumes(audioOutputType, track->type(), &typeVolume, &streamMute);
-                    if (streamMute) {
-                        typeVolume = 0;
-                    }
-                }
-#endif
                 float v = masterVolume * typeVolume;
                 vl = (uint32_t)(v * cblk->volume[0]) << 12;
                 vr = (uint32_t)(v * cblk->volume[1]) << 12;
@@ -1789,14 +1679,6 @@
             if (va > MAX_GAIN_INT) va = MAX_GAIN_INT;
             aux = int16_t(va);
 
-#ifdef LVMX
-            if ( tracksConnectedChanged || stateChanged )
-            {
-                 // only do the ramp when the volume is changed by the user / application
-                 param = AudioMixer::VOLUME;
-            }
-#endif
-
             // XXX: these things DON'T need to be done each time
             mAudioMixer->setBufferProvider(track);
             mAudioMixer->enable(AudioMixer::MIXING);
@@ -4292,18 +4174,6 @@
         } else {
             thread = new MixerThread(this, output, id, *pDevices);
             LOGV("openOutput() created mixer output: ID %d thread %p", id, thread);
-
-#ifdef LVMX
-            unsigned bitsPerSample =
-                (format == AudioSystem::PCM_16_BIT) ? 16 :
-                    ((format == AudioSystem::PCM_8_BIT) ? 8 : 0);
-            unsigned channelCount = (channels == AudioSystem::CHANNEL_OUT_STEREO) ? 2 : 1;
-            int audioOutputType = LifeVibes::threadIdToAudioOutputType(thread->id());
-
-            LifeVibes::init_aot(audioOutputType, samplingRate, bitsPerSample, channelCount);
-            LifeVibes::setDevice(audioOutputType, *pDevices);
-#endif
-
         }
         mPlaybackThreads.add(id, thread);
 
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 81f2eb4..ec3d202 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -1181,9 +1181,6 @@
 
                 DefaultKeyedVector< pid_t, sp<NotificationClient> >    mNotificationClients;
                 volatile int32_t                    mNextUniqueId;
-#ifdef LVMX
-                int mLifeVibesClientPid;
-#endif
                 uint32_t mMode;
 
 };
diff --git a/services/audioflinger/AudioPolicyManagerBase.cpp b/services/audioflinger/AudioPolicyManagerBase.cpp
index afa9acc..04d63e6 100644
--- a/services/audioflinger/AudioPolicyManagerBase.cpp
+++ b/services/audioflinger/AudioPolicyManagerBase.cpp
@@ -19,6 +19,7 @@
 #include <utils/Log.h>
 #include <hardware_legacy/AudioPolicyManagerBase.h>
 #include <media/mediarecorder.h>
+#include <math.h>
 
 namespace android {
 
@@ -1030,6 +1031,8 @@
         mForceUse[i] = AudioSystem::FORCE_NONE;
     }
 
+    initializeVolumeCurves();
+
     // devices available by default are speaker, ear piece and microphone
     mAvailableOutputDevices = AudioSystem::DEVICE_OUT_EARPIECE |
                         AudioSystem::DEVICE_OUT_SPEAKER;
@@ -1821,6 +1824,62 @@
     return 0;
 }
 
+float AudioPolicyManagerBase::volIndexToAmpl(uint32_t device, const StreamDescriptor& streamDesc,
+        int indexInUi) {
+    // the volume index in the UI is relative to the min and max volume indices for this stream type
+    int nbSteps = 1 + streamDesc.mVolIndex[StreamDescriptor::VOLMAX] -
+            streamDesc.mVolIndex[StreamDescriptor::VOLMIN];
+    int volIdx = (nbSteps * (indexInUi - streamDesc.mIndexMin)) /
+            (streamDesc.mIndexMax - streamDesc.mIndexMin);
+
+    // find what part of the curve this index volume belongs to, or if it's out of bounds
+    int segment = 0;
+    if (volIdx < streamDesc.mVolIndex[StreamDescriptor::VOLMIN]) {         // out of bounds
+        return 0.0f;
+    } else if (volIdx < streamDesc.mVolIndex[StreamDescriptor::VOLKNEE1]) {
+        segment = 0;
+    } else if (volIdx < streamDesc.mVolIndex[StreamDescriptor::VOLKNEE2]) {
+        segment = 1;
+    } else if (volIdx <= streamDesc.mVolIndex[StreamDescriptor::VOLMAX]) {
+        segment = 2;
+    } else {                                                               // out of bounds
+        return 1.0f;
+    }
+
+    // linear interpolation in the attenuation table in dB
+    float decibels = streamDesc.mVolDbAtt[segment] +
+            ((float)(volIdx - streamDesc.mVolIndex[segment])) *
+                ( (streamDesc.mVolDbAtt[segment+1] - streamDesc.mVolDbAtt[segment]) /
+                    ((float)(streamDesc.mVolIndex[segment+1] - streamDesc.mVolIndex[segment])) );
+
+    float amplification = exp( decibels * 0.115129f); // exp( dB * ln(10) / 20 )
+
+    LOGV("VOLUME vol index=[%d %d %d], dB=[%.1f %.1f %.1f] ampl=%.5f",
+            streamDesc.mVolIndex[segment], volIdx, streamDesc.mVolIndex[segment+1],
+            streamDesc.mVolDbAtt[segment], decibels, streamDesc.mVolDbAtt[segment+1],
+            amplification);
+
+    return amplification;
+}
+
+void AudioPolicyManagerBase::initializeVolumeCurves() {
+    // initialize the volume curves to a (-49.5 - 0 dB) attenuation in 0.5dB steps
+    for (int i=0 ; i< AudioSystem::NUM_STREAM_TYPES ; i++) {
+        mStreams[i].mVolIndex[StreamDescriptor::VOLMIN] = 1;
+        mStreams[i].mVolDbAtt[StreamDescriptor::VOLMIN] = -49.5f;
+        mStreams[i].mVolIndex[StreamDescriptor::VOLKNEE1] = 33;
+        mStreams[i].mVolDbAtt[StreamDescriptor::VOLKNEE1] = -33.5f;
+        mStreams[i].mVolIndex[StreamDescriptor::VOLKNEE2] = 66;
+        mStreams[i].mVolDbAtt[StreamDescriptor::VOLKNEE2] = -17.0f;
+        // here we use 100 steps to avoid rounding errors
+        // when computing the volume in volIndexToAmpl()
+        mStreams[i].mVolIndex[StreamDescriptor::VOLMAX] = 100;
+        mStreams[i].mVolDbAtt[StreamDescriptor::VOLMAX] = 0.0f;
+    }
+
+    // TODO add modifications for music to have finer steps below knee1 and above knee2
+}
+
 float AudioPolicyManagerBase::computeVolume(int stream, int index, audio_io_handle_t output, uint32_t device)
 {
     float volume = 1.0;
@@ -1831,8 +1890,7 @@
         device = outputDesc->device();
     }
 
-    int volInt = (100 * (index - streamDesc.mIndexMin)) / (streamDesc.mIndexMax - streamDesc.mIndexMin);
-    volume = AudioSystem::linearToLog(volInt);
+    volume = volIndexToAmpl(device, streamDesc, index);
 
     // if a headset is connected, apply the following rules to ring tones and notifications
     // to avoid sound level bursts in user's ears:
diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp
index b04672d..953ddac 100644
--- a/services/audioflinger/AudioPolicyService.cpp
+++ b/services/audioflinger/AudioPolicyService.cpp
@@ -488,13 +488,6 @@
 
 
 // ----------------------------------------------------------------------------
-void AudioPolicyService::instantiate() {
-    defaultServiceManager()->addService(
-            String16("media.audio_policy"), new AudioPolicyService());
-}
-
-
-// ----------------------------------------------------------------------------
 // AudioPolicyClientInterface implementation
 // ----------------------------------------------------------------------------
 
diff --git a/services/audioflinger/AudioPolicyService.h b/services/audioflinger/AudioPolicyService.h
index 54af1f1..4749b8b 100644
--- a/services/audioflinger/AudioPolicyService.h
+++ b/services/audioflinger/AudioPolicyService.h
@@ -21,6 +21,7 @@
 #include <hardware_legacy/AudioPolicyInterface.h>
 #include <media/ToneGenerator.h>
 #include <utils/Vector.h>
+#include <binder/BinderService.h>
 
 namespace android {
 
@@ -28,12 +29,17 @@
 
 // ----------------------------------------------------------------------------
 
-class AudioPolicyService: public BnAudioPolicyService, public AudioPolicyClientInterface,
+class AudioPolicyService :
+    public BinderService<AudioPolicyService>,
+    public BnAudioPolicyService,
+    public AudioPolicyClientInterface,
     public IBinder::DeathRecipient
 {
+    friend class BinderService<AudioPolicyService>;
 
 public:
-    static  void        instantiate();
+    // for BinderService
+    static const char *getServiceName() { return "media.audio_policy"; }
 
     virtual status_t    dump(int fd, const Vector<String16>& args);
 
@@ -241,11 +247,3 @@
 }; // namespace android
 
 #endif // ANDROID_AUDIOPOLICYSERVICE_H
-
-
-
-
-
-
-
-