MediaPlayer2: remove MediaPlayer2Engine

Test: MediaPlayer2 plays
Bug: 63934228
Change-Id: I2459082bf6bbe2384ed94901b1f8f28559345888
diff --git a/media/libmediaplayer2/mediaplayer2.cpp b/media/libmediaplayer2/mediaplayer2.cpp
index 75d06b8..b401ee8 100644
--- a/media/libmediaplayer2/mediaplayer2.cpp
+++ b/media/libmediaplayer2/mediaplayer2.cpp
@@ -18,44 +18,391 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "MediaPlayer2Native"
 
-#include <fcntl.h>
-#include <inttypes.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <utils/Log.h>
-
 #include <binder/IServiceManager.h>
 #include <binder/IPCThreadState.h>
 
-#include <media/AudioResamplerPublic.h>
 #include <media/AudioSystem.h>
-#include <media/AVSyncSettings.h>
-#include <media/DataSource.h>
 #include <media/DataSourceDesc.h>
 #include <media/MediaAnalyticsItem.h>
+#include <media/MemoryLeakTrackUtil.h>
+#include <media/Metadata.h>
 #include <media/NdkWrapper.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALooperRoster.h>
+#include <mediaplayer2/MediaPlayer2AudioOutput.h>
 #include <mediaplayer2/mediaplayer2.h>
 
-#include <binder/MemoryBase.h>
-
-#include <utils/KeyedVector.h>
+#include <utils/Log.h>
+#include <utils/SortedVector.h>
 #include <utils/String8.h>
 
 #include <system/audio.h>
 #include <system/window.h>
 
-#include "MediaPlayer2Manager.h"
+#include <nuplayer2/NuPlayer2Driver.h>
+
+#include <dirent.h>
+#include <sys/stat.h>
 
 namespace android {
 
-MediaPlayer2::MediaPlayer2()
-{
+extern ALooperRoster gLooperRoster;
+
+namespace {
+
+const int kDumpLockRetries = 50;
+const int kDumpLockSleepUs = 20000;
+
+// Max number of entries in the filter.
+const int kMaxFilterSize = 64;  // I pulled that out of thin air.
+
+// FIXME: Move all the metadata related function in the Metadata.cpp
+
+// Unmarshall a filter from a Parcel.
+// Filter format in a parcel:
+//
+//  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |                       number of entries (n)                   |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |                       metadata type 1                         |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |                       metadata type 2                         |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  ....
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |                       metadata type n                         |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+// @param p Parcel that should start with a filter.
+// @param[out] filter On exit contains the list of metadata type to be
+//                    filtered.
+// @param[out] status On exit contains the status code to be returned.
+// @return true if the parcel starts with a valid filter.
+bool unmarshallFilter(const Parcel& p,
+                      media::Metadata::Filter *filter,
+                      status_t *status) {
+    int32_t val;
+    if (p.readInt32(&val) != OK) {
+        ALOGE("Failed to read filter's length");
+        *status = NOT_ENOUGH_DATA;
+        return false;
+    }
+
+    if (val > kMaxFilterSize || val < 0) {
+        ALOGE("Invalid filter len %d", val);
+        *status = BAD_VALUE;
+        return false;
+    }
+
+    const size_t num = val;
+
+    filter->clear();
+    filter->setCapacity(num);
+
+    size_t size = num * sizeof(media::Metadata::Type);
+
+
+    if (p.dataAvail() < size) {
+        ALOGE("Filter too short expected %zu but got %zu", size, p.dataAvail());
+        *status = NOT_ENOUGH_DATA;
+        return false;
+    }
+
+    const media::Metadata::Type *data =
+        static_cast<const media::Metadata::Type*>(p.readInplace(size));
+
+    if (NULL == data) {
+        ALOGE("Filter had no data");
+        *status = BAD_VALUE;
+        return false;
+    }
+
+    // TODO: The stl impl of vector would be more efficient here
+    // because it degenerates into a memcpy on pod types. Try to
+    // replace later or use stl::set.
+    for (size_t i = 0; i < num; ++i) {
+        filter->add(*data);
+        ++data;
+    }
+    *status = OK;
+    return true;
+}
+
+// @param filter Of metadata type.
+// @param val To be searched.
+// @return true if a match was found.
+bool findMetadata(const media::Metadata::Filter& filter, const int32_t val) {
+    // Deal with empty and ANY right away
+    if (filter.isEmpty()) {
+        return false;
+    }
+    if (filter[0] == media::Metadata::kAny) {
+        return true;
+    }
+
+    return filter.indexOf(val) >= 0;
+}
+
+// marshalling tag indicating flattened utf16 tags
+// keep in sync with frameworks/base/media/java/android/media/AudioAttributes.java
+const int32_t kAudioAttributesMarshallTagFlattenTags = 1;
+
+// Audio attributes format in a parcel:
+//
+//  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |                       usage                                   |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |                       content_type                            |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |                       source                                  |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |                       flags                                   |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |                       kAudioAttributesMarshallTagFlattenTags  | // ignore tags if not found
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |                       flattened tags in UTF16                 |
+// |                         ...                                   |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+// @param p Parcel that contains audio attributes.
+// @param[out] attributes On exit points to an initialized audio_attributes_t structure
+// @param[out] status On exit contains the status code to be returned.
+void unmarshallAudioAttributes(const Parcel& parcel, audio_attributes_t *attributes) {
+    attributes->usage = (audio_usage_t) parcel.readInt32();
+    attributes->content_type = (audio_content_type_t) parcel.readInt32();
+    attributes->source = (audio_source_t) parcel.readInt32();
+    attributes->flags = (audio_flags_mask_t) parcel.readInt32();
+    const bool hasFlattenedTag = (parcel.readInt32() == kAudioAttributesMarshallTagFlattenTags);
+    if (hasFlattenedTag) {
+        // the tags are UTF16, convert to UTF8
+        String16 tags = parcel.readString16();
+        ssize_t realTagSize = utf16_to_utf8_length(tags.string(), tags.size());
+        if (realTagSize <= 0) {
+            strcpy(attributes->tags, "");
+        } else {
+            // copy the flattened string into the attributes as the destination for the conversion:
+            // copying array size -1, array for tags was calloc'd, no need to NULL-terminate it
+            size_t tagSize = realTagSize > AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1 ?
+                    AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1 : realTagSize;
+            utf16_to_utf8(tags.string(), tagSize, attributes->tags,
+                    sizeof(attributes->tags) / sizeof(attributes->tags[0]));
+        }
+    } else {
+        ALOGE("unmarshallAudioAttributes() received unflattened tags, ignoring tag values");
+        strcpy(attributes->tags, "");
+    }
+}
+
+class AudioDeviceUpdatedNotifier: public AudioSystem::AudioDeviceCallback {
+public:
+    AudioDeviceUpdatedNotifier(const sp<MediaPlayer2Interface>& listener)
+        : mListener(listener) { }
+
+    ~AudioDeviceUpdatedNotifier() { }
+
+    virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo,
+                                     audio_port_handle_t deviceId) override {
+        sp<MediaPlayer2Interface> listener = mListener.promote();
+        if (listener != NULL) {
+            listener->sendEvent(0, MEDIA2_AUDIO_ROUTING_CHANGED, audioIo, deviceId);
+        } else {
+            ALOGW("listener for process %d death is gone", MEDIA2_AUDIO_ROUTING_CHANGED);
+        }
+    }
+
+private:
+    wp<MediaPlayer2Interface> mListener;
+};
+
+class proxyListener : public MediaPlayer2InterfaceListener {
+public:
+    proxyListener(const wp<MediaPlayer2> &player)
+        : mPlayer(player) { }
+
+    ~proxyListener() { };
+
+    virtual void notify(int64_t srcId, int msg, int ext1, int ext2, const Parcel *obj) override {
+        sp<MediaPlayer2> player = mPlayer.promote();
+        if (player != NULL) {
+            player->notify(srcId, msg, ext1, ext2, obj);
+        }
+    }
+
+private:
+    wp<MediaPlayer2> mPlayer;
+};
+
+Mutex sRecordLock;
+SortedVector<wp<MediaPlayer2> > *sPlayers;
+
+void ensureInit_l() {
+    if (sPlayers == NULL) {
+        sPlayers = new SortedVector<wp<MediaPlayer2> >();
+    }
+}
+
+void addPlayer(const wp<MediaPlayer2>& player) {
+    Mutex::Autolock lock(sRecordLock);
+    ensureInit_l();
+    sPlayers->add(player);
+}
+
+void removePlayer(const wp<MediaPlayer2>& player) {
+    Mutex::Autolock lock(sRecordLock);
+    ensureInit_l();
+    sPlayers->remove(player);
+}
+
+/**
+ * The only arguments this understands right now are -c, -von and -voff,
+ * which are parsed by ALooperRoster::dump()
+ */
+status_t dumpPlayers(int fd, const Vector<String16>& args) {
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    SortedVector< sp<MediaPlayer2> > players; //to serialise the mutex unlock & client destruction.
+
+    if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
+        snprintf(buffer, SIZE, "Permission Denial: can't dump MediaPlayer2\n");
+        result.append(buffer);
+    } else {
+        {
+            Mutex::Autolock lock(sRecordLock);
+            ensureInit_l();
+            for (int i = 0, n = sPlayers->size(); i < n; ++i) {
+                sp<MediaPlayer2> p = (*sPlayers)[i].promote();
+                if (p != 0) {
+                    p->dump(fd, args);
+                }
+                players.add(p);
+            }
+        }
+
+        result.append(" Files opened and/or mapped:\n");
+        snprintf(buffer, SIZE, "/proc/%d/maps", getpid());
+        FILE *f = fopen(buffer, "r");
+        if (f) {
+            while (!feof(f)) {
+                fgets(buffer, SIZE, f);
+                if (strstr(buffer, " /storage/") ||
+                    strstr(buffer, " /system/sounds/") ||
+                    strstr(buffer, " /data/") ||
+                    strstr(buffer, " /system/media/")) {
+                    result.append("  ");
+                    result.append(buffer);
+                }
+            }
+            fclose(f);
+        } else {
+            result.append("couldn't open ");
+            result.append(buffer);
+            result.append("\n");
+        }
+
+        snprintf(buffer, SIZE, "/proc/%d/fd", getpid());
+        DIR *d = opendir(buffer);
+        if (d) {
+            struct dirent *ent;
+            while((ent = readdir(d)) != NULL) {
+                if (strcmp(ent->d_name,".") && strcmp(ent->d_name,"..")) {
+                    snprintf(buffer, SIZE, "/proc/%d/fd/%s", getpid(), ent->d_name);
+                    struct stat s;
+                    if (lstat(buffer, &s) == 0) {
+                        if ((s.st_mode & S_IFMT) == S_IFLNK) {
+                            char linkto[256];
+                            int len = readlink(buffer, linkto, sizeof(linkto));
+                            if(len > 0) {
+                                if(len > 255) {
+                                    linkto[252] = '.';
+                                    linkto[253] = '.';
+                                    linkto[254] = '.';
+                                    linkto[255] = 0;
+                                } else {
+                                    linkto[len] = 0;
+                                }
+                                if (strstr(linkto, "/storage/") == linkto ||
+                                    strstr(linkto, "/system/sounds/") == linkto ||
+                                    strstr(linkto, "/data/") == linkto ||
+                                    strstr(linkto, "/system/media/") == linkto) {
+                                    result.append("  ");
+                                    result.append(buffer);
+                                    result.append(" -> ");
+                                    result.append(linkto);
+                                    result.append("\n");
+                                }
+                            }
+                        } else {
+                            result.append("  unexpected type for ");
+                            result.append(buffer);
+                            result.append("\n");
+                        }
+                    }
+                }
+            }
+            closedir(d);
+        } else {
+            result.append("couldn't open ");
+            result.append(buffer);
+            result.append("\n");
+        }
+
+        gLooperRoster.dump(fd, args);
+
+        bool dumpMem = false;
+        bool unreachableMemory = false;
+        for (size_t i = 0; i < args.size(); i++) {
+            if (args[i] == String16("-m")) {
+                dumpMem = true;
+            } else if (args[i] == String16("--unreachable")) {
+                unreachableMemory = true;
+            }
+        }
+        if (dumpMem) {
+            result.append("\nDumping memory:\n");
+            std::string s = dumpMemoryAddresses(100 /* limit */);
+            result.append(s.c_str(), s.size());
+        }
+        if (unreachableMemory) {
+            result.append("\nDumping unreachable memory:\n");
+            // TODO - should limit be an argument parameter?
+            // TODO: enable GetUnreachableMemoryString if it's part of stable API
+            //std::string s = GetUnreachableMemoryString(true /* contents */, 10000 /* limit */);
+            //result.append(s.c_str(), s.size());
+        }
+    }
+    write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+}  // anonymous namespace
+
+//static
+sp<MediaPlayer2> MediaPlayer2::Create() {
+    sp<MediaPlayer2> player = new MediaPlayer2();
+
+    if (!player->init()) {
+        return NULL;
+    }
+
+    ALOGV("Create new player(%p)", player.get());
+
+    addPlayer(player);
+    return player;
+}
+
+// static
+status_t MediaPlayer2::DumpAll(int fd, const Vector<String16>& args) {
+    return dumpPlayers(fd, args);
+}
+
+MediaPlayer2::MediaPlayer2() {
     ALOGV("constructor");
     mSrcId = 0;
+    mLockThreadId = 0;
     mListener = NULL;
-    mCookie = NULL;
     mStreamType = AUDIO_STREAM_MUSIC;
     mAudioAttributesParcel = NULL;
     mCurrentPosition = -1;
@@ -66,14 +413,18 @@
     mLoop = false;
     mLeftVolume = mRightVolume = 1.0;
     mVideoWidth = mVideoHeight = 0;
-    mLockThreadId = 0;
     mAudioSessionId = (audio_session_t) AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
     AudioSystem::acquireAudioSessionId(mAudioSessionId, -1);
     mSendLevel = 0;
+
+    // TODO: get pid and uid from JAVA
+    mPid = IPCThreadState::self()->getCallingPid();
+    mUid = IPCThreadState::self()->getCallingUid();
+
+    mAudioAttributes = NULL;
 }
 
-MediaPlayer2::~MediaPlayer2()
-{
+MediaPlayer2::~MediaPlayer2() {
     ALOGV("destructor");
     if (mAudioAttributesParcel != NULL) {
         delete mAudioAttributesParcel;
@@ -81,13 +432,21 @@
     }
     AudioSystem::releaseAudioSessionId(mAudioSessionId, -1);
     disconnect();
-    IPCThreadState::self()->flushCommands();
+    removePlayer(this);
+    if (mAudioAttributes != NULL) {
+        free(mAudioAttributes);
+    }
 }
 
-void MediaPlayer2::disconnect()
-{
+bool MediaPlayer2::init() {
+    // TODO: after merge with NuPlayer2Driver, MediaPlayer2 will have its own
+    // looper for notification.
+    return true;
+}
+
+void MediaPlayer2::disconnect() {
     ALOGV("disconnect");
-    sp<MediaPlayer2Engine> p;
+    sp<MediaPlayer2Interface> p;
     {
         Mutex::Autolock _l(mLock);
         p = mPlayer;
@@ -95,13 +454,17 @@
     }
 
     if (p != 0) {
-        p->disconnect();
+        p->setListener(NULL);
+        p->reset();
+    }
+
+    {
+        Mutex::Autolock _l(mLock);
+        disconnectNativeWindow_l();
     }
 }
 
-// always call with lock held
-void MediaPlayer2::clear_l()
-{
+void MediaPlayer2::clear_l() {
     mCurrentPosition = -1;
     mCurrentSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
     mSeekPosition = -1;
@@ -109,8 +472,7 @@
     mVideoWidth = mVideoHeight = 0;
 }
 
-status_t MediaPlayer2::setListener(const sp<MediaPlayer2Listener>& listener)
-{
+status_t MediaPlayer2::setListener(const sp<MediaPlayer2Listener>& listener) {
     ALOGV("setListener");
     Mutex::Autolock _l(mLock);
     mListener = listener;
@@ -127,51 +489,54 @@
     return OK;
 }
 
-status_t MediaPlayer2::attachNewPlayer(const sp<MediaPlayer2Engine>& player, long srcId)
-{
-    status_t err = UNKNOWN_ERROR;
-    sp<MediaPlayer2Engine> p;
-    { // scope for the lock
-        Mutex::Autolock _l(mLock);
-
-        if ( !( (mCurrentState & MEDIA_PLAYER2_IDLE) ||
-                (mCurrentState == MEDIA_PLAYER2_STATE_ERROR ) ) ) {
-            ALOGE("attachNewPlayer called in state %d", mCurrentState);
-            return INVALID_OPERATION;
-        }
-
-        clear_l();
-        p = mPlayer;
-        mPlayer = player;
-        mSrcId = srcId;
-        if (player != 0) {
-            mCurrentState = MEDIA_PLAYER2_INITIALIZED;
-            err = NO_ERROR;
-        } else {
-            ALOGE("Unable to create media player");
-        }
-    }
-
-    if (p != 0) {
-        p->disconnect();
-    }
-
-    return err;
-}
-
-status_t MediaPlayer2::setDataSource(const sp<DataSourceDesc> &dsd)
-{
+status_t MediaPlayer2::setDataSource(const sp<DataSourceDesc> &dsd) {
     if (dsd == NULL) {
         return BAD_VALUE;
     }
-    ALOGV("setDataSource type(%d)", dsd->mType);
-    status_t err = UNKNOWN_ERROR;
-    sp<MediaPlayer2Engine> player(MediaPlayer2Manager::get().create(this, mAudioSessionId));
-    if (NO_ERROR != player->setDataSource(dsd)) {
-        player.clear();
+    ALOGV("setDataSource type(%d), srcId(%lld)", dsd->mType, (long long)dsd->mId);
+
+    sp<MediaPlayer2Interface> oldPlayer;
+
+    Mutex::Autolock _l(mLock);
+    {
+        if (!((mCurrentState & MEDIA_PLAYER2_IDLE)
+              || mCurrentState == MEDIA_PLAYER2_STATE_ERROR)) {
+            ALOGE("setDataSource called in wrong state %d", mCurrentState);
+            return INVALID_OPERATION;
+        }
+
+        sp<MediaPlayer2Interface> player = new NuPlayer2Driver(mPid, mUid);
+        status_t err = player->initCheck();
+        if (err != NO_ERROR) {
+            ALOGE("Failed to create player object, initCheck failed(%d)", err);
+            return err;
+        }
+
+        clear_l();
+
+        player->setListener(new proxyListener(this));
+        mAudioOutput = new MediaPlayer2AudioOutput(mAudioSessionId, mUid,
+                mPid, mAudioAttributes, new AudioDeviceUpdatedNotifier(player));
+        player->setAudioSink(mAudioOutput);
+
+        err = player->setDataSource(dsd);
+        if (err != OK) {
+            ALOGE("setDataSource error: %d", err);
+            return err;
+        }
+
+        sp<MediaPlayer2Interface> oldPlayer = mPlayer;
+        mPlayer = player;
+        mSrcId = dsd->mId;
+        mCurrentState = MEDIA_PLAYER2_INITIALIZED;
     }
-    err = attachNewPlayer(player, dsd->mId);
-    return err;
+
+    if (oldPlayer != NULL) {
+        oldPlayer->setListener(NULL);
+        oldPlayer->reset();
+    }
+
+    return OK;
 }
 
 status_t MediaPlayer2::prepareNextDataSource(const sp<DataSourceDesc> &dsd) {
@@ -181,81 +546,179 @@
     ALOGV("prepareNextDataSource type(%d), srcId(%lld)", dsd->mType, (long long)dsd->mId);
 
     Mutex::Autolock _l(mLock);
-    if (mPlayer != NULL) {
-        return mPlayer->prepareNextDataSource(dsd);
+    if (mPlayer == NULL) {
+        ALOGE("prepareNextDataSource failed: state %X, mPlayer(%p)", mCurrentState, mPlayer.get());
+        return INVALID_OPERATION;
     }
-    ALOGE("prepareNextDataSource failed: state %X, mPlayer(%p)", mCurrentState, mPlayer.get());
-    return INVALID_OPERATION;
+    return mPlayer->prepareNextDataSource(dsd);
 }
 
 status_t MediaPlayer2::playNextDataSource(int64_t srcId) {
     ALOGV("playNextDataSource srcId(%lld)", (long long)srcId);
 
     Mutex::Autolock _l(mLock);
-    if (mPlayer != NULL) {
-        mSrcId = srcId;
-        return mPlayer->playNextDataSource(srcId);
+    if (mPlayer == NULL) {
+        ALOGE("playNextDataSource failed: state %X, mPlayer(%p)", mCurrentState, mPlayer.get());
+        return INVALID_OPERATION;
     }
-    ALOGE("playNextDataSource failed: state %X, mPlayer(%p)", mCurrentState, mPlayer.get());
-    return INVALID_OPERATION;
+    mSrcId = srcId;
+    return mPlayer->playNextDataSource(srcId);
 }
 
-status_t MediaPlayer2::invoke(const Parcel& request, Parcel *reply)
-{
+status_t MediaPlayer2::invoke(const Parcel& request, Parcel *reply) {
     Mutex::Autolock _l(mLock);
     const bool hasBeenInitialized =
             (mCurrentState != MEDIA_PLAYER2_STATE_ERROR) &&
             ((mCurrentState & MEDIA_PLAYER2_IDLE) != MEDIA_PLAYER2_IDLE);
-    if ((mPlayer != NULL) && hasBeenInitialized) {
-        ALOGV("invoke %zu", request.dataSize());
-        return  mPlayer->invoke(request, reply);
+    if ((mPlayer == NULL) || !hasBeenInitialized) {
+        ALOGE("invoke failed: wrong state %X, mPlayer(%p)", mCurrentState, mPlayer.get());
+        return INVALID_OPERATION;
     }
-    ALOGE("invoke failed: wrong state %X, mPlayer(%p)", mCurrentState, mPlayer.get());
-    return INVALID_OPERATION;
+    ALOGV("invoke %zu", request.dataSize());
+    return mPlayer->invoke(request, reply);
 }
 
-status_t MediaPlayer2::setMetadataFilter(const Parcel& filter)
-{
+// This call doesn't need to access the native player.
+status_t MediaPlayer2::setMetadataFilter(const Parcel& filter) {
     ALOGD("setMetadataFilter");
-    Mutex::Autolock lock(mLock);
-    if (mPlayer == NULL) {
-        return NO_INIT;
+
+    status_t status;
+    media::Metadata::Filter allow, drop;
+
+    if (unmarshallFilter(filter, &allow, &status) &&
+        unmarshallFilter(filter, &drop, &status)) {
+        Mutex::Autolock lock(mLock);
+
+        mMetadataAllow = allow;
+        mMetadataDrop = drop;
     }
-    return mPlayer->setMetadataFilter(filter);
+    return status;
 }
 
-status_t MediaPlayer2::getMetadata(bool update_only, bool apply_filter, Parcel *metadata)
-{
+status_t MediaPlayer2::getMetadata(bool update_only, bool /* apply_filter */, Parcel *reply) {
     ALOGD("getMetadata");
+    sp<MediaPlayer2Interface> player;
+    media::Metadata::Filter ids;
     Mutex::Autolock lock(mLock);
-    if (mPlayer == NULL) {
+    {
+        if (mPlayer == NULL) {
+            return NO_INIT;
+        }
+
+        player = mPlayer;
+        // Placeholder for the return code, updated by the caller.
+        reply->writeInt32(-1);
+
+        // We don't block notifications while we fetch the data. We clear
+        // mMetadataUpdated first so we don't lose notifications happening
+        // during the rest of this call.
+        if (update_only) {
+            ids = mMetadataUpdated;
+        }
+        mMetadataUpdated.clear();
+    }
+
+    media::Metadata metadata(reply);
+
+    metadata.appendHeader();
+    status_t status = player->getMetadata(ids, reply);
+
+    if (status != OK) {
+        metadata.resetParcel();
+        ALOGE("getMetadata failed %d", status);
+        return status;
+    }
+
+    // FIXME: ement filtering on the result. Not critical since
+    // filtering takes place on the update notifications already. This
+    // would be when all the metadata are fetch and a filter is set.
+
+    // Everything is fine, update the metadata length.
+    metadata.updateLength();
+    return OK;
+}
+
+void MediaPlayer2::disconnectNativeWindow_l() {
+    if (mConnectedWindow != NULL && mConnectedWindow->getANativeWindow() != NULL) {
+        status_t err = native_window_api_disconnect(
+                mConnectedWindow->getANativeWindow(), NATIVE_WINDOW_API_MEDIA);
+
+        if (err != OK) {
+            ALOGW("nativeWindowDisconnect returned an error: %s (%d)",
+                  strerror(-err), err);
+        }
+    }
+    mConnectedWindow.clear();
+}
+
+status_t MediaPlayer2::setVideoSurfaceTexture(const sp<ANativeWindowWrapper>& nww) {
+    ANativeWindow *anw = (nww == NULL ? NULL : nww->getANativeWindow());
+    ALOGV("setVideoSurfaceTexture(%p)", anw);
+    Mutex::Autolock _l(mLock);
+    if (mPlayer == 0) {
         return NO_INIT;
     }
-    return mPlayer->getMetadata(update_only, apply_filter, metadata);
+
+    if (anw != NULL) {
+        if (mConnectedWindow != NULL
+            && mConnectedWindow->getANativeWindow() == anw) {
+            return OK;
+        }
+        status_t err = native_window_api_connect(anw, NATIVE_WINDOW_API_MEDIA);
+
+        if (err != OK) {
+            ALOGE("setVideoSurfaceTexture failed: %d", err);
+            // Note that we must do the reset before disconnecting from the ANW.
+            // Otherwise queue/dequeue calls could be made on the disconnected
+            // ANW, which may result in errors.
+            mPlayer->reset();
+            disconnectNativeWindow_l();
+            return err;
+        }
+    }
+
+    // Note that we must set the player's new GraphicBufferProducer before
+    // disconnecting the old one.  Otherwise queue/dequeue calls could be made
+    // on the disconnected ANW, which may result in errors.
+    status_t err = mPlayer->setVideoSurfaceTexture(nww);
+
+    disconnectNativeWindow_l();
+
+    if (err == OK) {
+        mConnectedWindow = nww;
+        mLock.unlock();
+    } else if (anw != NULL) {
+        mLock.unlock();
+        status_t err = native_window_api_disconnect(anw, NATIVE_WINDOW_API_MEDIA);
+
+        if (err != OK) {
+            ALOGW("nativeWindowDisconnect returned an error: %s (%d)",
+                  strerror(-err), err);
+        }
+    }
+
+    return err;
 }
 
-status_t MediaPlayer2::setVideoSurfaceTexture(const sp<ANativeWindowWrapper>& nww)
-{
-    ALOGV("setVideoSurfaceTexture");
-    Mutex::Autolock _l(mLock);
-    if (mPlayer == 0) return NO_INIT;
-    return mPlayer->setVideoSurfaceTexture(nww);
-}
-
-status_t MediaPlayer2::getBufferingSettings(BufferingSettings* buffering /* nonnull */)
-{
+status_t MediaPlayer2::getBufferingSettings(BufferingSettings* buffering /* nonnull */) {
     ALOGV("getBufferingSettings");
 
     Mutex::Autolock _l(mLock);
     if (mPlayer == 0) {
         return NO_INIT;
     }
-    return mPlayer->getBufferingSettings(buffering);
+
+    status_t ret = mPlayer->getBufferingSettings(buffering);
+    if (ret == NO_ERROR) {
+        ALOGV("getBufferingSettings{%s}", buffering->toString().string());
+    } else {
+        ALOGE("getBufferingSettings returned %d", ret);
+    }
+    return ret;
 }
 
-status_t MediaPlayer2::setBufferingSettings(const BufferingSettings& buffering)
-{
-    ALOGV("setBufferingSettings");
+status_t MediaPlayer2::setBufferingSettings(const BufferingSettings& buffering) {
+    ALOGV("setBufferingSettings{%s}", buffering.toString().string());
 
     Mutex::Autolock _l(mLock);
     if (mPlayer == 0) {
@@ -264,14 +727,37 @@
     return mPlayer->setBufferingSettings(buffering);
 }
 
-// must call with lock held
-status_t MediaPlayer2::prepareAsync_l()
-{
-    if ( (mPlayer != 0) && ( mCurrentState & (MEDIA_PLAYER2_INITIALIZED | MEDIA_PLAYER2_STOPPED) ) ) {
+status_t MediaPlayer2::setAudioAttributes_l(const Parcel &parcel) {
+    if (mAudioAttributes != NULL) {
+        free(mAudioAttributes);
+    }
+    mAudioAttributes = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
+    if (mAudioAttributes == NULL) {
+        return NO_MEMORY;
+    }
+    unmarshallAudioAttributes(parcel, mAudioAttributes);
+
+    ALOGV("setAudioAttributes_l() usage=%d content=%d flags=0x%x tags=%s",
+            mAudioAttributes->usage, mAudioAttributes->content_type, mAudioAttributes->flags,
+            mAudioAttributes->tags);
+
+    if (mAudioOutput != 0) {
+        mAudioOutput->setAudioAttributes(mAudioAttributes);
+    }
+    return NO_ERROR;
+}
+
+status_t MediaPlayer2::prepareAsync() {
+    ALOGV("prepareAsync");
+    Mutex::Autolock _l(mLock);
+    if ((mPlayer != 0) && (mCurrentState & (MEDIA_PLAYER2_INITIALIZED | MEDIA_PLAYER2_STOPPED))) {
         if (mAudioAttributesParcel != NULL) {
-            mPlayer->setParameter(MEDIA2_KEY_PARAMETER_AUDIO_ATTRIBUTES, *mAudioAttributesParcel);
-        } else {
-            mPlayer->setAudioStreamType(mStreamType);
+            status_t err = setAudioAttributes_l(*mAudioAttributesParcel);
+            if (err != OK) {
+                return err;
+            }
+        } else if (mAudioOutput != 0) {
+            mAudioOutput->setAudioStreamType(mStreamType);
         }
         mCurrentState = MEDIA_PLAYER2_PREPARING;
         return mPlayer->prepareAsync();
@@ -280,15 +766,7 @@
     return INVALID_OPERATION;
 }
 
-status_t MediaPlayer2::prepareAsync()
-{
-    ALOGV("prepareAsync");
-    Mutex::Autolock _l(mLock);
-    return prepareAsync_l();
-}
-
-status_t MediaPlayer2::start()
-{
+status_t MediaPlayer2::start() {
     ALOGV("start");
 
     status_t ret = NO_ERROR;
@@ -301,8 +779,14 @@
     } else if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER2_PREPARED |
                     MEDIA_PLAYER2_PLAYBACK_COMPLETE | MEDIA_PLAYER2_PAUSED ) ) ) {
         mPlayer->setLooping(mLoop);
-        mPlayer->setVolume(mLeftVolume, mRightVolume);
-        mPlayer->setAuxEffectSendLevel(mSendLevel);
+
+        if (mAudioOutput != 0) {
+            mAudioOutput->setVolume(mLeftVolume, mRightVolume);
+        }
+
+        if (mAudioOutput != 0) {
+            mAudioOutput->setAuxEffectSendLevel(mSendLevel);
+        }
         mCurrentState = MEDIA_PLAYER2_STARTED;
         ret = mPlayer->start();
         if (ret != NO_ERROR) {
@@ -322,8 +806,7 @@
     return ret;
 }
 
-status_t MediaPlayer2::stop()
-{
+status_t MediaPlayer2::stop() {
     ALOGV("stop");
     Mutex::Autolock _l(mLock);
     if (mCurrentState & MEDIA_PLAYER2_STOPPED) return NO_ERROR;
@@ -341,8 +824,7 @@
     return INVALID_OPERATION;
 }
 
-status_t MediaPlayer2::pause()
-{
+status_t MediaPlayer2::pause() {
     ALOGV("pause");
     Mutex::Autolock _l(mLock);
     if (mCurrentState & (MEDIA_PLAYER2_PAUSED|MEDIA_PLAYER2_PLAYBACK_COMPLETE))
@@ -360,12 +842,10 @@
     return INVALID_OPERATION;
 }
 
-bool MediaPlayer2::isPlaying()
-{
+bool MediaPlayer2::isPlaying() {
     Mutex::Autolock _l(mLock);
     if (mPlayer != 0) {
-        bool temp = false;
-        mPlayer->isPlaying(&temp);
+        bool temp = mPlayer->isPlaying();
         ALOGV("isPlaying: %d", temp);
         if ((mCurrentState & MEDIA_PLAYER2_STARTED) && ! temp) {
             ALOGE("internal/external state mismatch corrected");
@@ -380,13 +860,12 @@
     return false;
 }
 
-status_t MediaPlayer2::setPlaybackSettings(const AudioPlaybackRate& rate)
-{
+status_t MediaPlayer2::setPlaybackSettings(const AudioPlaybackRate& rate) {
     ALOGV("setPlaybackSettings: %f %f %d %d",
             rate.mSpeed, rate.mPitch, rate.mFallbackMode, rate.mStretchMode);
     // Negative speed and pitch does not make sense. Further validation will
     // be done by the respective mediaplayers.
-    if (rate.mSpeed < 0.f || rate.mPitch < 0.f) {
+    if (rate.mSpeed <= 0.f || rate.mPitch < 0.f) {
         return BAD_VALUE;
     }
     Mutex::Autolock _l(mLock);
@@ -394,36 +873,27 @@
         return INVALID_OPERATION;
     }
 
-    if (rate.mSpeed != 0.f && !(mCurrentState & MEDIA_PLAYER2_STARTED)
-            && (mCurrentState & (MEDIA_PLAYER2_PREPARED | MEDIA_PLAYER2_PAUSED
-                    | MEDIA_PLAYER2_PLAYBACK_COMPLETE))) {
-        mPlayer->setLooping(mLoop);
-        mPlayer->setVolume(mLeftVolume, mRightVolume);
-        mPlayer->setAuxEffectSendLevel(mSendLevel);
-    }
-
     status_t err = mPlayer->setPlaybackSettings(rate);
-    if (err == OK) {
-        if (rate.mSpeed == 0.f && mCurrentState == MEDIA_PLAYER2_STARTED) {
-            mCurrentState = MEDIA_PLAYER2_PAUSED;
-        } else if (rate.mSpeed != 0.f
-                && (mCurrentState & (MEDIA_PLAYER2_PREPARED | MEDIA_PLAYER2_PAUSED
-                    | MEDIA_PLAYER2_PLAYBACK_COMPLETE))) {
-            mCurrentState = MEDIA_PLAYER2_STARTED;
-        }
-    }
     return err;
 }
 
-status_t MediaPlayer2::getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */)
-{
+status_t MediaPlayer2::getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */) {
     Mutex::Autolock _l(mLock);
-    if (mPlayer == 0) return INVALID_OPERATION;
+    if (mPlayer == 0) {
+        return INVALID_OPERATION;
+    }
     return mPlayer->getPlaybackSettings(rate);
+    status_t ret = mPlayer->getPlaybackSettings(rate);
+    if (ret == NO_ERROR) {
+        ALOGV("getPlaybackSettings(%f, %f, %d, %d)",
+                rate->mSpeed, rate->mPitch, rate->mFallbackMode, rate->mStretchMode);
+    } else {
+        ALOGV("getPlaybackSettings returned %d", ret);
+    }
+    return ret;
 }
 
-status_t MediaPlayer2::setSyncSettings(const AVSyncSettings& sync, float videoFpsHint)
-{
+status_t MediaPlayer2::setSyncSettings(const AVSyncSettings& sync, float videoFpsHint) {
     ALOGV("setSyncSettings: %u %u %f %f",
             sync.mSource, sync.mAudioAdjustMode, sync.mTolerance, videoFpsHint);
     Mutex::Autolock _l(mLock);
@@ -432,83 +902,92 @@
 }
 
 status_t MediaPlayer2::getSyncSettings(
-        AVSyncSettings* sync /* nonnull */, float* videoFps /* nonnull */)
-{
+        AVSyncSettings* sync /* nonnull */, float* videoFps /* nonnull */) {
     Mutex::Autolock _l(mLock);
     if (mPlayer == 0) return INVALID_OPERATION;
-    return mPlayer->getSyncSettings(sync, videoFps);
+    status_t ret = mPlayer->getSyncSettings(sync, videoFps);
+    if (ret == NO_ERROR) {
+        ALOGV("getSyncSettings(%u, %u, %f, %f)",
+                sync->mSource, sync->mAudioAdjustMode, sync->mTolerance, *videoFps);
+    } else {
+        ALOGV("getSyncSettings returned %d", ret);
+    }
+    return ret;
+
 }
 
-status_t MediaPlayer2::getVideoWidth(int *w)
-{
+status_t MediaPlayer2::getVideoWidth(int *w) {
     ALOGV("getVideoWidth");
     Mutex::Autolock _l(mLock);
-    if (mPlayer == 0) return INVALID_OPERATION;
+    if (mPlayer == 0) {
+        return INVALID_OPERATION;
+    }
     *w = mVideoWidth;
     return NO_ERROR;
 }
 
-status_t MediaPlayer2::getVideoHeight(int *h)
-{
+status_t MediaPlayer2::getVideoHeight(int *h) {
     ALOGV("getVideoHeight");
     Mutex::Autolock _l(mLock);
-    if (mPlayer == 0) return INVALID_OPERATION;
+    if (mPlayer == 0) {
+        return INVALID_OPERATION;
+    }
     *h = mVideoHeight;
     return NO_ERROR;
 }
 
-status_t MediaPlayer2::getCurrentPosition(int *msec)
-{
+status_t MediaPlayer2::getCurrentPosition(int *msec) {
     ALOGV("getCurrentPosition");
     Mutex::Autolock _l(mLock);
-    if (mPlayer != 0) {
-        if (mCurrentPosition >= 0) {
-            ALOGV("Using cached seek position: %d", mCurrentPosition);
-            *msec = mCurrentPosition;
-            return NO_ERROR;
-        }
-        return mPlayer->getCurrentPosition(msec);
+    if (mPlayer == 0) {
+        return INVALID_OPERATION;
     }
-    return INVALID_OPERATION;
+    if (mCurrentPosition >= 0) {
+        ALOGV("Using cached seek position: %d", mCurrentPosition);
+        *msec = mCurrentPosition;
+        return NO_ERROR;
+    }
+    status_t ret = mPlayer->getCurrentPosition(msec);
+    if (ret == NO_ERROR) {
+        ALOGV("getCurrentPosition = %d", *msec);
+    } else {
+        ALOGE("getCurrentPosition returned %d", ret);
+    }
+    return ret;
 }
 
-status_t MediaPlayer2::getDuration_l(int *msec)
-{
+status_t MediaPlayer2::getDuration(int *msec) {
+    Mutex::Autolock _l(mLock);
     ALOGV("getDuration_l");
     bool isValidState = (mCurrentState & (MEDIA_PLAYER2_PREPARED | MEDIA_PLAYER2_STARTED |
             MEDIA_PLAYER2_PAUSED | MEDIA_PLAYER2_STOPPED | MEDIA_PLAYER2_PLAYBACK_COMPLETE));
-    if (mPlayer != 0 && isValidState) {
-        int durationMs;
-        status_t ret = mPlayer->getDuration(&durationMs);
-
-        if (ret != OK) {
-            // Do not enter error state just because no duration was available.
-            durationMs = -1;
-            ret = OK;
-        }
-
-        if (msec) {
-            *msec = durationMs;
-        }
-        return ret;
+    if (mPlayer == 0 || !isValidState) {
+        ALOGE("Attempt to call getDuration in wrong state: mPlayer=%p, mCurrentState=%u",
+                mPlayer.get(), mCurrentState);
+        return INVALID_OPERATION;
     }
-    ALOGE("Attempt to call getDuration in wrong state: mPlayer=%p, mCurrentState=%u",
-            mPlayer.get(), mCurrentState);
-    return INVALID_OPERATION;
+    int durationMs;
+    status_t ret = mPlayer->getDuration(&durationMs);
+
+    if (ret == NO_ERROR) {
+        ALOGV("getDuration = %d", durationMs);
+    } else {
+        ALOGE("getDuration returned %d", ret);
+        // Do not enter error state just because no duration was available.
+        durationMs = -1;
+    }
+
+    if (msec) {
+        *msec = durationMs;
+    }
+    return OK;
 }
 
-status_t MediaPlayer2::getDuration(int *msec)
-{
-    Mutex::Autolock _l(mLock);
-    return getDuration_l(msec);
-}
-
-status_t MediaPlayer2::seekTo_l(int msec, MediaPlayer2SeekMode mode)
-{
+status_t MediaPlayer2::seekTo_l(int msec, MediaPlayer2SeekMode mode) {
     ALOGV("seekTo (%d, %d)", msec, mode);
     if ((mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER2_STARTED | MEDIA_PLAYER2_PREPARED |
             MEDIA_PLAYER2_PAUSED |  MEDIA_PLAYER2_PLAYBACK_COMPLETE) ) ) {
-        if ( msec < 0 ) {
+        if (msec < 0) {
             ALOGW("Attempt to seek to invalid position: %d", msec);
             msec = 0;
         }
@@ -537,8 +1016,7 @@
             mSeekPosition = msec;
             mSeekMode = mode;
             return mPlayer->seekTo(msec, mode);
-        }
-        else {
+        } else {
             ALOGV("Seek in progress - queue up seekTo[%d, %d]", msec, mode);
             return NO_ERROR;
         }
@@ -548,8 +1026,7 @@
     return INVALID_OPERATION;
 }
 
-status_t MediaPlayer2::seekTo(int msec, MediaPlayer2SeekMode mode)
-{
+status_t MediaPlayer2::seekTo(int msec, MediaPlayer2SeekMode mode) {
     mLockThreadId = getThreadId();
     Mutex::Autolock _l(mLock);
     status_t result = seekTo_l(msec, mode);
@@ -558,26 +1035,27 @@
     return result;
 }
 
-status_t MediaPlayer2::notifyAt(int64_t mediaTimeUs)
-{
+status_t MediaPlayer2::notifyAt(int64_t mediaTimeUs) {
     Mutex::Autolock _l(mLock);
     if (mPlayer != 0) {
-        return mPlayer->notifyAt(mediaTimeUs);
+        return INVALID_OPERATION;
     }
-    return INVALID_OPERATION;
+
+    return mPlayer->notifyAt(mediaTimeUs);
 }
 
-status_t MediaPlayer2::reset_l()
-{
+status_t MediaPlayer2::reset_l() {
     mLoop = false;
-    if (mCurrentState == MEDIA_PLAYER2_IDLE) return NO_ERROR;
+    if (mCurrentState == MEDIA_PLAYER2_IDLE) {
+        return NO_ERROR;
+    }
     if (mPlayer != 0) {
         status_t ret = mPlayer->reset();
         if (ret != NO_ERROR) {
             ALOGE("reset() failed with return code (%d)", ret);
             mCurrentState = MEDIA_PLAYER2_STATE_ERROR;
         } else {
-            mPlayer->disconnect();
+            mPlayer->setListener(NULL);
             mCurrentState = MEDIA_PLAYER2_IDLE;
         }
         // setDataSource has to be called again to create a
@@ -589,8 +1067,7 @@
     return NO_ERROR;
 }
 
-status_t MediaPlayer2::reset()
-{
+status_t MediaPlayer2::reset() {
     ALOGV("reset");
     mLockThreadId = getThreadId();
     Mutex::Autolock _l(mLock);
@@ -600,8 +1077,7 @@
     return result;
 }
 
-status_t MediaPlayer2::setAudioStreamType(audio_stream_type_t type)
-{
+status_t MediaPlayer2::setAudioStreamType(audio_stream_type_t type) {
     ALOGV("MediaPlayer2::setAudioStreamType");
     Mutex::Autolock _l(mLock);
     if (mStreamType == type) return NO_ERROR;
@@ -616,16 +1092,14 @@
     return OK;
 }
 
-status_t MediaPlayer2::getAudioStreamType(audio_stream_type_t *type)
-{
+status_t MediaPlayer2::getAudioStreamType(audio_stream_type_t *type) {
     ALOGV("getAudioStreamType");
     Mutex::Autolock _l(mLock);
     *type = mStreamType;
     return OK;
 }
 
-status_t MediaPlayer2::setLooping(int loop)
-{
+status_t MediaPlayer2::setLooping(int loop) {
     ALOGV("MediaPlayer2::setLooping");
     Mutex::Autolock _l(mLock);
     mLoop = (loop != 0);
@@ -645,20 +1119,18 @@
     return false;
 }
 
-status_t MediaPlayer2::setVolume(float leftVolume, float rightVolume)
-{
+status_t MediaPlayer2::setVolume(float leftVolume, float rightVolume) {
     ALOGV("MediaPlayer2::setVolume(%f, %f)", leftVolume, rightVolume);
     Mutex::Autolock _l(mLock);
     mLeftVolume = leftVolume;
     mRightVolume = rightVolume;
-    if (mPlayer != 0) {
-        return mPlayer->setVolume(leftVolume, rightVolume);
+    if (mAudioOutput != 0) {
+        mAudioOutput->setVolume(leftVolume, rightVolume);
     }
     return OK;
 }
 
-status_t MediaPlayer2::setAudioSessionId(audio_session_t sessionId)
-{
+status_t MediaPlayer2::setAudioSessionId(audio_session_t sessionId) {
     ALOGV("MediaPlayer2::setAudioSessionId(%d)", sessionId);
     Mutex::Autolock _l(mLock);
     if (!(mCurrentState & MEDIA_PLAYER2_IDLE)) {
@@ -676,40 +1148,36 @@
     return NO_ERROR;
 }
 
-audio_session_t MediaPlayer2::getAudioSessionId()
-{
+audio_session_t MediaPlayer2::getAudioSessionId() {
     Mutex::Autolock _l(mLock);
     return mAudioSessionId;
 }
 
-status_t MediaPlayer2::setAuxEffectSendLevel(float level)
-{
+status_t MediaPlayer2::setAuxEffectSendLevel(float level) {
     ALOGV("MediaPlayer2::setAuxEffectSendLevel(%f)", level);
     Mutex::Autolock _l(mLock);
     mSendLevel = level;
-    if (mPlayer != 0) {
-        return mPlayer->setAuxEffectSendLevel(level);
+    if (mAudioOutput != 0) {
+        return mAudioOutput->setAuxEffectSendLevel(level);
     }
     return OK;
 }
 
-status_t MediaPlayer2::attachAuxEffect(int effectId)
-{
+status_t MediaPlayer2::attachAuxEffect(int effectId) {
     ALOGV("MediaPlayer2::attachAuxEffect(%d)", effectId);
     Mutex::Autolock _l(mLock);
-    if (mPlayer == 0 ||
+    if (mAudioOutput == 0 ||
         (mCurrentState & MEDIA_PLAYER2_IDLE) ||
         (mCurrentState == MEDIA_PLAYER2_STATE_ERROR )) {
         ALOGE("attachAuxEffect called in state %d, mPlayer(%p)", mCurrentState, mPlayer.get());
         return INVALID_OPERATION;
     }
 
-    return mPlayer->attachAuxEffect(effectId);
+    return mAudioOutput->attachAuxEffect(effectId);
 }
 
 // always call with lock held
-status_t MediaPlayer2::checkStateForKeySet_l(int key)
-{
+status_t MediaPlayer2::checkStateForKeySet_l(int key) {
     switch(key) {
     case MEDIA2_KEY_PARAMETER_AUDIO_ATTRIBUTES:
         if (mCurrentState & ( MEDIA_PLAYER2_PREPARED | MEDIA_PLAYER2_STARTED |
@@ -726,8 +1194,7 @@
     return OK;
 }
 
-status_t MediaPlayer2::setParameter(int key, const Parcel& request)
-{
+status_t MediaPlayer2::setParameter(int key, const Parcel& request) {
     ALOGV("MediaPlayer2::setParameter(%d)", key);
     status_t status = INVALID_OPERATION;
     Mutex::Autolock _l(mLock);
@@ -737,10 +1204,15 @@
     switch (key) {
     case MEDIA2_KEY_PARAMETER_AUDIO_ATTRIBUTES:
         // save the marshalled audio attributes
-        if (mAudioAttributesParcel != NULL) { delete mAudioAttributesParcel; };
+        if (mAudioAttributesParcel != NULL) {
+            delete mAudioAttributesParcel;
+        }
         mAudioAttributesParcel = new Parcel();
         mAudioAttributesParcel->appendFrom(&request, 0, request.dataSize());
-        status = OK;
+        status = setAudioAttributes_l(request);
+        if (status != OK) {
+            return status;
+        }
         break;
     default:
         ALOGV_IF(mPlayer == NULL, "setParameter: no active player");
@@ -753,25 +1225,59 @@
     return status;
 }
 
-status_t MediaPlayer2::getParameter(int key, Parcel *reply)
-{
+status_t MediaPlayer2::getParameter(int key, Parcel *reply) {
     ALOGV("MediaPlayer2::getParameter(%d)", key);
     Mutex::Autolock _l(mLock);
-    if (mPlayer != NULL) {
-        status_t status =  mPlayer->getParameter(key, reply);
-        if (status != OK) {
-            ALOGD("getParameter returns %d", status);
-        }
-        return status;
+    if (mPlayer == NULL) {
+        ALOGV("getParameter: no active player");
+        return INVALID_OPERATION;
     }
-    ALOGV("getParameter: no active player");
-    return INVALID_OPERATION;
+
+    status_t status =  mPlayer->getParameter(key, reply);
+    if (status != OK) {
+        ALOGD("getParameter returns %d", status);
+    }
+    return status;
 }
 
-void MediaPlayer2::notify(int64_t srcId, int msg, int ext1, int ext2, const Parcel *obj)
-{
+bool MediaPlayer2::shouldDropMetadata(media::Metadata::Type code) const {
+    Mutex::Autolock lock(mLock);
+
+    if (findMetadata(mMetadataDrop, code)) {
+        return true;
+    }
+
+    if (mMetadataAllow.isEmpty() || findMetadata(mMetadataAllow, code)) {
+        return false;
+    } else {
+        return true;
+    }
+}
+
+
+void MediaPlayer2::addNewMetadataUpdate(media::Metadata::Type metadata_type) {
+    Mutex::Autolock lock(mLock);
+    if (mMetadataUpdated.indexOf(metadata_type) < 0) {
+        mMetadataUpdated.add(metadata_type);
+    }
+}
+
+void MediaPlayer2::notify(int64_t srcId, int msg, int ext1, int ext2, const Parcel *obj) {
     ALOGV("message received srcId=%lld, msg=%d, ext1=%d, ext2=%d",
           (long long)srcId, msg, ext1, ext2);
+
+    if (MEDIA2_INFO == msg && MEDIA2_INFO_METADATA_UPDATE == ext1) {
+        const media::Metadata::Type metadata_type = ext2;
+
+        if(shouldDropMetadata(metadata_type)) {
+            return;
+        }
+
+        // Update the list of metadata that have changed. getMetadata
+        // also access mMetadataUpdated and clears it.
+        addNewMetadataUpdate(metadata_type);
+    }
+
     bool send = true;
     bool locked = false;
 
@@ -881,24 +1387,12 @@
     }
 }
 
-status_t MediaPlayer2::setNextMediaPlayer(const sp<MediaPlayer2>& next) {
-    Mutex::Autolock _l(mLock);
-    if (mPlayer == NULL) {
-        return NO_INIT;
-    }
-
-    if (next != NULL && !(next->mCurrentState &
-            (MEDIA_PLAYER2_PREPARED | MEDIA_PLAYER2_PAUSED | MEDIA_PLAYER2_PLAYBACK_COMPLETE))) {
-        ALOGE("next player is not prepared");
-        return INVALID_OPERATION;
-    }
-
-    return mPlayer->setNextPlayer(next == NULL ? NULL : next->mPlayer);
+status_t MediaPlayer2::setNextMediaPlayer(const sp<MediaPlayer2>& /* next */) {
+    return INVALID_OPERATION;
 }
 
 // Modular DRM
-status_t MediaPlayer2::prepareDrm(const uint8_t uuid[16], const Vector<uint8_t>& drmSessionId)
-{
+status_t MediaPlayer2::prepareDrm(const uint8_t uuid[16], const Vector<uint8_t>& drmSessionId) {
     // TODO change to ALOGV
     ALOGD("prepareDrm: uuid: %p  drmSessionId: %p(%zu)", uuid,
             drmSessionId.array(), drmSessionId.size());
@@ -931,8 +1425,7 @@
     return status;
 }
 
-status_t MediaPlayer2::releaseDrm()
-{
+status_t MediaPlayer2::releaseDrm() {
     Mutex::Autolock _l(mLock);
     if (mPlayer == NULL) {
         return NO_INIT;
@@ -960,39 +1453,74 @@
     return status;
 }
 
-status_t MediaPlayer2::setOutputDevice(audio_port_handle_t deviceId)
-{
+status_t MediaPlayer2::setOutputDevice(audio_port_handle_t deviceId) {
     Mutex::Autolock _l(mLock);
-    if (mPlayer == NULL) {
-        ALOGV("setOutputDevice: player not init");
+    if (mAudioOutput == NULL) {
+        ALOGV("setOutputDevice: audio sink not init");
         return NO_INIT;
     }
-    return mPlayer->setOutputDevice(deviceId);
+    return mAudioOutput->setOutputDevice(deviceId);
 }
 
-audio_port_handle_t MediaPlayer2::getRoutedDeviceId()
-{
+audio_port_handle_t MediaPlayer2::getRoutedDeviceId() {
     Mutex::Autolock _l(mLock);
-    if (mPlayer == NULL) {
-        ALOGV("getRoutedDeviceId: player not init");
+    if (mAudioOutput == NULL) {
+        ALOGV("getRoutedDeviceId: audio sink not init");
         return AUDIO_PORT_HANDLE_NONE;
     }
     audio_port_handle_t deviceId;
-    status_t status = mPlayer->getRoutedDeviceId(&deviceId);
+    status_t status = mAudioOutput->getRoutedDeviceId(&deviceId);
     if (status != NO_ERROR) {
         return AUDIO_PORT_HANDLE_NONE;
     }
     return deviceId;
 }
 
-status_t MediaPlayer2::enableAudioDeviceCallback(bool enabled)
-{
+status_t MediaPlayer2::enableAudioDeviceCallback(bool enabled) {
     Mutex::Autolock _l(mLock);
-    if (mPlayer == NULL) {
+    if (mAudioOutput == NULL) {
         ALOGV("addAudioDeviceCallback: player not init");
         return NO_INIT;
     }
-    return mPlayer->enableAudioDeviceCallback(enabled);
+    return mAudioOutput->enableAudioDeviceCallback(enabled);
+}
+
+status_t MediaPlayer2::dump(int fd, const Vector<String16>& args) {
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    result.append(" MediaPlayer2\n");
+    snprintf(buffer, 255, "  pid(%d), looping(%s)\n", mPid, mLoop?"true": "false");
+    result.append(buffer);
+
+    sp<MediaPlayer2Interface> player;
+    sp<MediaPlayer2AudioOutput> audioOutput;
+    bool locked = false;
+    for (int i = 0; i < kDumpLockRetries; ++i) {
+        if (mLock.tryLock() == NO_ERROR) {
+            locked = true;
+            break;
+        }
+        usleep(kDumpLockSleepUs);
+    }
+
+    if (locked) {
+        player = mPlayer;
+        audioOutput = mAudioOutput;
+        mLock.unlock();
+    } else {
+        result.append("  lock is taken, no dump from player and audio output\n");
+    }
+    write(fd, result.string(), result.size());
+
+    if (player != NULL) {
+        player->dump(fd, args);
+    }
+    if (audioOutput != 0) {
+        audioOutput->dump(fd, args);
+    }
+    write(fd, "\n", 1);
+    return NO_ERROR;
 }
 
 } // namespace android