1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261 |
- /*
- **
- ** Copyright 2017, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- ** http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
- //#define LOG_NDEBUG 0
- #define LOG_TAG "MediaPlayer2Native"
- #include <android/binder_ibinder.h>
- #include <media/AudioSystem.h>
- #include <media/DataSourceDesc.h>
- #include <media/MemoryLeakTrackUtil.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 <utils/Log.h>
- #include <utils/SortedVector.h>
- #include <utils/String8.h>
- #include <system/audio.h>
- #include <system/window.h>
- #include <nuplayer2/NuPlayer2Driver.h>
- #include <dirent.h>
- #include <sys/stat.h>
- namespace android {
- extern ALooperRoster gLooperRoster;
- namespace {
- const int kDumpLockRetries = 50;
- const int kDumpLockSleepUs = 20000;
- 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 PlayerMessage *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.
- {
- 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(int32_t sessionId, jobject context) {
- sp<MediaPlayer2> player = new MediaPlayer2(sessionId, context);
- 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(int32_t sessionId, jobject context) {
- ALOGV("constructor");
- mSrcId = 0;
- mLockThreadId = 0;
- mListener = NULL;
- mStreamType = AUDIO_STREAM_MUSIC;
- mAudioAttributes = NULL;
- mContext = new JObjectHolder(context);
- mCurrentPosition = -1;
- mCurrentSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
- mSeekPosition = -1;
- mSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
- mCurrentState = MEDIA_PLAYER2_IDLE;
- mTransitionToNext = false;
- mLoop = false;
- mVolume = 1.0;
- mVideoWidth = mVideoHeight = 0;
- mSendLevel = 0;
- mPid = AIBinder_getCallingPid();
- mUid = AIBinder_getCallingUid();
- mAudioOutput = new MediaPlayer2AudioOutput(sessionId, mUid, mPid, NULL /*attributes*/);
- }
- MediaPlayer2::~MediaPlayer2() {
- ALOGV("destructor");
- disconnect();
- removePlayer(this);
- }
- bool MediaPlayer2::init() {
- // TODO: after merge with NuPlayer2Driver, MediaPlayer2 will have its own
- // looper for notification.
- return true;
- }
- void MediaPlayer2::disconnect() {
- ALOGV("disconnect");
- sp<MediaPlayer2Interface> p;
- {
- Mutex::Autolock _l(mLock);
- p = mPlayer;
- mPlayer.clear();
- }
- if (p != 0) {
- p->setListener(NULL);
- p->reset();
- }
- {
- Mutex::Autolock _l(mLock);
- disconnectNativeWindow_l();
- }
- }
- void MediaPlayer2::clear_l() {
- mCurrentPosition = -1;
- mCurrentSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
- mSeekPosition = -1;
- mSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
- mVideoWidth = mVideoHeight = 0;
- }
- status_t MediaPlayer2::setListener(const sp<MediaPlayer2Listener>& listener) {
- ALOGV("setListener");
- Mutex::Autolock _l(mLock);
- mListener = listener;
- return NO_ERROR;
- }
- status_t MediaPlayer2::getSrcId(int64_t *srcId) {
- if (srcId == NULL) {
- return BAD_VALUE;
- }
- Mutex::Autolock _l(mLock);
- *srcId = mSrcId;
- return OK;
- }
- status_t MediaPlayer2::setDataSource(const sp<DataSourceDesc> &dsd) {
- if (dsd == NULL) {
- return BAD_VALUE;
- }
- // Microsecond is used in NuPlayer2.
- if (dsd->mStartPositionMs > DataSourceDesc::kMaxTimeMs) {
- dsd->mStartPositionMs = DataSourceDesc::kMaxTimeMs;
- ALOGW("setDataSource, start poistion clamped to %lld ms", (long long)dsd->mStartPositionMs);
- }
- if (dsd->mEndPositionMs > DataSourceDesc::kMaxTimeMs) {
- dsd->mEndPositionMs = DataSourceDesc::kMaxTimeMs;
- ALOGW("setDataSource, end poistion clamped to %lld ms", (long long)dsd->mStartPositionMs);
- }
- 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, mContext);
- 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));
- 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;
- }
- if (oldPlayer != NULL) {
- oldPlayer->setListener(NULL);
- oldPlayer->reset();
- }
- return OK;
- }
- status_t MediaPlayer2::prepareNextDataSource(const sp<DataSourceDesc> &dsd) {
- if (dsd == NULL) {
- return BAD_VALUE;
- }
- ALOGV("prepareNextDataSource type(%d), srcId(%lld)", dsd->mType, (long long)dsd->mId);
- Mutex::Autolock _l(mLock);
- if (mPlayer == NULL) {
- 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) {
- ALOGE("playNextDataSource failed: state %X, mPlayer(%p)", mCurrentState, mPlayer.get());
- return INVALID_OPERATION;
- }
- mSrcId = srcId;
- mTransitionToNext = true;
- return mPlayer->playNextDataSource(srcId);
- }
- status_t MediaPlayer2::invoke(const PlayerMessage &request, PlayerMessage *reply) {
- Mutex::Autolock _l(mLock);
- const bool hasBeenInitialized =
- (mCurrentState != MEDIA_PLAYER2_STATE_ERROR) &&
- ((mCurrentState & MEDIA_PLAYER2_IDLE) != MEDIA_PLAYER2_IDLE);
- if ((mPlayer == NULL) || !hasBeenInitialized) {
- ALOGE("invoke() failed: wrong state %X, mPlayer(%p)", mCurrentState, mPlayer.get());
- return INVALID_OPERATION;
- }
- return mPlayer->invoke(request, reply);
- }
- 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;
- }
- 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::getBufferingSettings(BufferingSettings* buffering /* nonnull */) {
- ALOGV("getBufferingSettings");
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) {
- return NO_INIT;
- }
- 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{%s}", buffering.toString().string());
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) {
- return NO_INIT;
- }
- return mPlayer->setBufferingSettings(buffering);
- }
- status_t MediaPlayer2::setAudioAttributes_l(const jobject attributes) {
- if (mAudioOutput != NULL) {
- mAudioOutput->setAudioAttributes(attributes);
- }
- return NO_ERROR;
- }
- status_t MediaPlayer2::prepareAsync() {
- ALOGV("prepareAsync");
- Mutex::Autolock _l(mLock);
- if ((mPlayer != 0) && (mCurrentState & MEDIA_PLAYER2_INITIALIZED)) {
- if (mAudioAttributes != NULL) {
- status_t err = setAudioAttributes_l(mAudioAttributes->getJObject());
- if (err != OK) {
- return err;
- }
- }
- mCurrentState = MEDIA_PLAYER2_PREPARING;
- return mPlayer->prepareAsync();
- }
- ALOGE("prepareAsync called in state %d, mPlayer(%p)", mCurrentState, mPlayer.get());
- return INVALID_OPERATION;
- }
- status_t MediaPlayer2::start() {
- ALOGV("start");
- status_t ret = NO_ERROR;
- Mutex::Autolock _l(mLock);
- mLockThreadId = getThreadId();
- if (mCurrentState & MEDIA_PLAYER2_STARTED) {
- ret = NO_ERROR;
- } else if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER2_PREPARED |
- MEDIA_PLAYER2_PLAYBACK_COMPLETE | MEDIA_PLAYER2_PAUSED ) ) ) {
- mPlayer->setLooping(mLoop);
- if (mAudioOutput != 0) {
- mAudioOutput->setVolume(mVolume);
- }
- if (mAudioOutput != 0) {
- mAudioOutput->setAuxEffectSendLevel(mSendLevel);
- }
- mCurrentState = MEDIA_PLAYER2_STARTED;
- ret = mPlayer->start();
- if (ret != NO_ERROR) {
- mCurrentState = MEDIA_PLAYER2_STATE_ERROR;
- } else {
- if (mCurrentState == MEDIA_PLAYER2_PLAYBACK_COMPLETE) {
- ALOGV("playback completed immediately following start()");
- }
- }
- } else {
- ALOGE("start called in state %d, mPlayer(%p)", mCurrentState, mPlayer.get());
- ret = INVALID_OPERATION;
- }
- mLockThreadId = 0;
- return ret;
- }
- status_t MediaPlayer2::pause() {
- ALOGV("pause");
- Mutex::Autolock _l(mLock);
- if (mCurrentState & (MEDIA_PLAYER2_PAUSED|MEDIA_PLAYER2_PLAYBACK_COMPLETE))
- return NO_ERROR;
- if ((mPlayer != 0) && (mCurrentState & (MEDIA_PLAYER2_STARTED | MEDIA_PLAYER2_PREPARED))) {
- status_t ret = mPlayer->pause();
- if (ret != NO_ERROR) {
- mCurrentState = MEDIA_PLAYER2_STATE_ERROR;
- } else {
- mCurrentState = MEDIA_PLAYER2_PAUSED;
- mTransitionToNext = false;
- }
- return ret;
- }
- ALOGE("pause called in state %d, mPlayer(%p)", mCurrentState, mPlayer.get());
- return INVALID_OPERATION;
- }
- bool MediaPlayer2::isPlaying() {
- Mutex::Autolock _l(mLock);
- if (mPlayer != 0) {
- bool temp = mPlayer->isPlaying();
- ALOGV("isPlaying: %d", temp);
- if ((mCurrentState & MEDIA_PLAYER2_STARTED) && ! temp) {
- ALOGE("internal/external state mismatch corrected");
- mCurrentState = MEDIA_PLAYER2_PAUSED;
- } else if ((mCurrentState & MEDIA_PLAYER2_PAUSED) && temp) {
- ALOGE("internal/external state mismatch corrected");
- mCurrentState = MEDIA_PLAYER2_STARTED;
- }
- return temp;
- }
- ALOGV("isPlaying: no active player");
- return false;
- }
- mediaplayer2_states MediaPlayer2::getState() {
- Mutex::Autolock _l(mLock);
- if (mCurrentState & MEDIA_PLAYER2_STATE_ERROR) {
- return MEDIAPLAYER2_STATE_ERROR;
- }
- if (mPlayer == 0
- || (mCurrentState &
- (MEDIA_PLAYER2_IDLE | MEDIA_PLAYER2_INITIALIZED | MEDIA_PLAYER2_PREPARING))) {
- return MEDIAPLAYER2_STATE_IDLE;
- }
- if (mCurrentState & MEDIA_PLAYER2_STARTED) {
- return MEDIAPLAYER2_STATE_PLAYING;
- }
- if (mCurrentState & (MEDIA_PLAYER2_PAUSED | MEDIA_PLAYER2_PLAYBACK_COMPLETE)) {
- return MEDIAPLAYER2_STATE_PAUSED;
- }
- // now only mCurrentState & MEDIA_PLAYER2_PREPARED is true
- return MEDIAPLAYER2_STATE_PREPARED;
- }
- 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) {
- return BAD_VALUE;
- }
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) {
- return INVALID_OPERATION;
- }
- status_t err = mPlayer->setPlaybackSettings(rate);
- return err;
- }
- status_t MediaPlayer2::getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */) {
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) {
- return INVALID_OPERATION;
- }
- 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) {
- ALOGV("setSyncSettings: %u %u %f %f",
- sync.mSource, sync.mAudioAdjustMode, sync.mTolerance, videoFpsHint);
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) return INVALID_OPERATION;
- return mPlayer->setSyncSettings(sync, videoFpsHint);
- }
- status_t MediaPlayer2::getSyncSettings(
- AVSyncSettings* sync /* nonnull */, float* videoFps /* nonnull */) {
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) {
- return INVALID_OPERATION;
- }
- 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) {
- ALOGV("getVideoWidth");
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) {
- return INVALID_OPERATION;
- }
- *w = mVideoWidth;
- return NO_ERROR;
- }
- status_t MediaPlayer2::getVideoHeight(int *h) {
- ALOGV("getVideoHeight");
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) {
- return INVALID_OPERATION;
- }
- *h = mVideoHeight;
- return NO_ERROR;
- }
- status_t MediaPlayer2::getCurrentPosition(int64_t *msec) {
- ALOGV("getCurrentPosition");
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) {
- return INVALID_OPERATION;
- }
- if (mCurrentPosition >= 0) {
- ALOGV("Using cached seek position: %lld", (long long)mCurrentPosition);
- *msec = mCurrentPosition;
- return NO_ERROR;
- }
- status_t ret = mPlayer->getCurrentPosition(msec);
- if (ret == NO_ERROR) {
- ALOGV("getCurrentPosition = %lld", (long long)*msec);
- } else {
- ALOGE("getCurrentPosition returned %d", ret);
- }
- return ret;
- }
- status_t MediaPlayer2::getDuration(int64_t srcId, int64_t *msec) {
- Mutex::Autolock _l(mLock);
- // TODO: cache duration for currentSrcId and nextSrcId, and return correct
- // value for nextSrcId.
- if (srcId != mSrcId) {
- *msec = -1;
- return OK;
- }
- ALOGV("getDuration_l");
- bool isValidState = (mCurrentState & (MEDIA_PLAYER2_PREPARED | MEDIA_PLAYER2_STARTED |
- MEDIA_PLAYER2_PAUSED | MEDIA_PLAYER2_PLAYBACK_COMPLETE));
- if (mPlayer == 0 || !isValidState) {
- ALOGE("Attempt to call getDuration in wrong state: mPlayer=%p, mCurrentState=%u",
- mPlayer.get(), mCurrentState);
- return INVALID_OPERATION;
- }
- int64_t durationMs;
- status_t ret = mPlayer->getDuration(&durationMs);
- if (ret == NO_ERROR) {
- ALOGV("getDuration = %lld", (long long)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::seekTo_l(int64_t msec, MediaPlayer2SeekMode mode) {
- ALOGV("seekTo (%lld, %d)", (long long)msec, mode);
- if ((mPlayer == 0) || !(mCurrentState & (MEDIA_PLAYER2_STARTED | MEDIA_PLAYER2_PREPARED |
- MEDIA_PLAYER2_PAUSED | MEDIA_PLAYER2_PLAYBACK_COMPLETE))) {
- ALOGE("Attempt to perform seekTo in wrong state: mPlayer=%p, mCurrentState=%u",
- mPlayer.get(), mCurrentState);
- return INVALID_OPERATION;
- }
- if (msec < 0) {
- ALOGW("Attempt to seek to invalid position: %lld", (long long)msec);
- msec = 0;
- }
- int64_t durationMs;
- status_t err = mPlayer->getDuration(&durationMs);
- if (err != OK) {
- ALOGW("Stream has no duration and is therefore not seekable.");
- return err;
- }
- if (msec > durationMs) {
- ALOGW("Attempt to seek to past end of file: request = %lld, durationMs = %lld",
- (long long)msec, (long long)durationMs);
- msec = durationMs;
- }
- // cache duration
- mCurrentPosition = msec;
- mCurrentSeekMode = mode;
- if (mSeekPosition < 0) {
- mSeekPosition = msec;
- mSeekMode = mode;
- return mPlayer->seekTo(msec, mode);
- }
- ALOGV("Seek in progress - queue up seekTo[%lld, %d]", (long long)msec, mode);
- return NO_ERROR;
- }
- status_t MediaPlayer2::seekTo(int64_t msec, MediaPlayer2SeekMode mode) {
- mLockThreadId = getThreadId();
- Mutex::Autolock _l(mLock);
- status_t result = seekTo_l(msec, mode);
- mLockThreadId = 0;
- return result;
- }
- status_t MediaPlayer2::notifyAt(int64_t mediaTimeUs) {
- Mutex::Autolock _l(mLock);
- if (mPlayer != 0) {
- return INVALID_OPERATION;
- }
- return mPlayer->notifyAt(mediaTimeUs);
- }
- status_t MediaPlayer2::reset_l() {
- mLoop = false;
- 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->setListener(NULL);
- mCurrentState = MEDIA_PLAYER2_IDLE;
- mTransitionToNext = false;
- }
- // setDataSource has to be called again to create a
- // new mediaplayer.
- mPlayer = 0;
- return ret;
- }
- clear_l();
- return NO_ERROR;
- }
- status_t MediaPlayer2::reset() {
- ALOGV("reset");
- mLockThreadId = getThreadId();
- Mutex::Autolock _l(mLock);
- status_t result = reset_l();
- mLockThreadId = 0;
- return result;
- }
- status_t MediaPlayer2::setAudioStreamType(audio_stream_type_t type) {
- ALOGV("MediaPlayer2::setAudioStreamType");
- Mutex::Autolock _l(mLock);
- if (mStreamType == type) return NO_ERROR;
- if (mCurrentState & ( MEDIA_PLAYER2_PREPARED | MEDIA_PLAYER2_STARTED |
- MEDIA_PLAYER2_PAUSED | MEDIA_PLAYER2_PLAYBACK_COMPLETE ) ) {
- // Can't change the stream type after prepare
- ALOGE("setAudioStream called in state %d", mCurrentState);
- return INVALID_OPERATION;
- }
- // cache
- mStreamType = type;
- return OK;
- }
- 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) {
- ALOGV("MediaPlayer2::setLooping");
- Mutex::Autolock _l(mLock);
- mLoop = (loop != 0);
- if (mPlayer != 0) {
- return mPlayer->setLooping(loop);
- }
- return OK;
- }
- bool MediaPlayer2::isLooping() {
- ALOGV("isLooping");
- Mutex::Autolock _l(mLock);
- if (mPlayer != 0) {
- return mLoop;
- }
- ALOGV("isLooping: no active player");
- return false;
- }
- status_t MediaPlayer2::setVolume(float volume) {
- ALOGV("MediaPlayer2::setVolume(%f)", volume);
- Mutex::Autolock _l(mLock);
- mVolume = volume;
- if (mAudioOutput != 0) {
- mAudioOutput->setVolume(volume);
- }
- return OK;
- }
- status_t MediaPlayer2::setAudioSessionId(int32_t sessionId) {
- ALOGV("MediaPlayer2::setAudioSessionId(%d)", sessionId);
- Mutex::Autolock _l(mLock);
- if (!(mCurrentState & MEDIA_PLAYER2_IDLE)) {
- ALOGE("setAudioSessionId called in state %d", mCurrentState);
- return INVALID_OPERATION;
- }
- if (sessionId < 0) {
- return BAD_VALUE;
- }
- if (mAudioOutput != NULL && sessionId != mAudioOutput->getSessionId()) {
- mAudioOutput->setSessionId(sessionId);
- }
- return NO_ERROR;
- }
- int32_t MediaPlayer2::getAudioSessionId() {
- Mutex::Autolock _l(mLock);
- if (mAudioOutput != NULL) {
- return mAudioOutput->getSessionId();
- }
- return 0;
- }
- status_t MediaPlayer2::setAuxEffectSendLevel(float level) {
- ALOGV("MediaPlayer2::setAuxEffectSendLevel(%f)", level);
- Mutex::Autolock _l(mLock);
- mSendLevel = level;
- if (mAudioOutput != 0) {
- return mAudioOutput->setAuxEffectSendLevel(level);
- }
- return OK;
- }
- status_t MediaPlayer2::attachAuxEffect(int effectId) {
- ALOGV("MediaPlayer2::attachAuxEffect(%d)", effectId);
- Mutex::Autolock _l(mLock);
- 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 mAudioOutput->attachAuxEffect(effectId);
- }
- // always call with lock held
- status_t MediaPlayer2::checkState_l() {
- if (mCurrentState & ( MEDIA_PLAYER2_PREPARED | MEDIA_PLAYER2_STARTED |
- MEDIA_PLAYER2_PAUSED | MEDIA_PLAYER2_PLAYBACK_COMPLETE) ) {
- // Can't change the audio attributes after prepare
- ALOGE("trying to set audio attributes called in state %d", mCurrentState);
- return INVALID_OPERATION;
- }
- return OK;
- }
- status_t MediaPlayer2::setAudioAttributes(const jobject attributes) {
- ALOGV("MediaPlayer2::setAudioAttributes");
- status_t status = INVALID_OPERATION;
- Mutex::Autolock _l(mLock);
- if (checkState_l() != OK) {
- return status;
- }
- mAudioAttributes = new JObjectHolder(attributes);
- status = setAudioAttributes_l(attributes);
- return status;
- }
- jobject MediaPlayer2::getAudioAttributes() {
- ALOGV("MediaPlayer2::getAudioAttributes)");
- Mutex::Autolock _l(mLock);
- return mAudioAttributes != NULL ? mAudioAttributes->getJObject() : NULL;
- }
- status_t MediaPlayer2::getParameter(int key, Parcel *reply) {
- ALOGV("MediaPlayer2::getParameter(%d)", key);
- Mutex::Autolock _l(mLock);
- if (mPlayer == NULL) {
- 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;
- }
- // for mediametrics
- status_t MediaPlayer2::getMetrics(char **buffer, size_t *length) {
- ALOGD("MediaPlayer2::getMetrics()");
- Mutex::Autolock _l(mLock);
- if (mPlayer == NULL) {
- ALOGV("getMetrics: no active player");
- return INVALID_OPERATION;
- }
- status_t status = mPlayer->getMetrics(buffer, length);
- if (status != OK) {
- ALOGD("getMetrics returns %d", status);
- }
- return status;
- }
- void MediaPlayer2::notify(int64_t srcId, int msg, int ext1, int ext2, const PlayerMessage *obj) {
- ALOGV("message received srcId=%lld, msg=%d, ext1=%d, ext2=%d",
- (long long)srcId, msg, ext1, ext2);
- bool send = true;
- bool locked = false;
- // TODO: In the future, we might be on the same thread if the app is
- // running in the same process as the media server. In that case,
- // this will deadlock.
- //
- // The threadId hack below works around this for the care of prepare,
- // seekTo, start, and reset within the same process.
- // FIXME: Remember, this is a hack, it's not even a hack that is applied
- // consistently for all use-cases, this needs to be revisited.
- if (mLockThreadId != getThreadId()) {
- mLock.lock();
- locked = true;
- }
- // Allows calls from JNI in idle state to notify errors
- if (!(msg == MEDIA2_ERROR && mCurrentState == MEDIA_PLAYER2_IDLE) && mPlayer == 0) {
- ALOGV("notify(%lld, %d, %d, %d) callback on disconnected mediaplayer",
- (long long)srcId, msg, ext1, ext2);
- if (locked) mLock.unlock(); // release the lock when done.
- return;
- }
- switch (msg) {
- case MEDIA2_NOP: // interface test message
- break;
- case MEDIA2_PREPARED:
- ALOGV("MediaPlayer2::notify() prepared, srcId=%lld", (long long)srcId);
- if (srcId == mSrcId) {
- mCurrentState = MEDIA_PLAYER2_PREPARED;
- }
- break;
- case MEDIA2_DRM_INFO:
- ALOGV("MediaPlayer2::notify() MEDIA2_DRM_INFO(%lld, %d, %d, %d, %p)",
- (long long)srcId, msg, ext1, ext2, obj);
- break;
- case MEDIA2_PLAYBACK_COMPLETE:
- ALOGV("playback complete");
- if (mCurrentState == MEDIA_PLAYER2_IDLE) {
- ALOGE("playback complete in idle state");
- }
- if (!mLoop && srcId == mSrcId) {
- mCurrentState = MEDIA_PLAYER2_PLAYBACK_COMPLETE;
- }
- break;
- case MEDIA2_ERROR:
- // Always log errors.
- // ext1: Media framework error code.
- // ext2: Implementation dependant error code.
- ALOGE("error (%d, %d)", ext1, ext2);
- mCurrentState = MEDIA_PLAYER2_STATE_ERROR;
- break;
- case MEDIA2_INFO:
- // ext1: Media framework error code.
- // ext2: Implementation dependant error code.
- if (ext1 != MEDIA2_INFO_VIDEO_TRACK_LAGGING) {
- ALOGW("info/warning (%d, %d)", ext1, ext2);
- if (ext1 == MEDIA2_INFO_DATA_SOURCE_START && srcId == mSrcId && mTransitionToNext) {
- mCurrentState = MEDIA_PLAYER2_STARTED;
- mTransitionToNext = false;
- }
- }
- break;
- case MEDIA2_SEEK_COMPLETE:
- ALOGV("Received seek complete");
- if (mSeekPosition != mCurrentPosition || (mSeekMode != mCurrentSeekMode)) {
- ALOGV("Executing queued seekTo(%lld, %d)",
- (long long)mCurrentPosition, mCurrentSeekMode);
- mSeekPosition = -1;
- mSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
- seekTo_l(mCurrentPosition, mCurrentSeekMode);
- }
- else {
- ALOGV("All seeks complete - return to regularly scheduled program");
- mCurrentPosition = mSeekPosition = -1;
- mCurrentSeekMode = mSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
- }
- break;
- case MEDIA2_BUFFERING_UPDATE:
- ALOGV("buffering %d", ext1);
- break;
- case MEDIA2_SET_VIDEO_SIZE:
- ALOGV("New video size %d x %d", ext1, ext2);
- mVideoWidth = ext1;
- mVideoHeight = ext2;
- break;
- case MEDIA2_NOTIFY_TIME:
- ALOGV("Received notify time message");
- break;
- case MEDIA2_TIMED_TEXT:
- ALOGV("Received timed text message");
- break;
- case MEDIA2_SUBTITLE_DATA:
- ALOGV("Received subtitle data message");
- break;
- case MEDIA2_META_DATA:
- ALOGV("Received timed metadata message");
- break;
- default:
- ALOGV("unrecognized message: (%d, %d, %d)", msg, ext1, ext2);
- break;
- }
- sp<MediaPlayer2Listener> listener = mListener;
- if (locked) mLock.unlock();
- // this prevents re-entrant calls into client code
- if ((listener != 0) && send) {
- Mutex::Autolock _l(mNotifyLock);
- ALOGV("callback application");
- listener->notify(srcId, msg, ext1, ext2, obj);
- ALOGV("back from callback");
- }
- }
- // Modular DRM
- status_t MediaPlayer2::prepareDrm(
- int64_t srcId, 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());
- Mutex::Autolock _l(mLock);
- if (mPlayer == NULL) {
- return NO_INIT;
- }
- // Only allowed it in player's preparing/prepared state.
- // We get here only if MEDIA_DRM_INFO has already arrived (e.g., prepare is half-way through or
- // completed) so the state change to "prepared" might not have happened yet (e.g., buffering).
- // Still, we can allow prepareDrm for the use case of being called in OnDrmInfoListener.
- if (!(mCurrentState & (MEDIA_PLAYER2_PREPARING | MEDIA_PLAYER2_PREPARED))) {
- ALOGW("prepareDrm(%lld) called in non-prepare state(%d)", (long long)srcId, mCurrentState);
- if (srcId == mSrcId) {
- return INVALID_OPERATION;
- }
- }
- if (drmSessionId.isEmpty()) {
- ALOGE("prepareDrm: Unexpected. Can't proceed with crypto. Empty drmSessionId.");
- return INVALID_OPERATION;
- }
- // Passing down to mediaserver mainly for creating the crypto
- status_t status = mPlayer->prepareDrm(srcId, uuid, drmSessionId);
- ALOGE_IF(status != OK, "prepareDrm: Failed at mediaserver with ret: %d", status);
- // TODO change to ALOGV
- ALOGD("prepareDrm: mediaserver::prepareDrm ret=%d", status);
- return status;
- }
- status_t MediaPlayer2::releaseDrm(int64_t srcId) {
- Mutex::Autolock _l(mLock);
- if (mPlayer == NULL) {
- return NO_INIT;
- }
- // Not allowing releaseDrm in an active/resumable state
- if (mCurrentState & (MEDIA_PLAYER2_STARTED |
- MEDIA_PLAYER2_PAUSED |
- MEDIA_PLAYER2_PLAYBACK_COMPLETE |
- MEDIA_PLAYER2_STATE_ERROR)) {
- ALOGE("releaseDrm Unexpected state %d. Can only be called in stopped/idle.", mCurrentState);
- return INVALID_OPERATION;
- }
- status_t status = mPlayer->releaseDrm(srcId);
- // TODO change to ALOGV
- ALOGD("releaseDrm: mediaserver::releaseDrm ret: %d", status);
- if (status != OK) {
- ALOGE("releaseDrm: Failed at mediaserver with ret: %d", status);
- // Overriding to OK so the client proceed with its own cleanup
- // Client can't do more cleanup. mediaserver release its crypto at end of session anyway.
- status = OK;
- }
- return status;
- }
- status_t MediaPlayer2::setPreferredDevice(jobject device) {
- Mutex::Autolock _l(mLock);
- if (mAudioOutput == NULL) {
- ALOGV("setPreferredDevice: audio sink not init");
- return NO_INIT;
- }
- return mAudioOutput->setPreferredDevice(device);
- }
- jobject MediaPlayer2::getRoutedDevice() {
- Mutex::Autolock _l(mLock);
- if (mAudioOutput == NULL) {
- ALOGV("getRoutedDevice: audio sink not init");
- return nullptr;
- }
- return mAudioOutput->getRoutedDevice();
- }
- status_t MediaPlayer2::addAudioDeviceCallback(jobject routingDelegate) {
- Mutex::Autolock _l(mLock);
- if (mAudioOutput == NULL) {
- ALOGV("addAudioDeviceCallback: player not init");
- return NO_INIT;
- }
- return mAudioOutput->addAudioDeviceCallback(routingDelegate);
- }
- status_t MediaPlayer2::removeAudioDeviceCallback(jobject listener) {
- Mutex::Autolock _l(mLock);
- if (mAudioOutput == NULL) {
- ALOGV("addAudioDeviceCallback: player not init");
- return NO_INIT;
- }
- return mAudioOutput->removeAudioDeviceCallback(listener);
- }
- 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
|