Home | History | Annotate | Download | only in nuplayer
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 //#define LOG_NDEBUG 0
     18 #define LOG_TAG "NuPlayerDriver"
     19 #include <inttypes.h>
     20 #include <android-base/macros.h>
     21 #include <utils/Log.h>
     22 #include <cutils/properties.h>
     23 
     24 #include "NuPlayerDriver.h"
     25 
     26 #include "NuPlayer.h"
     27 #include "NuPlayerSource.h"
     28 
     29 #include <media/stagefright/foundation/ADebug.h>
     30 #include <media/stagefright/foundation/ALooper.h>
     31 #include <media/stagefright/foundation/AUtils.h>
     32 #include <media/stagefright/foundation/ByteUtils.h>
     33 #include <media/stagefright/MediaClock.h>
     34 #include <media/stagefright/MetaData.h>
     35 #include <media/stagefright/Utils.h>
     36 
     37 #include <media/IMediaAnalyticsService.h>
     38 
     39 static const int kDumpLockRetries = 50;
     40 static const int kDumpLockSleepUs = 20000;
     41 
     42 namespace android {
     43 
     44 // key for media statistics
     45 static const char *kKeyPlayer = "nuplayer";
     46 // attrs for media statistics
     47     // NB: these are matched with public Java API constants defined
     48     // in frameworks/base/media/java/android/media/MediaPlayer.java
     49     // These must be kept synchronized with the constants there.
     50 static const char *kPlayerVMime = "android.media.mediaplayer.video.mime";
     51 static const char *kPlayerVCodec = "android.media.mediaplayer.video.codec";
     52 static const char *kPlayerWidth = "android.media.mediaplayer.width";
     53 static const char *kPlayerHeight = "android.media.mediaplayer.height";
     54 static const char *kPlayerFrames = "android.media.mediaplayer.frames";
     55 static const char *kPlayerFramesDropped = "android.media.mediaplayer.dropped";
     56 static const char *kPlayerFrameRate = "android.media.mediaplayer.fps";
     57 static const char *kPlayerAMime = "android.media.mediaplayer.audio.mime";
     58 static const char *kPlayerACodec = "android.media.mediaplayer.audio.codec";
     59 static const char *kPlayerDuration = "android.media.mediaplayer.durationMs";
     60 static const char *kPlayerPlaying = "android.media.mediaplayer.playingMs";
     61 static const char *kPlayerError = "android.media.mediaplayer.err";
     62 static const char *kPlayerErrorCode = "android.media.mediaplayer.errcode";
     63 
     64     // NB: These are not yet exposed as public Java API constants.
     65 static const char *kPlayerErrorState = "android.media.mediaplayer.errstate";
     66 static const char *kPlayerDataSourceType = "android.media.mediaplayer.dataSource";
     67 //
     68 static const char *kPlayerRebuffering = "android.media.mediaplayer.rebufferingMs";
     69 static const char *kPlayerRebufferingCount = "android.media.mediaplayer.rebuffers";
     70 static const char *kPlayerRebufferingAtExit = "android.media.mediaplayer.rebufferExit";
     71 
     72 
     73 NuPlayerDriver::NuPlayerDriver(pid_t pid)
     74     : mState(STATE_IDLE),
     75       mIsAsyncPrepare(false),
     76       mAsyncResult(UNKNOWN_ERROR),
     77       mSetSurfaceInProgress(false),
     78       mDurationUs(-1),
     79       mPositionUs(-1),
     80       mSeekInProgress(false),
     81       mPlayingTimeUs(0),
     82       mRebufferingTimeUs(0),
     83       mRebufferingEvents(0),
     84       mRebufferingAtExit(false),
     85       mLooper(new ALooper),
     86       mMediaClock(new MediaClock),
     87       mPlayer(new NuPlayer(pid, mMediaClock)),
     88       mPlayerFlags(0),
     89       mAnalyticsItem(NULL),
     90       mClientUid(-1),
     91       mAtEOS(false),
     92       mLooping(false),
     93       mAutoLoop(false) {
     94     ALOGD("NuPlayerDriver(%p) created, clientPid(%d)", this, pid);
     95     mLooper->setName("NuPlayerDriver Looper");
     96 
     97     mMediaClock->init();
     98 
     99     // set up an analytics record
    100     mAnalyticsItem = MediaAnalyticsItem::create(kKeyPlayer);
    101 
    102     mLooper->start(
    103             false, /* runOnCallingThread */
    104             true,  /* canCallJava */
    105             PRIORITY_AUDIO);
    106 
    107     mLooper->registerHandler(mPlayer);
    108 
    109     mPlayer->init(this);
    110 }
    111 
    112 NuPlayerDriver::~NuPlayerDriver() {
    113     ALOGV("~NuPlayerDriver(%p)", this);
    114     mLooper->stop();
    115 
    116     // finalize any pending metrics, usually a no-op.
    117     updateMetrics("destructor");
    118     logMetrics("destructor");
    119 
    120     if (mAnalyticsItem != NULL) {
    121         delete mAnalyticsItem;
    122         mAnalyticsItem = NULL;
    123     }
    124 }
    125 
    126 status_t NuPlayerDriver::initCheck() {
    127     return OK;
    128 }
    129 
    130 status_t NuPlayerDriver::setUID(uid_t uid) {
    131     mPlayer->setUID(uid);
    132     mClientUid = uid;
    133     if (mAnalyticsItem) {
    134         mAnalyticsItem->setUid(mClientUid);
    135     }
    136 
    137     return OK;
    138 }
    139 
    140 status_t NuPlayerDriver::setDataSource(
    141         const sp<IMediaHTTPService> &httpService,
    142         const char *url,
    143         const KeyedVector<String8, String8> *headers) {
    144     ALOGV("setDataSource(%p) url(%s)", this, uriDebugString(url, false).c_str());
    145     Mutex::Autolock autoLock(mLock);
    146 
    147     if (mState != STATE_IDLE) {
    148         return INVALID_OPERATION;
    149     }
    150 
    151     mState = STATE_SET_DATASOURCE_PENDING;
    152 
    153     mPlayer->setDataSourceAsync(httpService, url, headers);
    154 
    155     while (mState == STATE_SET_DATASOURCE_PENDING) {
    156         mCondition.wait(mLock);
    157     }
    158 
    159     return mAsyncResult;
    160 }
    161 
    162 status_t NuPlayerDriver::setDataSource(int fd, int64_t offset, int64_t length) {
    163     ALOGV("setDataSource(%p) file(%d)", this, fd);
    164     Mutex::Autolock autoLock(mLock);
    165 
    166     if (mState != STATE_IDLE) {
    167         return INVALID_OPERATION;
    168     }
    169 
    170     mState = STATE_SET_DATASOURCE_PENDING;
    171 
    172     mPlayer->setDataSourceAsync(fd, offset, length);
    173 
    174     while (mState == STATE_SET_DATASOURCE_PENDING) {
    175         mCondition.wait(mLock);
    176     }
    177 
    178     return mAsyncResult;
    179 }
    180 
    181 status_t NuPlayerDriver::setDataSource(const sp<IStreamSource> &source) {
    182     ALOGV("setDataSource(%p) stream source", this);
    183     Mutex::Autolock autoLock(mLock);
    184 
    185     if (mState != STATE_IDLE) {
    186         return INVALID_OPERATION;
    187     }
    188 
    189     mState = STATE_SET_DATASOURCE_PENDING;
    190 
    191     mPlayer->setDataSourceAsync(source);
    192 
    193     while (mState == STATE_SET_DATASOURCE_PENDING) {
    194         mCondition.wait(mLock);
    195     }
    196 
    197     return mAsyncResult;
    198 }
    199 
    200 status_t NuPlayerDriver::setDataSource(const sp<DataSource> &source) {
    201     ALOGV("setDataSource(%p) callback source", this);
    202     Mutex::Autolock autoLock(mLock);
    203 
    204     if (mState != STATE_IDLE) {
    205         return INVALID_OPERATION;
    206     }
    207 
    208     mState = STATE_SET_DATASOURCE_PENDING;
    209 
    210     mPlayer->setDataSourceAsync(source);
    211 
    212     while (mState == STATE_SET_DATASOURCE_PENDING) {
    213         mCondition.wait(mLock);
    214     }
    215 
    216     return mAsyncResult;
    217 }
    218 
    219 status_t NuPlayerDriver::setVideoSurfaceTexture(
    220         const sp<IGraphicBufferProducer> &bufferProducer) {
    221     ALOGV("setVideoSurfaceTexture(%p)", this);
    222     Mutex::Autolock autoLock(mLock);
    223 
    224     if (mSetSurfaceInProgress) {
    225         return INVALID_OPERATION;
    226     }
    227 
    228     switch (mState) {
    229         case STATE_SET_DATASOURCE_PENDING:
    230         case STATE_RESET_IN_PROGRESS:
    231             return INVALID_OPERATION;
    232 
    233         default:
    234             break;
    235     }
    236 
    237     mSetSurfaceInProgress = true;
    238 
    239     mPlayer->setVideoSurfaceTextureAsync(bufferProducer);
    240 
    241     while (mSetSurfaceInProgress) {
    242         mCondition.wait(mLock);
    243     }
    244 
    245     return OK;
    246 }
    247 
    248 status_t NuPlayerDriver::getBufferingSettings(BufferingSettings* buffering) {
    249     ALOGV("getBufferingSettings(%p)", this);
    250     {
    251         Mutex::Autolock autoLock(mLock);
    252         if (mState == STATE_IDLE) {
    253             return INVALID_OPERATION;
    254         }
    255     }
    256 
    257     return mPlayer->getBufferingSettings(buffering);
    258 }
    259 
    260 status_t NuPlayerDriver::setBufferingSettings(const BufferingSettings& buffering) {
    261     ALOGV("setBufferingSettings(%p)", this);
    262     {
    263         Mutex::Autolock autoLock(mLock);
    264         if (mState == STATE_IDLE) {
    265             return INVALID_OPERATION;
    266         }
    267     }
    268 
    269     return mPlayer->setBufferingSettings(buffering);
    270 }
    271 
    272 status_t NuPlayerDriver::prepare() {
    273     ALOGV("prepare(%p)", this);
    274     Mutex::Autolock autoLock(mLock);
    275     return prepare_l();
    276 }
    277 
    278 status_t NuPlayerDriver::prepare_l() {
    279     switch (mState) {
    280         case STATE_UNPREPARED:
    281             mState = STATE_PREPARING;
    282 
    283             // Make sure we're not posting any notifications, success or
    284             // failure information is only communicated through our result
    285             // code.
    286             mIsAsyncPrepare = false;
    287             mPlayer->prepareAsync();
    288             while (mState == STATE_PREPARING) {
    289                 mCondition.wait(mLock);
    290             }
    291             return (mState == STATE_PREPARED) ? OK : UNKNOWN_ERROR;
    292         case STATE_STOPPED:
    293             // this is really just paused. handle as seek to start
    294             mAtEOS = false;
    295             mState = STATE_STOPPED_AND_PREPARING;
    296             mIsAsyncPrepare = false;
    297             mPlayer->seekToAsync(0, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */,
    298                     true /* needNotify */);
    299             while (mState == STATE_STOPPED_AND_PREPARING) {
    300                 mCondition.wait(mLock);
    301             }
    302             return (mState == STATE_STOPPED_AND_PREPARED) ? OK : UNKNOWN_ERROR;
    303         default:
    304             return INVALID_OPERATION;
    305     };
    306 }
    307 
    308 status_t NuPlayerDriver::prepareAsync() {
    309     ALOGV("prepareAsync(%p)", this);
    310     Mutex::Autolock autoLock(mLock);
    311 
    312     switch (mState) {
    313         case STATE_UNPREPARED:
    314             mState = STATE_PREPARING;
    315             mIsAsyncPrepare = true;
    316             mPlayer->prepareAsync();
    317             return OK;
    318         case STATE_STOPPED:
    319             // this is really just paused. handle as seek to start
    320             mAtEOS = false;
    321             mState = STATE_STOPPED_AND_PREPARING;
    322             mIsAsyncPrepare = true;
    323             mPlayer->seekToAsync(0, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */,
    324                     true /* needNotify */);
    325             return OK;
    326         default:
    327             return INVALID_OPERATION;
    328     };
    329 }
    330 
    331 status_t NuPlayerDriver::start() {
    332     ALOGV("start(%p), state is %d, eos is %d", this, mState, mAtEOS);
    333     Mutex::Autolock autoLock(mLock);
    334     return start_l();
    335 }
    336 
    337 status_t NuPlayerDriver::start_l() {
    338     switch (mState) {
    339         case STATE_UNPREPARED:
    340         {
    341             status_t err = prepare_l();
    342 
    343             if (err != OK) {
    344                 return err;
    345             }
    346 
    347             CHECK_EQ(mState, STATE_PREPARED);
    348 
    349             FALLTHROUGH_INTENDED;
    350         }
    351 
    352         case STATE_PAUSED:
    353         case STATE_STOPPED_AND_PREPARED:
    354         case STATE_PREPARED:
    355         {
    356             mPlayer->start();
    357 
    358             FALLTHROUGH_INTENDED;
    359         }
    360 
    361         case STATE_RUNNING:
    362         {
    363             if (mAtEOS) {
    364                 mPlayer->seekToAsync(0);
    365                 mAtEOS = false;
    366                 mPositionUs = -1;
    367             }
    368             break;
    369         }
    370 
    371         default:
    372             return INVALID_OPERATION;
    373     }
    374 
    375     mState = STATE_RUNNING;
    376 
    377     return OK;
    378 }
    379 
    380 status_t NuPlayerDriver::stop() {
    381     ALOGD("stop(%p)", this);
    382     Mutex::Autolock autoLock(mLock);
    383 
    384     switch (mState) {
    385         case STATE_RUNNING:
    386             mPlayer->pause();
    387             FALLTHROUGH_INTENDED;
    388 
    389         case STATE_PAUSED:
    390             mState = STATE_STOPPED;
    391             notifyListener_l(MEDIA_STOPPED);
    392             break;
    393 
    394         case STATE_PREPARED:
    395         case STATE_STOPPED:
    396         case STATE_STOPPED_AND_PREPARING:
    397         case STATE_STOPPED_AND_PREPARED:
    398             mState = STATE_STOPPED;
    399             break;
    400 
    401         default:
    402             return INVALID_OPERATION;
    403     }
    404 
    405     return OK;
    406 }
    407 
    408 status_t NuPlayerDriver::pause() {
    409     ALOGD("pause(%p)", this);
    410     // The NuPlayerRenderer may get flushed if pause for long enough, e.g. the pause timeout tear
    411     // down for audio offload mode. If that happens, the NuPlayerRenderer will no longer know the
    412     // current position. So similar to seekTo, update |mPositionUs| to the pause position by calling
    413     // getCurrentPosition here.
    414     int unused;
    415     getCurrentPosition(&unused);
    416 
    417     Mutex::Autolock autoLock(mLock);
    418 
    419     switch (mState) {
    420         case STATE_PAUSED:
    421         case STATE_PREPARED:
    422             return OK;
    423 
    424         case STATE_RUNNING:
    425             mState = STATE_PAUSED;
    426             notifyListener_l(MEDIA_PAUSED);
    427             mPlayer->pause();
    428             break;
    429 
    430         default:
    431             return INVALID_OPERATION;
    432     }
    433 
    434     return OK;
    435 }
    436 
    437 bool NuPlayerDriver::isPlaying() {
    438     return mState == STATE_RUNNING && !mAtEOS;
    439 }
    440 
    441 status_t NuPlayerDriver::setPlaybackSettings(const AudioPlaybackRate &rate) {
    442     status_t err = mPlayer->setPlaybackSettings(rate);
    443     if (err == OK) {
    444         // try to update position
    445         int unused;
    446         getCurrentPosition(&unused);
    447         Mutex::Autolock autoLock(mLock);
    448         if (rate.mSpeed == 0.f && mState == STATE_RUNNING) {
    449             mState = STATE_PAUSED;
    450             notifyListener_l(MEDIA_PAUSED);
    451         } else if (rate.mSpeed != 0.f
    452                 && (mState == STATE_PAUSED
    453                     || mState == STATE_STOPPED_AND_PREPARED
    454                     || mState == STATE_PREPARED)) {
    455             err = start_l();
    456         }
    457     }
    458     return err;
    459 }
    460 
    461 status_t NuPlayerDriver::getPlaybackSettings(AudioPlaybackRate *rate) {
    462     return mPlayer->getPlaybackSettings(rate);
    463 }
    464 
    465 status_t NuPlayerDriver::setSyncSettings(const AVSyncSettings &sync, float videoFpsHint) {
    466     return mPlayer->setSyncSettings(sync, videoFpsHint);
    467 }
    468 
    469 status_t NuPlayerDriver::getSyncSettings(AVSyncSettings *sync, float *videoFps) {
    470     return mPlayer->getSyncSettings(sync, videoFps);
    471 }
    472 
    473 status_t NuPlayerDriver::seekTo(int msec, MediaPlayerSeekMode mode) {
    474     ALOGV("seekTo(%p) (%d ms, %d) at state %d", this, msec, mode, mState);
    475     Mutex::Autolock autoLock(mLock);
    476 
    477     int64_t seekTimeUs = msec * 1000LL;
    478 
    479     switch (mState) {
    480         case STATE_PREPARED:
    481         case STATE_STOPPED_AND_PREPARED:
    482         case STATE_PAUSED:
    483         case STATE_RUNNING:
    484         {
    485             mAtEOS = false;
    486             mSeekInProgress = true;
    487             // seeks can take a while, so we essentially paused
    488             notifyListener_l(MEDIA_PAUSED);
    489             mPlayer->seekToAsync(seekTimeUs, mode, true /* needNotify */);
    490             break;
    491         }
    492 
    493         default:
    494             return INVALID_OPERATION;
    495     }
    496 
    497     mPositionUs = seekTimeUs;
    498     return OK;
    499 }
    500 
    501 status_t NuPlayerDriver::getCurrentPosition(int *msec) {
    502     int64_t tempUs = 0;
    503     {
    504         Mutex::Autolock autoLock(mLock);
    505         if (mSeekInProgress || (mState == STATE_PAUSED && !mAtEOS)) {
    506             tempUs = (mPositionUs <= 0) ? 0 : mPositionUs;
    507             *msec = (int)divRound(tempUs, (int64_t)(1000));
    508             return OK;
    509         }
    510     }
    511 
    512     status_t ret = mPlayer->getCurrentPosition(&tempUs);
    513 
    514     Mutex::Autolock autoLock(mLock);
    515     // We need to check mSeekInProgress here because mPlayer->seekToAsync is an async call, which
    516     // means getCurrentPosition can be called before seek is completed. Iow, renderer may return a
    517     // position value that's different the seek to position.
    518     if (ret != OK) {
    519         tempUs = (mPositionUs <= 0) ? 0 : mPositionUs;
    520     } else {
    521         mPositionUs = tempUs;
    522     }
    523     *msec = (int)divRound(tempUs, (int64_t)(1000));
    524     return OK;
    525 }
    526 
    527 status_t NuPlayerDriver::getDuration(int *msec) {
    528     Mutex::Autolock autoLock(mLock);
    529 
    530     if (mDurationUs < 0) {
    531         return UNKNOWN_ERROR;
    532     }
    533 
    534     *msec = (mDurationUs + 500LL) / 1000;
    535 
    536     return OK;
    537 }
    538 
    539 void NuPlayerDriver::updateMetrics(const char *where) {
    540 
    541     if (where == NULL) {
    542         where = "unknown";
    543     }
    544     ALOGV("updateMetrics(%p) from %s at state %d", this, where, mState);
    545 
    546     // gather the final stats for this record
    547     Vector<sp<AMessage>> trackStats;
    548     mPlayer->getStats(&trackStats);
    549 
    550     if (trackStats.size() > 0) {
    551         for (size_t i = 0; i < trackStats.size(); ++i) {
    552             const sp<AMessage> &stats = trackStats.itemAt(i);
    553 
    554             AString mime;
    555             stats->findString("mime", &mime);
    556 
    557             AString name;
    558             stats->findString("component-name", &name);
    559 
    560             if (mime.startsWith("video/")) {
    561                 int32_t width, height;
    562                 mAnalyticsItem->setCString(kPlayerVMime, mime.c_str());
    563                 if (!name.empty()) {
    564                     mAnalyticsItem->setCString(kPlayerVCodec, name.c_str());
    565                 }
    566 
    567                 if (stats->findInt32("width", &width)
    568                         && stats->findInt32("height", &height)) {
    569                     mAnalyticsItem->setInt32(kPlayerWidth, width);
    570                     mAnalyticsItem->setInt32(kPlayerHeight, height);
    571                 }
    572 
    573                 int64_t numFramesTotal = 0;
    574                 int64_t numFramesDropped = 0;
    575                 stats->findInt64("frames-total", &numFramesTotal);
    576                 stats->findInt64("frames-dropped-output", &numFramesDropped);
    577 
    578                 mAnalyticsItem->setInt64(kPlayerFrames, numFramesTotal);
    579                 mAnalyticsItem->setInt64(kPlayerFramesDropped, numFramesDropped);
    580 
    581                 float frameRate = 0;
    582                 if (stats->findFloat("frame-rate-total", &frameRate)) {
    583                     mAnalyticsItem->setDouble(kPlayerFrameRate, (double) frameRate);
    584                 }
    585 
    586             } else if (mime.startsWith("audio/")) {
    587                 mAnalyticsItem->setCString(kPlayerAMime, mime.c_str());
    588                 if (!name.empty()) {
    589                     mAnalyticsItem->setCString(kPlayerACodec, name.c_str());
    590                 }
    591             }
    592         }
    593     }
    594 
    595     // always provide duration and playing time, even if they have 0/unknown values.
    596 
    597     // getDuration() uses mLock for mutex -- careful where we use it.
    598     int duration_ms = -1;
    599     getDuration(&duration_ms);
    600     mAnalyticsItem->setInt64(kPlayerDuration, duration_ms);
    601 
    602     mPlayer->updateInternalTimers();
    603 
    604     mAnalyticsItem->setInt64(kPlayerPlaying, (mPlayingTimeUs+500)/1000 );
    605 
    606     if (mRebufferingEvents != 0) {
    607         mAnalyticsItem->setInt64(kPlayerRebuffering, (mRebufferingTimeUs+500)/1000 );
    608         mAnalyticsItem->setInt32(kPlayerRebufferingCount, mRebufferingEvents);
    609         mAnalyticsItem->setInt32(kPlayerRebufferingAtExit, mRebufferingAtExit);
    610 
    611     }
    612 
    613     mAnalyticsItem->setCString(kPlayerDataSourceType, mPlayer->getDataSourceType());
    614 }
    615 
    616 
    617 void NuPlayerDriver::logMetrics(const char *where) {
    618     if (where == NULL) {
    619         where = "unknown";
    620     }
    621     ALOGV("logMetrics(%p) from %s at state %d", this, where, mState);
    622 
    623     if (mAnalyticsItem == NULL || mAnalyticsItem->isEnabled() == false) {
    624         return;
    625     }
    626 
    627     // log only non-empty records
    628     // we always updateMetrics() before we get here
    629     // and that always injects 3 fields (duration, playing time, and
    630     // datasource) into the record.
    631     // So the canonical "empty" record has 3 elements in it.
    632     if (mAnalyticsItem->count() > 3) {
    633 
    634         mAnalyticsItem->selfrecord();
    635 
    636         // re-init in case we prepare() and start() again.
    637         delete mAnalyticsItem ;
    638         mAnalyticsItem = MediaAnalyticsItem::create(kKeyPlayer);
    639         if (mAnalyticsItem) {
    640             mAnalyticsItem->setUid(mClientUid);
    641         }
    642     } else {
    643         ALOGV("nothing to record (only %d fields)", mAnalyticsItem->count());
    644     }
    645 }
    646 
    647 status_t NuPlayerDriver::reset() {
    648     ALOGD("reset(%p) at state %d", this, mState);
    649 
    650     updateMetrics("reset");
    651     logMetrics("reset");
    652 
    653     Mutex::Autolock autoLock(mLock);
    654 
    655     switch (mState) {
    656         case STATE_IDLE:
    657             return OK;
    658 
    659         case STATE_SET_DATASOURCE_PENDING:
    660         case STATE_RESET_IN_PROGRESS:
    661             return INVALID_OPERATION;
    662 
    663         case STATE_PREPARING:
    664         {
    665             CHECK(mIsAsyncPrepare);
    666 
    667             notifyListener_l(MEDIA_PREPARED);
    668             break;
    669         }
    670 
    671         default:
    672             break;
    673     }
    674 
    675     if (mState != STATE_STOPPED) {
    676         notifyListener_l(MEDIA_STOPPED);
    677     }
    678 
    679     if (property_get_bool("persist.debug.sf.stats", false)) {
    680         Vector<String16> args;
    681         dump(-1, args);
    682     }
    683 
    684     mState = STATE_RESET_IN_PROGRESS;
    685     mPlayer->resetAsync();
    686 
    687     while (mState == STATE_RESET_IN_PROGRESS) {
    688         mCondition.wait(mLock);
    689     }
    690 
    691     mDurationUs = -1;
    692     mPositionUs = -1;
    693     mLooping = false;
    694     mPlayingTimeUs = 0;
    695     mRebufferingTimeUs = 0;
    696     mRebufferingEvents = 0;
    697     mRebufferingAtExit = false;
    698 
    699     return OK;
    700 }
    701 
    702 status_t NuPlayerDriver::notifyAt(int64_t mediaTimeUs) {
    703     ALOGV("notifyAt(%p), time:%lld", this, (long long)mediaTimeUs);
    704     return mPlayer->notifyAt(mediaTimeUs);
    705 }
    706 
    707 status_t NuPlayerDriver::setLooping(int loop) {
    708     mLooping = loop != 0;
    709     return OK;
    710 }
    711 
    712 player_type NuPlayerDriver::playerType() {
    713     return NU_PLAYER;
    714 }
    715 
    716 status_t NuPlayerDriver::invoke(const Parcel &request, Parcel *reply) {
    717     if (reply == NULL) {
    718         ALOGE("reply is a NULL pointer");
    719         return BAD_VALUE;
    720     }
    721 
    722     int32_t methodId;
    723     status_t ret = request.readInt32(&methodId);
    724     if (ret != OK) {
    725         ALOGE("Failed to retrieve the requested method to invoke");
    726         return ret;
    727     }
    728 
    729     switch (methodId) {
    730         case INVOKE_ID_SET_VIDEO_SCALING_MODE:
    731         {
    732             int mode = request.readInt32();
    733             return mPlayer->setVideoScalingMode(mode);
    734         }
    735 
    736         case INVOKE_ID_GET_TRACK_INFO:
    737         {
    738             return mPlayer->getTrackInfo(reply);
    739         }
    740 
    741         case INVOKE_ID_SELECT_TRACK:
    742         {
    743             int trackIndex = request.readInt32();
    744             int msec = 0;
    745             // getCurrentPosition should always return OK
    746             getCurrentPosition(&msec);
    747             return mPlayer->selectTrack(trackIndex, true /* select */, msec * 1000LL);
    748         }
    749 
    750         case INVOKE_ID_UNSELECT_TRACK:
    751         {
    752             int trackIndex = request.readInt32();
    753             return mPlayer->selectTrack(trackIndex, false /* select */, 0xdeadbeef /* not used */);
    754         }
    755 
    756         case INVOKE_ID_GET_SELECTED_TRACK:
    757         {
    758             int32_t type = request.readInt32();
    759             return mPlayer->getSelectedTrack(type, reply);
    760         }
    761 
    762         default:
    763         {
    764             return INVALID_OPERATION;
    765         }
    766     }
    767 }
    768 
    769 void NuPlayerDriver::setAudioSink(const sp<AudioSink> &audioSink) {
    770     mPlayer->setAudioSink(audioSink);
    771     mAudioSink = audioSink;
    772 }
    773 
    774 status_t NuPlayerDriver::setParameter(
    775         int /* key */, const Parcel & /* request */) {
    776     return INVALID_OPERATION;
    777 }
    778 
    779 status_t NuPlayerDriver::getParameter(int key, Parcel *reply) {
    780 
    781     if (key == FOURCC('m','t','r','X') && mAnalyticsItem != NULL) {
    782         // mtrX -- a play on 'metrics' (not matrix)
    783         // gather current info all together, parcel it, and send it back
    784         updateMetrics("api");
    785         mAnalyticsItem->writeToParcel(reply);
    786         return OK;
    787     }
    788 
    789     return INVALID_OPERATION;
    790 }
    791 
    792 status_t NuPlayerDriver::getMetadata(
    793         const media::Metadata::Filter& /* ids */, Parcel *records) {
    794     Mutex::Autolock autoLock(mLock);
    795 
    796     using media::Metadata;
    797 
    798     Metadata meta(records);
    799 
    800     meta.appendBool(
    801             Metadata::kPauseAvailable,
    802             mPlayerFlags & NuPlayer::Source::FLAG_CAN_PAUSE);
    803 
    804     meta.appendBool(
    805             Metadata::kSeekBackwardAvailable,
    806             mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK_BACKWARD);
    807 
    808     meta.appendBool(
    809             Metadata::kSeekForwardAvailable,
    810             mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK_FORWARD);
    811 
    812     meta.appendBool(
    813             Metadata::kSeekAvailable,
    814             mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK);
    815 
    816     return OK;
    817 }
    818 
    819 void NuPlayerDriver::notifyResetComplete() {
    820     ALOGD("notifyResetComplete(%p)", this);
    821     Mutex::Autolock autoLock(mLock);
    822 
    823     CHECK_EQ(mState, STATE_RESET_IN_PROGRESS);
    824     mState = STATE_IDLE;
    825     mCondition.broadcast();
    826 }
    827 
    828 void NuPlayerDriver::notifySetSurfaceComplete() {
    829     ALOGV("notifySetSurfaceComplete(%p)", this);
    830     Mutex::Autolock autoLock(mLock);
    831 
    832     CHECK(mSetSurfaceInProgress);
    833     mSetSurfaceInProgress = false;
    834 
    835     mCondition.broadcast();
    836 }
    837 
    838 void NuPlayerDriver::notifyDuration(int64_t durationUs) {
    839     Mutex::Autolock autoLock(mLock);
    840     mDurationUs = durationUs;
    841 }
    842 
    843 void NuPlayerDriver::notifyMorePlayingTimeUs(int64_t playingUs) {
    844     Mutex::Autolock autoLock(mLock);
    845     mPlayingTimeUs += playingUs;
    846 }
    847 
    848 void NuPlayerDriver::notifyMoreRebufferingTimeUs(int64_t rebufferingUs) {
    849     Mutex::Autolock autoLock(mLock);
    850     mRebufferingTimeUs += rebufferingUs;
    851     mRebufferingEvents++;
    852 }
    853 
    854 void NuPlayerDriver::notifyRebufferingWhenExit(bool status) {
    855     Mutex::Autolock autoLock(mLock);
    856     mRebufferingAtExit = status;
    857 }
    858 
    859 void NuPlayerDriver::notifySeekComplete() {
    860     ALOGV("notifySeekComplete(%p)", this);
    861     Mutex::Autolock autoLock(mLock);
    862     mSeekInProgress = false;
    863     notifySeekComplete_l();
    864 }
    865 
    866 void NuPlayerDriver::notifySeekComplete_l() {
    867     bool wasSeeking = true;
    868     if (mState == STATE_STOPPED_AND_PREPARING) {
    869         wasSeeking = false;
    870         mState = STATE_STOPPED_AND_PREPARED;
    871         mCondition.broadcast();
    872         if (!mIsAsyncPrepare) {
    873             // if we are preparing synchronously, no need to notify listener
    874             return;
    875         }
    876     } else if (mState == STATE_STOPPED) {
    877         // no need to notify listener
    878         return;
    879     }
    880     notifyListener_l(wasSeeking ? MEDIA_SEEK_COMPLETE : MEDIA_PREPARED);
    881 }
    882 
    883 status_t NuPlayerDriver::dump(
    884         int fd, const Vector<String16> & /* args */) const {
    885 
    886     Vector<sp<AMessage> > trackStats;
    887     mPlayer->getStats(&trackStats);
    888 
    889     AString logString(" NuPlayer\n");
    890     char buf[256] = {0};
    891 
    892     bool locked = false;
    893     for (int i = 0; i < kDumpLockRetries; ++i) {
    894         if (mLock.tryLock() == NO_ERROR) {
    895             locked = true;
    896             break;
    897         }
    898         usleep(kDumpLockSleepUs);
    899     }
    900 
    901     if (locked) {
    902         snprintf(buf, sizeof(buf), "  state(%d), atEOS(%d), looping(%d), autoLoop(%d)\n",
    903                 mState, mAtEOS, mLooping, mAutoLoop);
    904         mLock.unlock();
    905     } else {
    906         snprintf(buf, sizeof(buf), "  NPD(%p) lock is taken\n", this);
    907     }
    908     logString.append(buf);
    909 
    910     for (size_t i = 0; i < trackStats.size(); ++i) {
    911         const sp<AMessage> &stats = trackStats.itemAt(i);
    912 
    913         AString mime;
    914         if (stats->findString("mime", &mime)) {
    915             snprintf(buf, sizeof(buf), "  mime(%s)\n", mime.c_str());
    916             logString.append(buf);
    917         }
    918 
    919         AString name;
    920         if (stats->findString("component-name", &name)) {
    921             snprintf(buf, sizeof(buf), "    decoder(%s)\n", name.c_str());
    922             logString.append(buf);
    923         }
    924 
    925         if (mime.startsWith("video/")) {
    926             int32_t width, height;
    927             if (stats->findInt32("width", &width)
    928                     && stats->findInt32("height", &height)) {
    929                 snprintf(buf, sizeof(buf), "    resolution(%d x %d)\n", width, height);
    930                 logString.append(buf);
    931             }
    932 
    933             int64_t numFramesTotal = 0;
    934             int64_t numFramesDropped = 0;
    935 
    936             stats->findInt64("frames-total", &numFramesTotal);
    937             stats->findInt64("frames-dropped-output", &numFramesDropped);
    938             snprintf(buf, sizeof(buf), "    numFramesTotal(%lld), numFramesDropped(%lld), "
    939                      "percentageDropped(%.2f%%)\n",
    940                      (long long)numFramesTotal,
    941                      (long long)numFramesDropped,
    942                      numFramesTotal == 0
    943                             ? 0.0 : (double)(numFramesDropped * 100) / numFramesTotal);
    944             logString.append(buf);
    945         }
    946     }
    947 
    948     ALOGI("%s", logString.c_str());
    949 
    950     if (fd >= 0) {
    951         FILE *out = fdopen(dup(fd), "w");
    952         fprintf(out, "%s", logString.c_str());
    953         fclose(out);
    954         out = NULL;
    955     }
    956 
    957     return OK;
    958 }
    959 
    960 void NuPlayerDriver::notifyListener(
    961         int msg, int ext1, int ext2, const Parcel *in) {
    962     Mutex::Autolock autoLock(mLock);
    963     notifyListener_l(msg, ext1, ext2, in);
    964 }
    965 
    966 void NuPlayerDriver::notifyListener_l(
    967         int msg, int ext1, int ext2, const Parcel *in) {
    968     ALOGV("notifyListener_l(%p), (%d, %d, %d, %d), loop setting(%d, %d)",
    969             this, msg, ext1, ext2, (in == NULL ? -1 : (int)in->dataSize()), mAutoLoop, mLooping);
    970     switch (msg) {
    971         case MEDIA_PLAYBACK_COMPLETE:
    972         {
    973             if (mState != STATE_RESET_IN_PROGRESS) {
    974                 if (mAutoLoop) {
    975                     audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
    976                     if (mAudioSink != NULL) {
    977                         streamType = mAudioSink->getAudioStreamType();
    978                     }
    979                     if (streamType == AUDIO_STREAM_NOTIFICATION) {
    980                         ALOGW("disabling auto-loop for notification");
    981                         mAutoLoop = false;
    982                     }
    983                 }
    984                 if (mLooping || mAutoLoop) {
    985                     mPlayer->seekToAsync(0);
    986                     if (mAudioSink != NULL) {
    987                         // The renderer has stopped the sink at the end in order to play out
    988                         // the last little bit of audio. If we're looping, we need to restart it.
    989                         mAudioSink->start();
    990                     }
    991                     // don't send completion event when looping
    992                     return;
    993                 }
    994                 if (property_get_bool("persist.debug.sf.stats", false)) {
    995                     Vector<String16> args;
    996                     dump(-1, args);
    997                 }
    998                 mPlayer->pause();
    999                 mState = STATE_PAUSED;
   1000             }
   1001             FALLTHROUGH_INTENDED;
   1002         }
   1003 
   1004         case MEDIA_ERROR:
   1005         {
   1006             // when we have an error, add it to the analytics for this playback.
   1007             // ext1 is our primary 'error type' value. Only add ext2 when non-zero.
   1008             // [test against msg is due to fall through from previous switch value]
   1009             if (msg == MEDIA_ERROR && mAnalyticsItem != NULL) {
   1010                 mAnalyticsItem->setInt32(kPlayerError, ext1);
   1011                 if (ext2 != 0) {
   1012                     mAnalyticsItem->setInt32(kPlayerErrorCode, ext2);
   1013                 }
   1014                 mAnalyticsItem->setCString(kPlayerErrorState, stateString(mState).c_str());
   1015             }
   1016             mAtEOS = true;
   1017             break;
   1018         }
   1019 
   1020         default:
   1021             break;
   1022     }
   1023 
   1024     mLock.unlock();
   1025     sendEvent(msg, ext1, ext2, in);
   1026     mLock.lock();
   1027 }
   1028 
   1029 void NuPlayerDriver::notifySetDataSourceCompleted(status_t err) {
   1030     Mutex::Autolock autoLock(mLock);
   1031 
   1032     CHECK_EQ(mState, STATE_SET_DATASOURCE_PENDING);
   1033 
   1034     mAsyncResult = err;
   1035     mState = (err == OK) ? STATE_UNPREPARED : STATE_IDLE;
   1036     mCondition.broadcast();
   1037 }
   1038 
   1039 void NuPlayerDriver::notifyPrepareCompleted(status_t err) {
   1040     ALOGV("notifyPrepareCompleted %d", err);
   1041 
   1042     Mutex::Autolock autoLock(mLock);
   1043 
   1044     if (mState != STATE_PREPARING) {
   1045         // We were preparing asynchronously when the client called
   1046         // reset(), we sent a premature "prepared" notification and
   1047         // then initiated the reset. This notification is stale.
   1048         CHECK(mState == STATE_RESET_IN_PROGRESS || mState == STATE_IDLE);
   1049         return;
   1050     }
   1051 
   1052     CHECK_EQ(mState, STATE_PREPARING);
   1053 
   1054     mAsyncResult = err;
   1055 
   1056     if (err == OK) {
   1057         // update state before notifying client, so that if client calls back into NuPlayerDriver
   1058         // in response, NuPlayerDriver has the right state
   1059         mState = STATE_PREPARED;
   1060         if (mIsAsyncPrepare) {
   1061             notifyListener_l(MEDIA_PREPARED);
   1062         }
   1063     } else {
   1064         mState = STATE_UNPREPARED;
   1065         if (mIsAsyncPrepare) {
   1066             notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
   1067         }
   1068     }
   1069 
   1070     sp<MetaData> meta = mPlayer->getFileMeta();
   1071     int32_t loop;
   1072     if (meta != NULL
   1073             && meta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {
   1074         mAutoLoop = true;
   1075     }
   1076 
   1077     mCondition.broadcast();
   1078 }
   1079 
   1080 void NuPlayerDriver::notifyFlagsChanged(uint32_t flags) {
   1081     Mutex::Autolock autoLock(mLock);
   1082 
   1083     mPlayerFlags = flags;
   1084 }
   1085 
   1086 // Modular DRM
   1087 status_t NuPlayerDriver::prepareDrm(const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId)
   1088 {
   1089     ALOGV("prepareDrm(%p) state: %d", this, mState);
   1090 
   1091     // leaving the state verification for mediaplayer.cpp
   1092     status_t ret = mPlayer->prepareDrm(uuid, drmSessionId);
   1093 
   1094     ALOGV("prepareDrm ret: %d", ret);
   1095 
   1096     return ret;
   1097 }
   1098 
   1099 status_t NuPlayerDriver::releaseDrm()
   1100 {
   1101     ALOGV("releaseDrm(%p) state: %d", this, mState);
   1102 
   1103     // leaving the state verification for mediaplayer.cpp
   1104     status_t ret = mPlayer->releaseDrm();
   1105 
   1106     ALOGV("releaseDrm ret: %d", ret);
   1107 
   1108     return ret;
   1109 }
   1110 
   1111 std::string NuPlayerDriver::stateString(State state) {
   1112     const char *rval = NULL;
   1113     char rawbuffer[16];  // allows "%d"
   1114 
   1115     switch (state) {
   1116         case STATE_IDLE: rval = "IDLE"; break;
   1117         case STATE_SET_DATASOURCE_PENDING: rval = "SET_DATASOURCE_PENDING"; break;
   1118         case STATE_UNPREPARED: rval = "UNPREPARED"; break;
   1119         case STATE_PREPARING: rval = "PREPARING"; break;
   1120         case STATE_PREPARED: rval = "PREPARED"; break;
   1121         case STATE_RUNNING: rval = "RUNNING"; break;
   1122         case STATE_PAUSED: rval = "PAUSED"; break;
   1123         case STATE_RESET_IN_PROGRESS: rval = "RESET_IN_PROGRESS"; break;
   1124         case STATE_STOPPED: rval = "STOPPED"; break;
   1125         case STATE_STOPPED_AND_PREPARING: rval = "STOPPED_AND_PREPARING"; break;
   1126         case STATE_STOPPED_AND_PREPARED: rval = "STOPPED_AND_PREPARED"; break;
   1127         default:
   1128             // yes, this buffer is shared and vulnerable to races
   1129             snprintf(rawbuffer, sizeof(rawbuffer), "%d", state);
   1130             rval = rawbuffer;
   1131             break;
   1132     }
   1133 
   1134     return rval;
   1135 }
   1136 
   1137 }  // namespace android
   1138