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 
     22 #include "NuPlayerDriver.h"
     23 
     24 #include "NuPlayer.h"
     25 #include "NuPlayerSource.h"
     26 
     27 #include <media/stagefright/foundation/ADebug.h>
     28 #include <media/stagefright/foundation/ALooper.h>
     29 #include <media/stagefright/foundation/AUtils.h>
     30 #include <media/stagefright/MetaData.h>
     31 #include <media/stagefright/Utils.h>
     32 
     33 namespace android {
     34 
     35 NuPlayerDriver::NuPlayerDriver()
     36     : mState(STATE_IDLE),
     37       mIsAsyncPrepare(false),
     38       mAsyncResult(UNKNOWN_ERROR),
     39       mSetSurfaceInProgress(false),
     40       mDurationUs(-1),
     41       mPositionUs(-1),
     42       mSeekInProgress(false),
     43       mLooper(new ALooper),
     44       mPlayerFlags(0),
     45       mAtEOS(false),
     46       mLooping(false),
     47       mAutoLoop(false),
     48       mStartupSeekTimeUs(-1) {
     49     ALOGV("NuPlayerDriver(%p)", this);
     50     mLooper->setName("NuPlayerDriver Looper");
     51 
     52     mLooper->start(
     53             false, /* runOnCallingThread */
     54             true,  /* canCallJava */
     55             PRIORITY_AUDIO);
     56 
     57     mPlayer = new NuPlayer;
     58     mLooper->registerHandler(mPlayer);
     59 
     60     mPlayer->setDriver(this);
     61 }
     62 
     63 NuPlayerDriver::~NuPlayerDriver() {
     64     ALOGV("~NuPlayerDriver(%p)", this);
     65     mLooper->stop();
     66 }
     67 
     68 status_t NuPlayerDriver::initCheck() {
     69     return OK;
     70 }
     71 
     72 status_t NuPlayerDriver::setUID(uid_t uid) {
     73     mPlayer->setUID(uid);
     74 
     75     return OK;
     76 }
     77 
     78 status_t NuPlayerDriver::setDataSource(
     79         const sp<IMediaHTTPService> &httpService,
     80         const char *url,
     81         const KeyedVector<String8, String8> *headers) {
     82     ALOGV("setDataSource(%p) url(%s)", this, uriDebugString(url, false).c_str());
     83     Mutex::Autolock autoLock(mLock);
     84 
     85     if (mState != STATE_IDLE) {
     86         return INVALID_OPERATION;
     87     }
     88 
     89     mState = STATE_SET_DATASOURCE_PENDING;
     90 
     91     mPlayer->setDataSourceAsync(httpService, url, headers);
     92 
     93     while (mState == STATE_SET_DATASOURCE_PENDING) {
     94         mCondition.wait(mLock);
     95     }
     96 
     97     return mAsyncResult;
     98 }
     99 
    100 status_t NuPlayerDriver::setDataSource(int fd, int64_t offset, int64_t length) {
    101     ALOGV("setDataSource(%p) file(%d)", this, fd);
    102     Mutex::Autolock autoLock(mLock);
    103 
    104     if (mState != STATE_IDLE) {
    105         return INVALID_OPERATION;
    106     }
    107 
    108     mState = STATE_SET_DATASOURCE_PENDING;
    109 
    110     mPlayer->setDataSourceAsync(fd, offset, length);
    111 
    112     while (mState == STATE_SET_DATASOURCE_PENDING) {
    113         mCondition.wait(mLock);
    114     }
    115 
    116     return mAsyncResult;
    117 }
    118 
    119 status_t NuPlayerDriver::setDataSource(const sp<IStreamSource> &source) {
    120     ALOGV("setDataSource(%p) stream source", this);
    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(source);
    130 
    131     while (mState == STATE_SET_DATASOURCE_PENDING) {
    132         mCondition.wait(mLock);
    133     }
    134 
    135     return mAsyncResult;
    136 }
    137 
    138 status_t NuPlayerDriver::setVideoSurfaceTexture(
    139         const sp<IGraphicBufferProducer> &bufferProducer) {
    140     ALOGV("setVideoSurfaceTexture(%p)", this);
    141     Mutex::Autolock autoLock(mLock);
    142 
    143     if (mSetSurfaceInProgress) {
    144         return INVALID_OPERATION;
    145     }
    146 
    147     switch (mState) {
    148         case STATE_SET_DATASOURCE_PENDING:
    149         case STATE_RESET_IN_PROGRESS:
    150             return INVALID_OPERATION;
    151 
    152         default:
    153             break;
    154     }
    155 
    156     mSetSurfaceInProgress = true;
    157 
    158     mPlayer->setVideoSurfaceTextureAsync(bufferProducer);
    159 
    160     while (mSetSurfaceInProgress) {
    161         mCondition.wait(mLock);
    162     }
    163 
    164     return OK;
    165 }
    166 
    167 status_t NuPlayerDriver::prepare() {
    168     ALOGV("prepare(%p)", this);
    169     Mutex::Autolock autoLock(mLock);
    170     return prepare_l();
    171 }
    172 
    173 status_t NuPlayerDriver::prepare_l() {
    174     switch (mState) {
    175         case STATE_UNPREPARED:
    176             mState = STATE_PREPARING;
    177 
    178             // Make sure we're not posting any notifications, success or
    179             // failure information is only communicated through our result
    180             // code.
    181             mIsAsyncPrepare = false;
    182             mPlayer->prepareAsync();
    183             while (mState == STATE_PREPARING) {
    184                 mCondition.wait(mLock);
    185             }
    186             return (mState == STATE_PREPARED) ? OK : UNKNOWN_ERROR;
    187         case STATE_STOPPED:
    188             // this is really just paused. handle as seek to start
    189             mAtEOS = false;
    190             mState = STATE_STOPPED_AND_PREPARING;
    191             mIsAsyncPrepare = false;
    192             mPlayer->seekToAsync(0, true /* needNotify */);
    193             while (mState == STATE_STOPPED_AND_PREPARING) {
    194                 mCondition.wait(mLock);
    195             }
    196             return (mState == STATE_STOPPED_AND_PREPARED) ? OK : UNKNOWN_ERROR;
    197         default:
    198             return INVALID_OPERATION;
    199     };
    200 }
    201 
    202 status_t NuPlayerDriver::prepareAsync() {
    203     ALOGV("prepareAsync(%p)", this);
    204     Mutex::Autolock autoLock(mLock);
    205 
    206     switch (mState) {
    207         case STATE_UNPREPARED:
    208             mState = STATE_PREPARING;
    209             mIsAsyncPrepare = true;
    210             mPlayer->prepareAsync();
    211             return OK;
    212         case STATE_STOPPED:
    213             // this is really just paused. handle as seek to start
    214             mAtEOS = false;
    215             mState = STATE_STOPPED_AND_PREPARING;
    216             mIsAsyncPrepare = true;
    217             mPlayer->seekToAsync(0, true /* needNotify */);
    218             return OK;
    219         default:
    220             return INVALID_OPERATION;
    221     };
    222 }
    223 
    224 status_t NuPlayerDriver::start() {
    225     ALOGD("start(%p)", this);
    226     Mutex::Autolock autoLock(mLock);
    227 
    228     switch (mState) {
    229         case STATE_UNPREPARED:
    230         {
    231             status_t err = prepare_l();
    232 
    233             if (err != OK) {
    234                 return err;
    235             }
    236 
    237             CHECK_EQ(mState, STATE_PREPARED);
    238 
    239             // fall through
    240         }
    241 
    242         case STATE_PREPARED:
    243         {
    244             mAtEOS = false;
    245             mPlayer->start();
    246 
    247             if (mStartupSeekTimeUs >= 0) {
    248                 if (mStartupSeekTimeUs > 0) {
    249                     mPlayer->seekToAsync(mStartupSeekTimeUs);
    250                 }
    251 
    252                 mStartupSeekTimeUs = -1;
    253             }
    254             break;
    255         }
    256 
    257         case STATE_RUNNING:
    258         {
    259             if (mAtEOS) {
    260                 mPlayer->seekToAsync(0);
    261                 mAtEOS = false;
    262                 mPositionUs = -1;
    263             }
    264             break;
    265         }
    266 
    267         case STATE_PAUSED:
    268         case STATE_STOPPED_AND_PREPARED:
    269         {
    270             if (mAtEOS) {
    271                 mPlayer->seekToAsync(0);
    272                 mAtEOS = false;
    273                 mPlayer->resume();
    274                 mPositionUs = -1;
    275             } else {
    276                 mPlayer->resume();
    277             }
    278             break;
    279         }
    280 
    281         default:
    282             return INVALID_OPERATION;
    283     }
    284 
    285     mState = STATE_RUNNING;
    286 
    287     return OK;
    288 }
    289 
    290 status_t NuPlayerDriver::stop() {
    291     ALOGD("stop(%p)", this);
    292     Mutex::Autolock autoLock(mLock);
    293 
    294     switch (mState) {
    295         case STATE_RUNNING:
    296             mPlayer->pause();
    297             // fall through
    298 
    299         case STATE_PAUSED:
    300             mState = STATE_STOPPED;
    301             notifyListener_l(MEDIA_STOPPED);
    302             break;
    303 
    304         case STATE_PREPARED:
    305         case STATE_STOPPED:
    306         case STATE_STOPPED_AND_PREPARING:
    307         case STATE_STOPPED_AND_PREPARED:
    308             mState = STATE_STOPPED;
    309             break;
    310 
    311         default:
    312             return INVALID_OPERATION;
    313     }
    314 
    315     return OK;
    316 }
    317 
    318 status_t NuPlayerDriver::pause() {
    319     Mutex::Autolock autoLock(mLock);
    320 
    321     switch (mState) {
    322         case STATE_PAUSED:
    323         case STATE_PREPARED:
    324             return OK;
    325 
    326         case STATE_RUNNING:
    327             mState = STATE_PAUSED;
    328             notifyListener_l(MEDIA_PAUSED);
    329             mPlayer->pause();
    330             break;
    331 
    332         default:
    333             return INVALID_OPERATION;
    334     }
    335 
    336     return OK;
    337 }
    338 
    339 bool NuPlayerDriver::isPlaying() {
    340     return mState == STATE_RUNNING && !mAtEOS;
    341 }
    342 
    343 status_t NuPlayerDriver::seekTo(int msec) {
    344     ALOGD("seekTo(%p) %d ms", this, msec);
    345     Mutex::Autolock autoLock(mLock);
    346 
    347     int64_t seekTimeUs = msec * 1000ll;
    348 
    349     switch (mState) {
    350         case STATE_PREPARED:
    351         {
    352             mStartupSeekTimeUs = seekTimeUs;
    353             // pretend that the seek completed. It will actually happen when starting playback.
    354             // TODO: actually perform the seek here, so the player is ready to go at the new
    355             // location
    356             notifySeekComplete_l();
    357             break;
    358         }
    359 
    360         case STATE_RUNNING:
    361         case STATE_PAUSED:
    362         {
    363             mAtEOS = false;
    364             mSeekInProgress = true;
    365             // seeks can take a while, so we essentially paused
    366             notifyListener_l(MEDIA_PAUSED);
    367             mPlayer->seekToAsync(seekTimeUs, true /* needNotify */);
    368             break;
    369         }
    370 
    371         default:
    372             return INVALID_OPERATION;
    373     }
    374 
    375     mPositionUs = seekTimeUs;
    376     return OK;
    377 }
    378 
    379 status_t NuPlayerDriver::getCurrentPosition(int *msec) {
    380     int64_t tempUs = 0;
    381     status_t ret = mPlayer->getCurrentPosition(&tempUs);
    382 
    383     Mutex::Autolock autoLock(mLock);
    384     // We need to check mSeekInProgress here because mPlayer->seekToAsync is an async call, which
    385     // means getCurrentPosition can be called before seek is completed. Iow, renderer may return a
    386     // position value that's different the seek to position.
    387     if (ret != OK || mSeekInProgress) {
    388         tempUs = (mPositionUs <= 0) ? 0 : mPositionUs;
    389     } else {
    390         mPositionUs = tempUs;
    391     }
    392     *msec = (int)divRound(tempUs, (int64_t)(1000));
    393     return OK;
    394 }
    395 
    396 status_t NuPlayerDriver::getDuration(int *msec) {
    397     Mutex::Autolock autoLock(mLock);
    398 
    399     if (mDurationUs < 0) {
    400         return UNKNOWN_ERROR;
    401     }
    402 
    403     *msec = (mDurationUs + 500ll) / 1000;
    404 
    405     return OK;
    406 }
    407 
    408 status_t NuPlayerDriver::reset() {
    409     ALOGD("reset(%p)", this);
    410     Mutex::Autolock autoLock(mLock);
    411 
    412     switch (mState) {
    413         case STATE_IDLE:
    414             return OK;
    415 
    416         case STATE_SET_DATASOURCE_PENDING:
    417         case STATE_RESET_IN_PROGRESS:
    418             return INVALID_OPERATION;
    419 
    420         case STATE_PREPARING:
    421         {
    422             CHECK(mIsAsyncPrepare);
    423 
    424             notifyListener_l(MEDIA_PREPARED);
    425             break;
    426         }
    427 
    428         default:
    429             break;
    430     }
    431 
    432     if (mState != STATE_STOPPED) {
    433         notifyListener_l(MEDIA_STOPPED);
    434     }
    435 
    436     mState = STATE_RESET_IN_PROGRESS;
    437     mPlayer->resetAsync();
    438 
    439     while (mState == STATE_RESET_IN_PROGRESS) {
    440         mCondition.wait(mLock);
    441     }
    442 
    443     mDurationUs = -1;
    444     mPositionUs = -1;
    445     mStartupSeekTimeUs = -1;
    446     mLooping = false;
    447 
    448     return OK;
    449 }
    450 
    451 status_t NuPlayerDriver::setLooping(int loop) {
    452     mLooping = loop != 0;
    453     return OK;
    454 }
    455 
    456 player_type NuPlayerDriver::playerType() {
    457     return NU_PLAYER;
    458 }
    459 
    460 status_t NuPlayerDriver::invoke(const Parcel &request, Parcel *reply) {
    461     if (reply == NULL) {
    462         ALOGE("reply is a NULL pointer");
    463         return BAD_VALUE;
    464     }
    465 
    466     int32_t methodId;
    467     status_t ret = request.readInt32(&methodId);
    468     if (ret != OK) {
    469         ALOGE("Failed to retrieve the requested method to invoke");
    470         return ret;
    471     }
    472 
    473     switch (methodId) {
    474         case INVOKE_ID_SET_VIDEO_SCALING_MODE:
    475         {
    476             int mode = request.readInt32();
    477             return mPlayer->setVideoScalingMode(mode);
    478         }
    479 
    480         case INVOKE_ID_GET_TRACK_INFO:
    481         {
    482             return mPlayer->getTrackInfo(reply);
    483         }
    484 
    485         case INVOKE_ID_SELECT_TRACK:
    486         {
    487             int trackIndex = request.readInt32();
    488             return mPlayer->selectTrack(trackIndex, true /* select */);
    489         }
    490 
    491         case INVOKE_ID_UNSELECT_TRACK:
    492         {
    493             int trackIndex = request.readInt32();
    494             return mPlayer->selectTrack(trackIndex, false /* select */);
    495         }
    496 
    497         case INVOKE_ID_GET_SELECTED_TRACK:
    498         {
    499             int32_t type = request.readInt32();
    500             return mPlayer->getSelectedTrack(type, reply);
    501         }
    502 
    503         default:
    504         {
    505             return INVALID_OPERATION;
    506         }
    507     }
    508 }
    509 
    510 void NuPlayerDriver::setAudioSink(const sp<AudioSink> &audioSink) {
    511     mPlayer->setAudioSink(audioSink);
    512     mAudioSink = audioSink;
    513 }
    514 
    515 status_t NuPlayerDriver::setParameter(
    516         int /* key */, const Parcel & /* request */) {
    517     return INVALID_OPERATION;
    518 }
    519 
    520 status_t NuPlayerDriver::getParameter(int /* key */, Parcel * /* reply */) {
    521     return INVALID_OPERATION;
    522 }
    523 
    524 status_t NuPlayerDriver::getMetadata(
    525         const media::Metadata::Filter& /* ids */, Parcel *records) {
    526     Mutex::Autolock autoLock(mLock);
    527 
    528     using media::Metadata;
    529 
    530     Metadata meta(records);
    531 
    532     meta.appendBool(
    533             Metadata::kPauseAvailable,
    534             mPlayerFlags & NuPlayer::Source::FLAG_CAN_PAUSE);
    535 
    536     meta.appendBool(
    537             Metadata::kSeekBackwardAvailable,
    538             mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK_BACKWARD);
    539 
    540     meta.appendBool(
    541             Metadata::kSeekForwardAvailable,
    542             mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK_FORWARD);
    543 
    544     meta.appendBool(
    545             Metadata::kSeekAvailable,
    546             mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK);
    547 
    548     return OK;
    549 }
    550 
    551 void NuPlayerDriver::notifyResetComplete() {
    552     ALOGD("notifyResetComplete(%p)", this);
    553     Mutex::Autolock autoLock(mLock);
    554 
    555     CHECK_EQ(mState, STATE_RESET_IN_PROGRESS);
    556     mState = STATE_IDLE;
    557     mCondition.broadcast();
    558 }
    559 
    560 void NuPlayerDriver::notifySetSurfaceComplete() {
    561     ALOGV("notifySetSurfaceComplete(%p)", this);
    562     Mutex::Autolock autoLock(mLock);
    563 
    564     CHECK(mSetSurfaceInProgress);
    565     mSetSurfaceInProgress = false;
    566 
    567     mCondition.broadcast();
    568 }
    569 
    570 void NuPlayerDriver::notifyDuration(int64_t durationUs) {
    571     Mutex::Autolock autoLock(mLock);
    572     mDurationUs = durationUs;
    573 }
    574 
    575 void NuPlayerDriver::notifySeekComplete() {
    576     ALOGV("notifySeekComplete(%p)", this);
    577     Mutex::Autolock autoLock(mLock);
    578     mSeekInProgress = false;
    579     notifySeekComplete_l();
    580 }
    581 
    582 void NuPlayerDriver::notifySeekComplete_l() {
    583     bool wasSeeking = true;
    584     if (mState == STATE_STOPPED_AND_PREPARING) {
    585         wasSeeking = false;
    586         mState = STATE_STOPPED_AND_PREPARED;
    587         mCondition.broadcast();
    588         if (!mIsAsyncPrepare) {
    589             // if we are preparing synchronously, no need to notify listener
    590             return;
    591         }
    592     } else if (mState == STATE_STOPPED) {
    593         // no need to notify listener
    594         return;
    595     }
    596     notifyListener_l(wasSeeking ? MEDIA_SEEK_COMPLETE : MEDIA_PREPARED);
    597 }
    598 
    599 status_t NuPlayerDriver::dump(
    600         int fd, const Vector<String16> & /* args */) const {
    601     int64_t numFramesTotal;
    602     int64_t numFramesDropped;
    603     mPlayer->getStats(&numFramesTotal, &numFramesDropped);
    604 
    605     FILE *out = fdopen(dup(fd), "w");
    606 
    607     fprintf(out, " NuPlayer\n");
    608     fprintf(out, "  numFramesTotal(%" PRId64 "), numFramesDropped(%" PRId64 "), "
    609                  "percentageDropped(%.2f)\n",
    610                  numFramesTotal,
    611                  numFramesDropped,
    612                  numFramesTotal == 0
    613                     ? 0.0 : (double)numFramesDropped / numFramesTotal);
    614 
    615     fclose(out);
    616     out = NULL;
    617 
    618     return OK;
    619 }
    620 
    621 void NuPlayerDriver::notifyListener(
    622         int msg, int ext1, int ext2, const Parcel *in) {
    623     Mutex::Autolock autoLock(mLock);
    624     notifyListener_l(msg, ext1, ext2, in);
    625 }
    626 
    627 void NuPlayerDriver::notifyListener_l(
    628         int msg, int ext1, int ext2, const Parcel *in) {
    629     switch (msg) {
    630         case MEDIA_PLAYBACK_COMPLETE:
    631         {
    632             if (mState != STATE_RESET_IN_PROGRESS) {
    633                 if (mLooping || (mAutoLoop
    634                         && (mAudioSink == NULL || mAudioSink->realtime()))) {
    635                     mPlayer->seekToAsync(0);
    636                     break;
    637                 }
    638 
    639                 mPlayer->pause();
    640                 mState = STATE_PAUSED;
    641             }
    642             // fall through
    643         }
    644 
    645         case MEDIA_ERROR:
    646         {
    647             mAtEOS = true;
    648             break;
    649         }
    650 
    651         default:
    652             break;
    653     }
    654 
    655     mLock.unlock();
    656     sendEvent(msg, ext1, ext2, in);
    657     mLock.lock();
    658 }
    659 
    660 void NuPlayerDriver::notifySetDataSourceCompleted(status_t err) {
    661     Mutex::Autolock autoLock(mLock);
    662 
    663     CHECK_EQ(mState, STATE_SET_DATASOURCE_PENDING);
    664 
    665     mAsyncResult = err;
    666     mState = (err == OK) ? STATE_UNPREPARED : STATE_IDLE;
    667     mCondition.broadcast();
    668 }
    669 
    670 void NuPlayerDriver::notifyPrepareCompleted(status_t err) {
    671     Mutex::Autolock autoLock(mLock);
    672 
    673     if (mState != STATE_PREPARING) {
    674         // We were preparing asynchronously when the client called
    675         // reset(), we sent a premature "prepared" notification and
    676         // then initiated the reset. This notification is stale.
    677         CHECK(mState == STATE_RESET_IN_PROGRESS || mState == STATE_IDLE);
    678         return;
    679     }
    680 
    681     CHECK_EQ(mState, STATE_PREPARING);
    682 
    683     mAsyncResult = err;
    684 
    685     if (err == OK) {
    686         // update state before notifying client, so that if client calls back into NuPlayerDriver
    687         // in response, NuPlayerDriver has the right state
    688         mState = STATE_PREPARED;
    689         if (mIsAsyncPrepare) {
    690             notifyListener_l(MEDIA_PREPARED);
    691         }
    692     } else {
    693         mState = STATE_UNPREPARED;
    694         if (mIsAsyncPrepare) {
    695             notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
    696         }
    697     }
    698 
    699     sp<MetaData> meta = mPlayer->getFileMeta();
    700     int32_t loop;
    701     if (meta != NULL
    702             && meta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {
    703         mAutoLoop = true;
    704     }
    705 
    706     mCondition.broadcast();
    707 }
    708 
    709 void NuPlayerDriver::notifyFlagsChanged(uint32_t flags) {
    710     Mutex::Autolock autoLock(mLock);
    711 
    712     mPlayerFlags = flags;
    713 }
    714 
    715 }  // namespace android
    716