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