Merge change 24179 into eclair

* changes:
  Support encoding amr-wb content in stagefright.
diff --git a/include/media/MediaMetadataRetrieverInterface.h b/include/media/MediaMetadataRetrieverInterface.h
index b178836..e228357 100644
--- a/include/media/MediaMetadataRetrieverInterface.h
+++ b/include/media/MediaMetadataRetrieverInterface.h
@@ -44,6 +44,28 @@
 {
 public:
     virtual             ~MediaMetadataRetrieverInterface() {}
+
+    // @param mode The intended mode of operations:
+    // can be any of the following:
+    // METADATA_MODE_NOOP: Experimental - just add and remove data source.
+    // METADATA_MODE_FRAME_CAPTURE_ONLY: For capture frame/thumbnail only.
+    // METADATA_MODE_METADATA_RETRIEVAL_ONLY: For meta data retrieval only.
+    // METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL: For both frame
+    //     capture and meta data retrieval.
+    virtual status_t    setMode(int mode) {
+                            if (mode < METADATA_MODE_NOOP ||
+                                mode > METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL) {
+                                return BAD_VALUE;
+                            }
+                            return NO_ERROR;
+                        }
+
+    virtual status_t    getMode(int* mode) const { *mode = mMode; return NO_ERROR; }
+    virtual VideoFrame* captureFrame() { return NULL; }
+    virtual MediaAlbumArt* extractAlbumArt() { return NULL; }
+    virtual const char* extractMetadata(int keyCode) { return NULL; }
+
+    uint32_t mMode;
 };
 
 }; // namespace android
diff --git a/include/media/ToneGenerator.h b/include/media/ToneGenerator.h
index eafa661..ea6bf5d 100644
--- a/include/media/ToneGenerator.h
+++ b/include/media/ToneGenerator.h
@@ -154,7 +154,7 @@
     ToneGenerator(int streamType, float volume);
     ~ToneGenerator();
 
-    bool startTone(int toneType);
+    bool startTone(int toneType, int durationMs = -1);
     void stopTone();
 
     bool isInited() { return (mState == TONE_IDLE)?false:true;}
@@ -246,6 +246,7 @@
     // NOTE: because mTotalSmp, mNextSegSmp are stored on 32 bit, current design will operate properly
     // only if tone duration is less than about 27 Hours(@44100Hz sampling rate). If this time is exceeded,
     // no crash will occur but tone sequence will show a glitch.
+    unsigned int mMaxSmp;  // Maximum number of audio samples played (maximun tone duration)
 
     unsigned short mCurSegment;  // Current segment index in ToneDescriptor segments[]
     unsigned short mCurCount;  // Current sequence repeat count
diff --git a/include/media/mediametadataretriever.h b/include/media/mediametadataretriever.h
index 9ea2775..cfc205c 100644
--- a/include/media/mediametadataretriever.h
+++ b/include/media/mediametadataretriever.h
@@ -56,6 +56,18 @@
     // Add more here...
 };
 
+// The intended mode of operations:$
+// METADATA_MODE_NOOP: Experimental - just add and remove data source.$
+// METADATA_MODE_FRAME_CAPTURE_ONLY: For capture frame/thumbnail only.$
+// METADATA_MODE_METADATA_RETRIEVAL_ONLY: For meta data retrieval only.$
+// METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL: For both frame capture
+//   and meta data retrieval.$
+enum {
+    METADATA_MODE_NOOP                                 = 0x00,
+    METADATA_MODE_FRAME_CAPTURE_ONLY                   = 0x01,
+    METADATA_MODE_METADATA_RETRIEVAL_ONLY              = 0x02,
+    METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL = 0x03
+};
 
 class MediaMetadataRetriever: public RefBase
 {
diff --git a/include/private/ui/LayerState.h b/include/private/ui/LayerState.h
index b6fcd80..f1a2618 100644
--- a/include/private/ui/LayerState.h
+++ b/include/private/ui/LayerState.h
@@ -25,8 +25,6 @@
 #include <ui/ISurfaceFlingerClient.h>
 #include <ui/Region.h>
 
-#include <private/ui/SharedState.h>
-
 namespace android {
 
 class Parcel;
diff --git a/include/private/ui/SharedBufferStack.h b/include/private/ui/SharedBufferStack.h
new file mode 100644
index 0000000..2bd5344
--- /dev/null
+++ b/include/private/ui/SharedBufferStack.h
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_UI_SHARED_BUFFER_STACK_H
+#define ANDROID_UI_SHARED_BUFFER_STACK_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <cutils/compiler.h>
+
+#include <utils/Debug.h>
+#include <utils/threads.h>
+#include <utils/String8.h>
+
+#include <ui/Rect.h>
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+/*
+ * These classes manage a stack of buffers in shared memory.
+ * 
+ * SharedClient: represents a client with several stacks
+ * SharedBufferStack: represents a stack of buffers
+ * SharedBufferClient: manipulates the SharedBufferStack from the client side 
+ * SharedBufferServer: manipulates the SharedBufferStack from the server side 
+ *
+ * Buffers can be dequeued until there are none available, they can be locked
+ * unless they are in use by the server, which is only the case for the last 
+ * dequeue-able buffer. When these various conditions are not met, the caller
+ * waits until the condition is met.
+ *
+ * 
+ * CAVEATS:
+ * 
+ * In the current implementation there are several limitations:
+ * - buffers must be locked in the same order they've been dequeued
+ * - buffers must be enqueued in the same order they've been locked
+ * - dequeue() is not reentrant
+ * - no error checks are done on the condition above
+ * 
+ */
+
+// When changing these values, the COMPILE_TIME_ASSERT at the end of this
+// file need to be updated.
+const unsigned int NUM_LAYERS_MAX  = 31;
+const unsigned int NUM_BUFFER_MAX  = 4;
+const unsigned int NUM_DISPLAY_MAX = 4;
+
+// ----------------------------------------------------------------------------
+
+class Region;
+class SharedBufferStack;
+class SharedClient;
+
+// ----------------------------------------------------------------------------
+
+struct FlatRegion { // 12 bytes
+    static const unsigned int NUM_RECT_MAX = 1;
+    uint32_t    count;
+    uint16_t    rects[4*NUM_RECT_MAX];
+};
+
+// should be 128 bytes (32 longs)
+class SharedBufferStack
+{
+    friend class SharedClient;
+    friend class SharedBufferBase;
+    friend class SharedBufferClient;
+    friend class SharedBufferServer;
+
+public:
+    SharedBufferStack();
+    status_t setDirtyRegion(int buffer, const Region& reg);
+    Region getDirtyRegion(int buffer) const;
+
+    // these attributes are part of the conditions/updates
+    volatile int32_t head;      // server's current front buffer
+    volatile int32_t available; // number of dequeue-able buffers
+    volatile int32_t queued;    // number of buffers waiting for post
+    volatile int32_t inUse;     // buffer currently in use by SF
+
+    // not part of the conditions
+    volatile int32_t reallocMask;
+
+    int32_t     identity;       // surface's identity (const)
+    status_t    status;         // surface's status code
+    int32_t     reserved32[13];
+    FlatRegion  dirtyRegion[NUM_BUFFER_MAX];    // 12*4=48 bytes
+};
+
+// ----------------------------------------------------------------------------
+
+// 4 KB max
+class SharedClient
+{
+public:
+    SharedClient();
+    ~SharedClient();
+
+    status_t validate(size_t token) const;
+    uint32_t getIdentity(size_t token) const;
+    status_t setIdentity(size_t token, uint32_t identity);
+
+private:
+    friend class SharedBufferBase;
+    friend class SharedBufferClient;
+    friend class SharedBufferServer;
+
+    // FIXME: this should be replaced by a lock-less primitive
+    Mutex lock;
+    Condition cv;
+    SharedBufferStack surfaces[ NUM_LAYERS_MAX ];
+};
+
+// ============================================================================
+
+class SharedBufferBase
+{
+public:
+    SharedBufferBase(SharedClient* sharedClient, int surface, int num);
+    ~SharedBufferBase();
+    uint32_t getIdentity();
+    size_t getFrontBuffer() const;
+    String8 dump(char const* prefix) const;
+
+protected:
+    SharedClient* const mSharedClient;
+    SharedBufferStack* const mSharedStack;
+    const int mNumBuffers;
+
+    friend struct Update;
+    friend struct QueueUpdate;
+
+    struct ConditionBase {
+        SharedBufferStack& stack;
+        inline ConditionBase(SharedBufferBase* sbc) 
+            : stack(*sbc->mSharedStack) { }
+    };
+
+    struct UpdateBase {
+        SharedBufferStack& stack;
+        inline UpdateBase(SharedBufferBase* sbb) 
+            : stack(*sbb->mSharedStack) { }
+    };
+
+    template <typename T>
+    status_t waitForCondition(T condition);
+
+    template <typename T>
+    status_t updateCondition(T update);
+};
+
+template <typename T>
+status_t SharedBufferBase::waitForCondition(T condition) 
+{
+    SharedClient& client( *mSharedClient );
+    const nsecs_t TIMEOUT = s2ns(1); 
+    Mutex::Autolock _l(client.lock);
+    while (!condition()) {
+        status_t err = client.cv.waitRelative(client.lock, TIMEOUT);
+        
+        // handle errors and timeouts
+        if (CC_UNLIKELY(err != NO_ERROR)) {
+            if (err == TIMED_OUT) {
+                if (condition()) {
+                    LOGE("waitForCondition(%s) timed out (identity=%d), "
+                            "but condition is true! We recovered but it "
+                            "shouldn't happen." , 
+                            T::name(), mSharedStack->identity);
+                    break;
+                } else {
+                    LOGW("waitForCondition(%s) timed out (identity=%d). "
+                            "CPU may be pegged. trying again.",
+                            T::name(), mSharedStack->identity);
+                }
+            } else {
+                LOGE("waitForCondition(%s) error (%s) ",
+                        T::name(), strerror(-err));
+                return err;
+            }
+        }
+    }
+    return NO_ERROR;
+}
+
+
+template <typename T>
+status_t SharedBufferBase::updateCondition(T update) {
+    SharedClient& client( *mSharedClient );
+    Mutex::Autolock _l(client.lock);
+    ssize_t result = update();
+    client.cv.broadcast();    
+    return result;
+}
+
+// ----------------------------------------------------------------------------
+
+class SharedBufferClient : public SharedBufferBase
+{
+public:
+    SharedBufferClient(SharedClient* sharedClient, int surface, int num);
+    
+    ssize_t dequeue();
+    status_t undoDequeue(int buf);
+    
+    status_t lock(int buf);
+    status_t queue(int buf);
+    bool needNewBuffer(int buffer) const;
+    status_t setDirtyRegion(int buffer, const Region& reg);
+
+private:
+    friend struct Condition;
+    friend struct DequeueCondition;
+    friend struct LockCondition;
+
+    struct QueueUpdate : public UpdateBase {
+        inline QueueUpdate(SharedBufferBase* sbb);
+        inline ssize_t operator()();
+    };
+
+    struct UndoDequeueUpdate : public UpdateBase {
+        inline UndoDequeueUpdate(SharedBufferBase* sbb);
+        inline ssize_t operator()();
+    };
+
+    // --
+
+    struct DequeueCondition : public ConditionBase {
+        inline DequeueCondition(SharedBufferClient* sbc);
+        inline bool operator()();
+        static inline const char* name() { return "DequeueCondition"; }
+    };
+
+    struct LockCondition : public ConditionBase {
+        int buf;
+        inline LockCondition(SharedBufferClient* sbc, int buf);
+        inline bool operator()();
+        static inline const char* name() { return "LockCondition"; }
+    };
+
+    int32_t tail;
+};
+
+// ----------------------------------------------------------------------------
+
+class SharedBufferServer : public SharedBufferBase
+{
+public:
+    SharedBufferServer(SharedClient* sharedClient, int surface, int num);
+
+    ssize_t retireAndLock();
+    status_t unlock(int buffer);
+    status_t reallocate();
+    status_t assertReallocate(int buffer);
+
+    Region getDirtyRegion(int buffer) const;
+
+private:
+    struct UnlockUpdate : public UpdateBase {
+        const int lockedBuffer;
+        inline UnlockUpdate(SharedBufferBase* sbb, int lockedBuffer);
+        inline ssize_t operator()();
+    };
+
+    struct RetireUpdate : public UpdateBase {
+        const int numBuffers;
+        inline RetireUpdate(SharedBufferBase* sbb, int numBuffers);
+        inline ssize_t operator()();
+    };
+
+    struct ReallocateCondition : public ConditionBase {
+        int buf;
+        inline ReallocateCondition(SharedBufferBase* sbb, int buf);
+        inline bool operator()();
+        static inline const char* name() { return "ReallocateCondition"; }
+    };
+};
+
+// ===========================================================================
+
+struct display_cblk_t
+{
+    uint16_t    w;
+    uint16_t    h;
+    uint8_t     format;
+    uint8_t     orientation;
+    uint8_t     reserved[2];
+    float       fps;
+    float       density;
+    float       xdpi;
+    float       ydpi;
+    uint32_t    pad[2];
+};
+
+struct surface_flinger_cblk_t   // 4KB max
+{
+    uint8_t         connected;
+    uint8_t         reserved[3];
+    uint32_t        pad[7];
+    display_cblk_t  displays[NUM_DISPLAY_MAX];
+};
+
+// ---------------------------------------------------------------------------
+
+COMPILE_TIME_ASSERT(sizeof(SharedClient) <= 4096)
+COMPILE_TIME_ASSERT(sizeof(SharedBufferStack) == 128)
+COMPILE_TIME_ASSERT(sizeof(surface_flinger_cblk_t) <= 4096)
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif /* ANDROID_UI_SHARED_BUFFER_STACK_H */
diff --git a/include/private/ui/SharedState.h b/include/private/ui/SharedState.h
deleted file mode 100644
index c9f6b5e..0000000
--- a/include/private/ui/SharedState.h
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_UI_SHARED_STATE_H
-#define ANDROID_UI_SHARED_STATE_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Debug.h>
-#include <utils/threads.h>
-
-namespace android {
-
-/*
- * These structures are shared between the composer process and its clients
- */
-
-// ---------------------------------------------------------------------------
-
-struct surface_info_t { // 4 longs, 16 bytes
-    enum {
-        eBufferDirty    = 0x01,
-        eNeedNewBuffer  = 0x02
-    };
-    uint8_t     reserved[11];
-    uint8_t     flags;
-    status_t    status;
-};
-
-// ---------------------------------------------------------------------------
-
-const uint32_t NUM_LAYERS_MAX = 31;
-
-enum { // layer_cblk_t swapState
-    eIndex              = 0x00000001,
-    eFlipRequested      = 0x00000002,
-    
-    eResizeBuffer0      = 0x00000004,
-    eResizeBuffer1      = 0x00000008,    
-    eResizeRequested    = eResizeBuffer0 | eResizeBuffer1,
-    
-    eBusy               = 0x00000010,
-    eLocked             = 0x00000020,
-    eNextFlipPending    = 0x00000040,    
-    eInvalidSurface     = 0x00000080
-};
-
-enum { // layer_cblk_t flags
-    eLayerNotPosted     = 0x00000001,
-    eNoCopyBack         = 0x00000002,
-    eReserved           = 0x0000007C,
-    eBufferIndexShift   = 7,
-    eBufferIndex        = 1<<eBufferIndexShift,
-};
-
-struct flat_region_t    // 40 bytes
-{
-    int32_t     count;
-    int16_t     l;
-    int16_t     t;
-    int16_t     r;
-    int16_t     b;
-    uint16_t    runs[14];
-};
-
-struct layer_cblk_t     // (128 bytes)
-{
-    volatile    int32_t             swapState;      //  4
-    volatile    int32_t             flags;          //  4
-    volatile    int32_t             identity;       //  4
-                int32_t             reserved;       //  4
-                surface_info_t      surface[2];     // 32
-                flat_region_t       region[2];      // 80
-
-    static inline int backBuffer(uint32_t state) {
-        return ((state & eIndex) ^ ((state & eFlipRequested)>>1));
-    }
-    static inline int frontBuffer(uint32_t state) {
-        return 1 - backBuffer(state);
-    }
-};
-
-// ---------------------------------------------------------------------------
-
-struct per_client_cblk_t   // 4KB max
-{
-    per_client_cblk_t() : lock(Mutex::SHARED) { }
-
-                Mutex           lock;
-                Condition       cv;
-                layer_cblk_t    layers[NUM_LAYERS_MAX] __attribute__((aligned(32)));
-
-    enum {
-        BLOCKING = 0x00000001,
-        INSPECT  = 0x00000002
-    };
-
-    // these functions are used by the clients
-    status_t validate(size_t i) const;
-    int32_t lock_layer(size_t i, uint32_t flags);
-    uint32_t unlock_layer_and_post(size_t i);
-    void unlock_layer(size_t i);
-};
-// ---------------------------------------------------------------------------
-
-const uint32_t NUM_DISPLAY_MAX = 4;
-
-struct display_cblk_t
-{
-    uint16_t    w;
-    uint16_t    h;
-    uint8_t     format;
-    uint8_t     orientation;
-    uint8_t     reserved[2];
-    float       fps;
-    float       density;
-    float       xdpi;
-    float       ydpi;
-    uint32_t    pad[2];
-};
-
-struct surface_flinger_cblk_t   // 4KB max
-{
-    uint8_t         connected;
-    uint8_t         reserved[3];
-    uint32_t        pad[7];
-    display_cblk_t  displays[NUM_DISPLAY_MAX];
-};
-
-// ---------------------------------------------------------------------------
-
-COMPILE_TIME_ASSERT(sizeof(layer_cblk_t) == 128)
-COMPILE_TIME_ASSERT(sizeof(per_client_cblk_t) <= 4096)
-COMPILE_TIME_ASSERT(sizeof(surface_flinger_cblk_t) <= 4096)
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_UI_SHARED_STATE_H
-
diff --git a/include/private/ui/SurfaceBuffer.h b/include/private/ui/SurfaceBuffer.h
index bf68406..73e517b 100644
--- a/include/private/ui/SurfaceBuffer.h
+++ b/include/private/ui/SurfaceBuffer.h
@@ -47,6 +47,9 @@
     status_t lock(uint32_t usage, const Rect& rect, void** vaddr);
     status_t unlock();
 
+    void setIndex(int index);
+    int getIndex() const;
+    
 protected:
             SurfaceBuffer();
             SurfaceBuffer(const Parcel& reply);
@@ -69,6 +72,7 @@
             android_native_buffer_t const* buffer);
     
     BufferMapper& mBufferMapper;
+    int mIndex;
 };
 
 }; // namespace android
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
index 799c349..4008bfd 100644
--- a/media/libmedia/ToneGenerator.cpp
+++ b/media/libmedia/ToneGenerator.cpp
@@ -791,7 +791,6 @@
 //        generators, instantiates output audio track.
 //
 //    Input:
-//        toneType:        Type of tone generated (values in enum tone_type)
 //        streamType:        Type of stream used for tone playback (enum AudioTrack::stream_type)
 //        volume:            volume applied to tone (0.0 to 1.0)
 //
@@ -869,13 +868,16 @@
 //    Description:    Starts tone playback.
 //
 //    Input:
-//        none
+//        toneType:        Type of tone generated (values in enum tone_type)
+//        durationMs:      The tone duration in milliseconds. If the tone is limited in time by definition,
+//              the actual duration will be the minimum of durationMs and the defined tone duration.
+//              Ommiting or setting durationMs to -1 does not limit tone duration.
 //
 //    Output:
 //        none
 //
 ////////////////////////////////////////////////////////////////////////////////
-bool ToneGenerator::startTone(int toneType) {
+bool ToneGenerator::startTone(int toneType, int durationMs) {
     bool lResult = false;
 
     if ((toneType < 0) || (toneType >= NUM_TONES))
@@ -896,6 +898,17 @@
     toneType = getToneForRegion(toneType);
     mpNewToneDesc = &sToneDescriptors[toneType];
 
+    if (durationMs == -1) {
+        mMaxSmp = TONEGEN_INF;
+    } else {
+        if (durationMs > (int)(TONEGEN_INF / mSamplingRate)) {
+            mMaxSmp = (durationMs / 1000) * mSamplingRate;
+        } else {
+            mMaxSmp = (durationMs * mSamplingRate) / 1000;
+        }
+        LOGV("startTone, duration limited to %d ms", durationMs);
+    }
+
     if (mState == TONE_INIT) {
         if (prepareWave()) {
             LOGV("Immediate start, time %d\n", (unsigned int)(systemTime()/1000000));
@@ -1102,11 +1115,17 @@
 
 
         // Exit if tone sequence is over
-        if (lpToneDesc->segments[lpToneGen->mCurSegment].duration == 0) {
+        if (lpToneDesc->segments[lpToneGen->mCurSegment].duration == 0 ||
+            lpToneGen->mTotalSmp > lpToneGen->mMaxSmp) {
             if (lpToneGen->mState == TONE_PLAYING) {
                 lpToneGen->mState = TONE_STOPPING;
             }
-            goto audioCallback_EndLoop;
+            if (lpToneDesc->segments[lpToneGen->mCurSegment].duration == 0) {
+                goto audioCallback_EndLoop;
+            }
+            // fade out before stopping if maximum duraiton reached
+            lWaveCmd = WaveGenerator::WAVEGEN_STOP;
+            lpToneGen->mNextSegSmp = TONEGEN_INF; // forced to skip state machine management below
         }
 
         if (lpToneGen->mTotalSmp > lpToneGen->mNextSegSmp) {
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index 84f858c..59ecde6 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -13,6 +13,8 @@
     StagefrightPlayer.cpp       \
     TestPlayerStub.cpp          \
     VorbisPlayer.cpp            \
+    VorbisMetadataRetriever.cpp \
+    MidiMetadataRetriever.cpp \
     MidiFile.cpp
 
 ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index eeb4e49..8998f10 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -611,7 +611,7 @@
     return PV_PLAYER;
 }
 
-static player_type getPlayerType(int fd, int64_t offset, int64_t length)
+player_type getPlayerType(int fd, int64_t offset, int64_t length)
 {
     char buf[20];
     lseek(fd, offset, SEEK_SET);
@@ -644,7 +644,7 @@
     return getDefaultPlayerType();
 }
 
-static player_type getPlayerType(const char* url)
+player_type getPlayerType(const char* url)
 {
     if (TestPlayerStub::canBeUsed(url)) {
         return TEST_PLAYER;
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index ba8d9a8..b34421d 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -34,12 +34,15 @@
 #include <media/MediaPlayerInterface.h>
 #include <media/PVMetadataRetriever.h>
 #include <private/media/VideoFrame.h>
-
+#include "VorbisMetadataRetriever.h"
+#include "MidiMetadataRetriever.h"
 #include "MetadataRetrieverClient.h"
 
-
 namespace android {
 
+extern player_type getPlayerType(const char* url);
+extern player_type getPlayerType(int fd, int64_t offset, int64_t length);
+
 MetadataRetrieverClient::MetadataRetrieverClient(pid_t pid)
 {
     LOGV("MetadataRetrieverClient constructor pid(%d)", pid);
@@ -90,6 +93,36 @@
     IPCThreadState::self()->flushCommands();
 }
 
+static sp<MediaMetadataRetrieverBase> createRetriever(player_type playerType)
+{
+    sp<MediaMetadataRetrieverBase> p;
+    switch (playerType) {
+#ifndef NO_OPENCORE
+        case PV_PLAYER:
+            LOGV("create pv metadata retriever");
+            p = new PVMetadataRetriever();
+            break;
+#endif
+        case VORBIS_PLAYER:
+            LOGV("create vorbis metadata retriever");
+            p = new VorbisMetadataRetriever();
+            break;
+        case SONIVOX_PLAYER:
+            LOGV("create midi metadata retriever");
+            p = new MidiMetadataRetriever();
+            break;
+        default:
+            // TODO:
+            // support for STAGEFRIGHT_PLAYER and TEST_PLAYER
+            LOGE("player type %d is not supported",  playerType);
+            break;
+    }
+    if (p == NULL) {
+        LOGE("failed to create a retriever object");
+    }
+    return p;
+}
+
 status_t MetadataRetrieverClient::setDataSource(const char *url)
 {
     LOGV("setDataSource(%s)", url);
@@ -97,11 +130,13 @@
     if (url == NULL) {
         return UNKNOWN_ERROR;
     }
-    if (mRetriever == NULL) {
-        LOGE("retriever is not initialized");
-        return NO_INIT;
-    }
-    return mRetriever->setDataSource(url);
+    player_type playerType = getPlayerType(url);
+    LOGV("player type = %d", playerType);
+    sp<MediaMetadataRetrieverBase> p = createRetriever(playerType);
+    if (p == NULL) return NO_INIT;
+    status_t ret = p->setDataSource(url);
+    if (ret == NO_ERROR) mRetriever = p;
+    return ret;
 }
 
 status_t MetadataRetrieverClient::setDataSource(int fd, int64_t offset, int64_t length)
@@ -118,7 +153,7 @@
     int ret = fstat(fd, &sb);
     if (ret != 0) {
         LOGE("fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
-        return UNKNOWN_ERROR;
+        return BAD_VALUE;
     }
     LOGV("st_dev  = %llu", sb.st_dev);
     LOGV("st_mode = %u", sb.st_mode);
@@ -129,13 +164,22 @@
     if (offset >= sb.st_size) {
         LOGE("offset (%lld) bigger than file size (%llu)", offset, sb.st_size);
         ::close(fd);
-        return UNKNOWN_ERROR;
+        return BAD_VALUE;
     }
     if (offset + length > sb.st_size) {
         length = sb.st_size - offset;
-        LOGE("calculated length = %lld", length);
+        LOGV("calculated length = %lld", length);
     }
-    status_t status = mRetriever->setDataSource(fd, offset, length);
+
+    player_type playerType = getPlayerType(fd, offset, length);
+    LOGV("player type = %d", playerType);
+    sp<MediaMetadataRetrieverBase> p = createRetriever(playerType);
+    if (p == NULL) {
+        ::close(fd);
+        return NO_INIT;
+    }
+    status_t status = p->setDataSource(fd, offset, length);
+    if (status == NO_ERROR) mRetriever = p;
     ::close(fd);
     return status;
 }
diff --git a/media/libmediaplayerservice/MidiMetadataRetriever.cpp b/media/libmediaplayerservice/MidiMetadataRetriever.cpp
new file mode 100644
index 0000000..3795b7b
--- /dev/null
+++ b/media/libmediaplayerservice/MidiMetadataRetriever.cpp
@@ -0,0 +1,91 @@
+/*
+**
+** Copyright 2009, 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 "MidiMetadataRetriever"
+#include <utils/Log.h>
+
+#include "MidiMetadataRetriever.h"
+#include <media/mediametadataretriever.h>
+
+namespace android {
+
+static status_t ERROR_NOT_OPEN = -1;
+static status_t ERROR_OPEN_FAILED = -2;
+static status_t ERROR_EAS_FAILURE = -3;
+static status_t ERROR_ALLOCATE_FAILED = -4;
+
+void MidiMetadataRetriever::clearMetadataValues()
+{
+    LOGV("clearMetadataValues");
+    mMetadataValues[0][0] = '\0';
+}
+
+status_t MidiMetadataRetriever::setDataSource(const char *url)
+{
+    LOGV("setDataSource: %s", url? url: "NULL pointer");
+    Mutex::Autolock lock(mLock);
+    clearMetadataValues();
+    if (mMidiPlayer == 0) {
+        mMidiPlayer = new MidiFile();
+    }
+    return mMidiPlayer->setDataSource(url);
+}
+
+status_t MidiMetadataRetriever::setDataSource(int fd, int64_t offset, int64_t length)
+{
+    LOGV("setDataSource: fd(%d), offset(%lld), and length(%lld)", fd, offset, length);
+    Mutex::Autolock lock(mLock);
+    clearMetadataValues();
+    if (mMidiPlayer == 0) {
+        mMidiPlayer = new MidiFile();
+    }
+    return mMidiPlayer->setDataSource(fd, offset, length);;
+}
+
+const char* MidiMetadataRetriever::extractMetadata(int keyCode)
+{
+    LOGV("extractMetdata: key(%d)", keyCode);
+    Mutex::Autolock lock(mLock);
+    if (mMidiPlayer == 0 || mMidiPlayer->initCheck() != NO_ERROR) {
+        LOGE("Midi player is not initialized yet");
+        return NULL;
+    }
+    switch (keyCode) {
+    case METADATA_KEY_DURATION:
+        {
+            if (mMetadataValues[0][0] == '\0') {
+                int duration = -1;
+                if (mMidiPlayer->getDuration(&duration) != NO_ERROR) {
+                    LOGE("failed to get duration");
+                    return NULL;
+                }
+                snprintf(mMetadataValues[0], MAX_METADATA_STRING_LENGTH, "%d", duration);
+            }
+
+            LOGV("duration: %s ms", mMetadataValues[0]);
+            return mMetadataValues[0];
+        }
+    default:
+        LOGE("Unsupported key code (%d)", keyCode);
+        return NULL;
+    }
+    return NULL;
+}
+
+};
+
diff --git a/media/libmediaplayerservice/MidiMetadataRetriever.h b/media/libmediaplayerservice/MidiMetadataRetriever.h
new file mode 100644
index 0000000..73ff347
--- /dev/null
+++ b/media/libmediaplayerservice/MidiMetadataRetriever.h
@@ -0,0 +1,49 @@
+/*
+**
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef ANDROID_MIDIMETADATARETRIEVER_H
+#define ANDROID_MIDIMETADATARETRIEVER_H
+
+#include <utils/threads.h>
+#include <utils/Errors.h>
+#include <media/MediaMetadataRetrieverInterface.h>
+
+#include "MidiFile.h"
+
+namespace android {
+
+class MidiMetadataRetriever : public MediaMetadataRetrieverInterface {
+public:
+                                   MidiMetadataRetriever() {}
+                                   ~MidiMetadataRetriever() {}
+
+    virtual status_t                setDataSource(const char *url);
+    virtual status_t                setDataSource(int fd, int64_t offset, int64_t length);
+    virtual const char*             extractMetadata(int keyCode);
+
+private:
+    static const uint32_t MAX_METADATA_STRING_LENGTH = 128;
+    void clearMetadataValues();
+
+    Mutex               mLock;
+    sp<MidiFile>        mMidiPlayer;
+    char                mMetadataValues[1][MAX_METADATA_STRING_LENGTH];
+};
+
+}; // namespace android
+
+#endif // ANDROID_MIDIMETADATARETRIEVER_H
diff --git a/media/libmediaplayerservice/VorbisMetadataRetriever.cpp b/media/libmediaplayerservice/VorbisMetadataRetriever.cpp
new file mode 100644
index 0000000..e981678
--- /dev/null
+++ b/media/libmediaplayerservice/VorbisMetadataRetriever.cpp
@@ -0,0 +1,86 @@
+/*
+**
+** Copyright 2009, 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 "VorbisMetadataRetriever"
+#include <utils/Log.h>
+
+#include "VorbisMetadataRetriever.h"
+#include <media/mediametadataretriever.h>
+#
+
+namespace android {
+
+void VorbisMetadataRetriever::clearMetadataValues()
+{
+    LOGV("cleearMetadataValues");
+    mMetadataValues[0][0] = '\0';
+}
+
+status_t VorbisMetadataRetriever::setDataSource(const char *url)
+{
+    LOGV("setDataSource: url(%s)", url? url: "NULL pointer");
+    Mutex::Autolock lock(mLock);
+    clearMetadataValues();
+    if (mVorbisPlayer == 0) {
+        mVorbisPlayer = new VorbisPlayer();
+    }
+    return mVorbisPlayer->setDataSource(url);
+}
+
+status_t VorbisMetadataRetriever::setDataSource(int fd, int64_t offset, int64_t length)
+{
+    LOGV("setDataSource: fd(%d), offset(%lld), and length(%lld)", fd, offset, length);
+    Mutex::Autolock lock(mLock);
+    clearMetadataValues();
+    if (mVorbisPlayer == 0) {
+        mVorbisPlayer = new VorbisPlayer();
+    }
+    return mVorbisPlayer->setDataSource(fd, offset, length);
+}
+
+const char* VorbisMetadataRetriever::extractMetadata(int keyCode)
+{
+    LOGV("extractMetadata: key(%d)", keyCode);
+    Mutex::Autolock lock(mLock);
+    if (mVorbisPlayer == 0 || mVorbisPlayer->initCheck() != NO_ERROR) {
+        LOGE("no vorbis player is initialized yet");
+        return NULL;
+    }
+    switch (keyCode) {
+    case METADATA_KEY_DURATION:
+        {
+            if (mMetadataValues[0][0] == '\0') {
+                int duration = -1;
+                if (mVorbisPlayer->getDuration(&duration) != NO_ERROR) {
+                    LOGE("failed to get duration");
+                    return NULL;
+                }
+                snprintf(mMetadataValues[0], MAX_METADATA_STRING_LENGTH, "%d", duration);
+            }
+            LOGV("duration: %s ms", mMetadataValues[0]);
+            return mMetadataValues[0];
+        }
+    default:
+        LOGE("Unsupported key code (%d)", keyCode);
+        return NULL;
+    }
+    return NULL;
+}
+
+};
+
diff --git a/media/libmediaplayerservice/VorbisMetadataRetriever.h b/media/libmediaplayerservice/VorbisMetadataRetriever.h
new file mode 100644
index 0000000..1c57fe3
--- /dev/null
+++ b/media/libmediaplayerservice/VorbisMetadataRetriever.h
@@ -0,0 +1,49 @@
+/*
+**
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef ANDROID_VORBISMETADATARETRIEVER_H
+#define ANDROID_VORBISMETADATARETRIEVER_H
+
+#include <utils/threads.h>
+#include <utils/Errors.h>
+#include <media/MediaMetadataRetrieverInterface.h>
+
+#include "VorbisPlayer.h"
+
+namespace android {
+
+class VorbisMetadataRetriever : public MediaMetadataRetrieverInterface {
+public:
+                                   VorbisMetadataRetriever() {}
+                                   ~VorbisMetadataRetriever() {}
+
+    virtual status_t                setDataSource(const char *url);
+    virtual status_t                setDataSource(int fd, int64_t offset, int64_t length);
+    virtual const char*             extractMetadata(int keyCode);
+
+private:
+    static const uint32_t MAX_METADATA_STRING_LENGTH = 128;
+    void clearMetadataValues();
+
+    Mutex               mLock;
+    sp<VorbisPlayer>    mVorbisPlayer;
+    char                mMetadataValues[1][MAX_METADATA_STRING_LENGTH];
+};
+
+}; // namespace android
+
+#endif // ANDROID_VORBISMETADATARETRIEVER_H