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