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