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 namespace android {
     35 
     36 NuPlayerDriver::NuPlayerDriver(pid_t pid)
     37     : mState(STATE_IDLE),
     38       mIsAsyncPrepare(false),
     39       mAsyncResult(UNKNOWN_ERROR),
     40       mSetSurfaceInProgress(false),
     41       mDurationUs(-1),
     42       mPositionUs(-1),
     43       mSeekInProgress(false),
     44       mLooper(new ALooper),
     45       mPlayerFlags(0),
     46       mAtEOS(false),
     47       mLooping(false),
     48       mAutoLoop(false) {
     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(pid);
     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::setDataSource(const sp<DataSource> &source) {
    139     ALOGV("setDataSource(%p) callback source", this);
    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(source);
    149 
    150     while (mState == STATE_SET_DATASOURCE_PENDING) {
    151         mCondition.wait(mLock);
    152     }
    153 
    154     return mAsyncResult;
    155 }
    156 
    157 status_t NuPlayerDriver::setVideoSurfaceTexture(
    158         const sp<IGraphicBufferProducer> &bufferProducer) {
    159     ALOGV("setVideoSurfaceTexture(%p)", this);
    160     Mutex::Autolock autoLock(mLock);
    161 
    162     if (mSetSurfaceInProgress) {
    163         return INVALID_OPERATION;
    164     }
    165 
    166     switch (mState) {
    167         case STATE_SET_DATASOURCE_PENDING:
    168         case STATE_RESET_IN_PROGRESS:
    169             return INVALID_OPERATION;
    170 
    171         default:
    172             break;
    173     }
    174 
    175     mSetSurfaceInProgress = true;
    176 
    177     mPlayer->setVideoSurfaceTextureAsync(bufferProducer);
    178 
    179     while (mSetSurfaceInProgress) {
    180         mCondition.wait(mLock);
    181     }
    182 
    183     return OK;
    184 }
    185 
    186 status_t NuPlayerDriver::prepare() {
    187     ALOGV("prepare(%p)", this);
    188     Mutex::Autolock autoLock(mLock);
    189     return prepare_l();
    190 }
    191 
    192 status_t NuPlayerDriver::prepare_l() {
    193     switch (mState) {
    194         case STATE_UNPREPARED:
    195             mState = STATE_PREPARING;
    196 
    197             // Make sure we're not posting any notifications, success or
    198             // failure information is only communicated through our result
    199             // code.
    200             mIsAsyncPrepare = false;
    201             mPlayer->prepareAsync();
    202             while (mState == STATE_PREPARING) {
    203                 mCondition.wait(mLock);
    204             }
    205             return (mState == STATE_PREPARED) ? OK : UNKNOWN_ERROR;
    206         case STATE_STOPPED:
    207             // this is really just paused. handle as seek to start
    208             mAtEOS = false;
    209             mState = STATE_STOPPED_AND_PREPARING;
    210             mIsAsyncPrepare = false;
    211             mPlayer->seekToAsync(0, true /* needNotify */);
    212             while (mState == STATE_STOPPED_AND_PREPARING) {
    213                 mCondition.wait(mLock);
    214             }
    215             return (mState == STATE_STOPPED_AND_PREPARED) ? OK : UNKNOWN_ERROR;
    216         default:
    217             return INVALID_OPERATION;
    218     };
    219 }
    220 
    221 status_t NuPlayerDriver::prepareAsync() {
    222     ALOGV("prepareAsync(%p)", this);
    223     Mutex::Autolock autoLock(mLock);
    224 
    225     switch (mState) {
    226         case STATE_UNPREPARED:
    227             mState = STATE_PREPARING;
    228             mIsAsyncPrepare = true;
    229             mPlayer->prepareAsync();
    230             return OK;
    231         case STATE_STOPPED:
    232             // this is really just paused. handle as seek to start
    233             mAtEOS = false;
    234             mState = STATE_STOPPED_AND_PREPARING;
    235             mIsAsyncPrepare = true;
    236             mPlayer->seekToAsync(0, true /* needNotify */);
    237             return OK;
    238         default:
    239             return INVALID_OPERATION;
    240     };
    241 }
    242 
    243 status_t NuPlayerDriver::start() {
    244     ALOGD("start(%p), state is %d, eos is %d", this, mState, mAtEOS);
    245     Mutex::Autolock autoLock(mLock);
    246     return start_l();
    247 }
    248 
    249 status_t NuPlayerDriver::start_l() {
    250     switch (mState) {
    251         case STATE_UNPREPARED:
    252         {
    253             status_t err = prepare_l();
    254 
    255             if (err != OK) {
    256                 return err;
    257             }
    258 
    259             CHECK_EQ(mState, STATE_PREPARED);
    260 
    261             // fall through
    262         }
    263 
    264         case STATE_PAUSED:
    265         case STATE_STOPPED_AND_PREPARED:
    266         case STATE_PREPARED:
    267         {
    268             mPlayer->start();
    269 
    270             // fall through
    271         }
    272 
    273         case STATE_RUNNING:
    274         {
    275             if (mAtEOS) {
    276                 mPlayer->seekToAsync(0);
    277                 mAtEOS = false;
    278                 mPositionUs = -1;
    279             }
    280             break;
    281         }
    282 
    283         default:
    284             return INVALID_OPERATION;
    285     }
    286 
    287     mState = STATE_RUNNING;
    288 
    289     return OK;
    290 }
    291 
    292 status_t NuPlayerDriver::stop() {
    293     ALOGD("stop(%p)", this);
    294     Mutex::Autolock autoLock(mLock);
    295 
    296     switch (mState) {
    297         case STATE_RUNNING:
    298             mPlayer->pause();
    299             // fall through
    300 
    301         case STATE_PAUSED:
    302             mState = STATE_STOPPED;
    303             notifyListener_l(MEDIA_STOPPED);
    304             break;
    305 
    306         case STATE_PREPARED:
    307         case STATE_STOPPED:
    308         case STATE_STOPPED_AND_PREPARING:
    309         case STATE_STOPPED_AND_PREPARED:
    310             mState = STATE_STOPPED;
    311             break;
    312 
    313         default:
    314             return INVALID_OPERATION;
    315     }
    316 
    317     return OK;
    318 }
    319 
    320 status_t NuPlayerDriver::pause() {
    321     ALOGD("pause(%p)", this);
    322     // The NuPlayerRenderer may get flushed if pause for long enough, e.g. the pause timeout tear
    323     // down for audio offload mode. If that happens, the NuPlayerRenderer will no longer know the
    324     // current position. So similar to seekTo, update |mPositionUs| to the pause position by calling
    325     // getCurrentPosition here.
    326     int unused;
    327     getCurrentPosition(&unused);
    328 
    329     Mutex::Autolock autoLock(mLock);
    330 
    331     switch (mState) {
    332         case STATE_PAUSED:
    333         case STATE_PREPARED:
    334             return OK;
    335 
    336         case STATE_RUNNING:
    337             mState = STATE_PAUSED;
    338             notifyListener_l(MEDIA_PAUSED);
    339             mPlayer->pause();
    340             break;
    341 
    342         default:
    343             return INVALID_OPERATION;
    344     }
    345 
    346     return OK;
    347 }
    348 
    349 bool NuPlayerDriver::isPlaying() {
    350     return mState == STATE_RUNNING && !mAtEOS;
    351 }
    352 
    353 status_t NuPlayerDriver::setPlaybackSettings(const AudioPlaybackRate &rate) {
    354     status_t err = mPlayer->setPlaybackSettings(rate);
    355     if (err == OK) {
    356         // try to update position
    357         int unused;
    358         getCurrentPosition(&unused);
    359         Mutex::Autolock autoLock(mLock);
    360         if (rate.mSpeed == 0.f && mState == STATE_RUNNING) {
    361             mState = STATE_PAUSED;
    362             notifyListener_l(MEDIA_PAUSED);
    363         } else if (rate.mSpeed != 0.f
    364                 && (mState == STATE_PAUSED
    365                     || mState == STATE_STOPPED_AND_PREPARED
    366                     || mState == STATE_PREPARED)) {
    367             err = start_l();
    368         }
    369     }
    370     return err;
    371 }
    372 
    373 status_t NuPlayerDriver::getPlaybackSettings(AudioPlaybackRate *rate) {
    374     return mPlayer->getPlaybackSettings(rate);
    375 }
    376 
    377 status_t NuPlayerDriver::setSyncSettings(const AVSyncSettings &sync, float videoFpsHint) {
    378     return mPlayer->setSyncSettings(sync, videoFpsHint);
    379 }
    380 
    381 status_t NuPlayerDriver::getSyncSettings(AVSyncSettings *sync, float *videoFps) {
    382     return mPlayer->getSyncSettings(sync, videoFps);
    383 }
    384 
    385 status_t NuPlayerDriver::seekTo(int msec) {
    386     ALOGD("seekTo(%p) %d ms at state %d", this, msec, mState);
    387     Mutex::Autolock autoLock(mLock);
    388 
    389     int64_t seekTimeUs = msec * 1000ll;
    390 
    391     switch (mState) {
    392         case STATE_PREPARED:
    393         case STATE_STOPPED_AND_PREPARED:
    394         case STATE_PAUSED:
    395         case STATE_RUNNING:
    396         {
    397             mAtEOS = false;
    398             mSeekInProgress = true;
    399             // seeks can take a while, so we essentially paused
    400             notifyListener_l(MEDIA_PAUSED);
    401             mPlayer->seekToAsync(seekTimeUs, true /* needNotify */);
    402             break;
    403         }
    404 
    405         default:
    406             return INVALID_OPERATION;
    407     }
    408 
    409     mPositionUs = seekTimeUs;
    410     return OK;
    411 }
    412 
    413 status_t NuPlayerDriver::getCurrentPosition(int *msec) {
    414     int64_t tempUs = 0;
    415     {
    416         Mutex::Autolock autoLock(mLock);
    417         if (mSeekInProgress || (mState == STATE_PAUSED && !mAtEOS)) {
    418             tempUs = (mPositionUs <= 0) ? 0 : mPositionUs;
    419             *msec = (int)divRound(tempUs, (int64_t)(1000));
    420             return OK;
    421         }
    422     }
    423 
    424     status_t ret = mPlayer->getCurrentPosition(&tempUs);
    425 
    426     Mutex::Autolock autoLock(mLock);
    427     // We need to check mSeekInProgress here because mPlayer->seekToAsync is an async call, which
    428     // means getCurrentPosition can be called before seek is completed. Iow, renderer may return a
    429     // position value that's different the seek to position.
    430     if (ret != OK) {
    431         tempUs = (mPositionUs <= 0) ? 0 : mPositionUs;
    432     } else {
    433         mPositionUs = tempUs;
    434     }
    435     *msec = (int)divRound(tempUs, (int64_t)(1000));
    436     return OK;
    437 }
    438 
    439 status_t NuPlayerDriver::getDuration(int *msec) {
    440     Mutex::Autolock autoLock(mLock);
    441 
    442     if (mDurationUs < 0) {
    443         return UNKNOWN_ERROR;
    444     }
    445 
    446     *msec = (mDurationUs + 500ll) / 1000;
    447 
    448     return OK;
    449 }
    450 
    451 status_t NuPlayerDriver::reset() {
    452     ALOGD("reset(%p) at state %d", this, mState);
    453     Mutex::Autolock autoLock(mLock);
    454 
    455     switch (mState) {
    456         case STATE_IDLE:
    457             return OK;
    458 
    459         case STATE_SET_DATASOURCE_PENDING:
    460         case STATE_RESET_IN_PROGRESS:
    461             return INVALID_OPERATION;
    462 
    463         case STATE_PREPARING:
    464         {
    465             CHECK(mIsAsyncPrepare);
    466 
    467             notifyListener_l(MEDIA_PREPARED);
    468             break;
    469         }
    470 
    471         default:
    472             break;
    473     }
    474 
    475     if (mState != STATE_STOPPED) {
    476         notifyListener_l(MEDIA_STOPPED);
    477     }
    478 
    479     char value[PROPERTY_VALUE_MAX];
    480     if (property_get("persist.debug.sf.stats", value, NULL) &&
    481             (!strcmp("1", value) || !strcasecmp("true", value))) {
    482         Vector<String16> args;
    483         dump(-1, args);
    484     }
    485 
    486     mState = STATE_RESET_IN_PROGRESS;
    487     mPlayer->resetAsync();
    488 
    489     while (mState == STATE_RESET_IN_PROGRESS) {
    490         mCondition.wait(mLock);
    491     }
    492 
    493     mDurationUs = -1;
    494     mPositionUs = -1;
    495     mLooping = false;
    496 
    497     return OK;
    498 }
    499 
    500 status_t NuPlayerDriver::setLooping(int loop) {
    501     mLooping = loop != 0;
    502     return OK;
    503 }
    504 
    505 player_type NuPlayerDriver::playerType() {
    506     return NU_PLAYER;
    507 }
    508 
    509 status_t NuPlayerDriver::invoke(const Parcel &request, Parcel *reply) {
    510     if (reply == NULL) {
    511         ALOGE("reply is a NULL pointer");
    512         return BAD_VALUE;
    513     }
    514 
    515     int32_t methodId;
    516     status_t ret = request.readInt32(&methodId);
    517     if (ret != OK) {
    518         ALOGE("Failed to retrieve the requested method to invoke");
    519         return ret;
    520     }
    521 
    522     switch (methodId) {
    523         case INVOKE_ID_SET_VIDEO_SCALING_MODE:
    524         {
    525             int mode = request.readInt32();
    526             return mPlayer->setVideoScalingMode(mode);
    527         }
    528 
    529         case INVOKE_ID_GET_TRACK_INFO:
    530         {
    531             return mPlayer->getTrackInfo(reply);
    532         }
    533 
    534         case INVOKE_ID_SELECT_TRACK:
    535         {
    536             int trackIndex = request.readInt32();
    537             int msec = 0;
    538             // getCurrentPosition should always return OK
    539             getCurrentPosition(&msec);
    540             return mPlayer->selectTrack(trackIndex, true /* select */, msec * 1000ll);
    541         }
    542 
    543         case INVOKE_ID_UNSELECT_TRACK:
    544         {
    545             int trackIndex = request.readInt32();
    546             return mPlayer->selectTrack(trackIndex, false /* select */, 0xdeadbeef /* not used */);
    547         }
    548 
    549         case INVOKE_ID_GET_SELECTED_TRACK:
    550         {
    551             int32_t type = request.readInt32();
    552             return mPlayer->getSelectedTrack(type, reply);
    553         }
    554 
    555         default:
    556         {
    557             return INVALID_OPERATION;
    558         }
    559     }
    560 }
    561 
    562 void NuPlayerDriver::setAudioSink(const sp<AudioSink> &audioSink) {
    563     mPlayer->setAudioSink(audioSink);
    564     mAudioSink = audioSink;
    565 }
    566 
    567 status_t NuPlayerDriver::setParameter(
    568         int /* key */, const Parcel & /* request */) {
    569     return INVALID_OPERATION;
    570 }
    571 
    572 status_t NuPlayerDriver::getParameter(int /* key */, Parcel * /* reply */) {
    573     return INVALID_OPERATION;
    574 }
    575 
    576 status_t NuPlayerDriver::getMetadata(
    577         const media::Metadata::Filter& /* ids */, Parcel *records) {
    578     Mutex::Autolock autoLock(mLock);
    579 
    580     using media::Metadata;
    581 
    582     Metadata meta(records);
    583 
    584     meta.appendBool(
    585             Metadata::kPauseAvailable,
    586             mPlayerFlags & NuPlayer::Source::FLAG_CAN_PAUSE);
    587 
    588     meta.appendBool(
    589             Metadata::kSeekBackwardAvailable,
    590             mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK_BACKWARD);
    591 
    592     meta.appendBool(
    593             Metadata::kSeekForwardAvailable,
    594             mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK_FORWARD);
    595 
    596     meta.appendBool(
    597             Metadata::kSeekAvailable,
    598             mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK);
    599 
    600     return OK;
    601 }
    602 
    603 void NuPlayerDriver::notifyResetComplete() {
    604     ALOGD("notifyResetComplete(%p)", this);
    605     Mutex::Autolock autoLock(mLock);
    606 
    607     CHECK_EQ(mState, STATE_RESET_IN_PROGRESS);
    608     mState = STATE_IDLE;
    609     mCondition.broadcast();
    610 }
    611 
    612 void NuPlayerDriver::notifySetSurfaceComplete() {
    613     ALOGV("notifySetSurfaceComplete(%p)", this);
    614     Mutex::Autolock autoLock(mLock);
    615 
    616     CHECK(mSetSurfaceInProgress);
    617     mSetSurfaceInProgress = false;
    618 
    619     mCondition.broadcast();
    620 }
    621 
    622 void NuPlayerDriver::notifyDuration(int64_t durationUs) {
    623     Mutex::Autolock autoLock(mLock);
    624     mDurationUs = durationUs;
    625 }
    626 
    627 void NuPlayerDriver::notifySeekComplete() {
    628     ALOGV("notifySeekComplete(%p)", this);
    629     Mutex::Autolock autoLock(mLock);
    630     mSeekInProgress = false;
    631     notifySeekComplete_l();
    632 }
    633 
    634 void NuPlayerDriver::notifySeekComplete_l() {
    635     bool wasSeeking = true;
    636     if (mState == STATE_STOPPED_AND_PREPARING) {
    637         wasSeeking = false;
    638         mState = STATE_STOPPED_AND_PREPARED;
    639         mCondition.broadcast();
    640         if (!mIsAsyncPrepare) {
    641             // if we are preparing synchronously, no need to notify listener
    642             return;
    643         }
    644     } else if (mState == STATE_STOPPED) {
    645         // no need to notify listener
    646         return;
    647     }
    648     notifyListener_l(wasSeeking ? MEDIA_SEEK_COMPLETE : MEDIA_PREPARED);
    649 }
    650 
    651 status_t NuPlayerDriver::dump(
    652         int fd, const Vector<String16> & /* args */) const {
    653 
    654     Vector<sp<AMessage> > trackStats;
    655     mPlayer->getStats(&trackStats);
    656 
    657     AString logString(" NuPlayer\n");
    658     char buf[256] = {0};
    659 
    660     for (size_t i = 0; i < trackStats.size(); ++i) {
    661         const sp<AMessage> &stats = trackStats.itemAt(i);
    662 
    663         AString mime;
    664         if (stats->findString("mime", &mime)) {
    665             snprintf(buf, sizeof(buf), "  mime(%s)\n", mime.c_str());
    666             logString.append(buf);
    667         }
    668 
    669         AString name;
    670         if (stats->findString("component-name", &name)) {
    671             snprintf(buf, sizeof(buf), "    decoder(%s)\n", name.c_str());
    672             logString.append(buf);
    673         }
    674 
    675         if (mime.startsWith("video/")) {
    676             int32_t width, height;
    677             if (stats->findInt32("width", &width)
    678                     && stats->findInt32("height", &height)) {
    679                 snprintf(buf, sizeof(buf), "    resolution(%d x %d)\n", width, height);
    680                 logString.append(buf);
    681             }
    682 
    683             int64_t numFramesTotal = 0;
    684             int64_t numFramesDropped = 0;
    685 
    686             stats->findInt64("frames-total", &numFramesTotal);
    687             stats->findInt64("frames-dropped-output", &numFramesDropped);
    688             snprintf(buf, sizeof(buf), "    numFramesTotal(%lld), numFramesDropped(%lld), "
    689                      "percentageDropped(%.2f%%)\n",
    690                      (long long)numFramesTotal,
    691                      (long long)numFramesDropped,
    692                      numFramesTotal == 0
    693                             ? 0.0 : (double)(numFramesDropped * 100) / numFramesTotal);
    694             logString.append(buf);
    695         }
    696     }
    697 
    698     ALOGI("%s", logString.c_str());
    699 
    700     if (fd >= 0) {
    701         FILE *out = fdopen(dup(fd), "w");
    702         fprintf(out, "%s", logString.c_str());
    703         fclose(out);
    704         out = NULL;
    705     }
    706 
    707     return OK;
    708 }
    709 
    710 void NuPlayerDriver::notifyListener(
    711         int msg, int ext1, int ext2, const Parcel *in) {
    712     Mutex::Autolock autoLock(mLock);
    713     notifyListener_l(msg, ext1, ext2, in);
    714 }
    715 
    716 void NuPlayerDriver::notifyListener_l(
    717         int msg, int ext1, int ext2, const Parcel *in) {
    718     ALOGD("notifyListener_l(%p), (%d, %d, %d), loop setting(%d, %d)",
    719             this, msg, ext1, ext2, mAutoLoop, mLooping);
    720     switch (msg) {
    721         case MEDIA_PLAYBACK_COMPLETE:
    722         {
    723             if (mState != STATE_RESET_IN_PROGRESS) {
    724                 if (mAutoLoop) {
    725                     audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
    726                     if (mAudioSink != NULL) {
    727                         streamType = mAudioSink->getAudioStreamType();
    728                     }
    729                     if (streamType == AUDIO_STREAM_NOTIFICATION) {
    730                         ALOGW("disabling auto-loop for notification");
    731                         mAutoLoop = false;
    732                     }
    733                 }
    734                 if (mLooping || mAutoLoop) {
    735                     mPlayer->seekToAsync(0);
    736                     if (mAudioSink != NULL) {
    737                         // The renderer has stopped the sink at the end in order to play out
    738                         // the last little bit of audio. If we're looping, we need to restart it.
    739                         mAudioSink->start();
    740                     }
    741                     // don't send completion event when looping
    742                     return;
    743                 }
    744 
    745                 mPlayer->pause();
    746                 mState = STATE_PAUSED;
    747             }
    748             // fall through
    749         }
    750 
    751         case MEDIA_ERROR:
    752         {
    753             mAtEOS = true;
    754             break;
    755         }
    756 
    757         default:
    758             break;
    759     }
    760 
    761     mLock.unlock();
    762     sendEvent(msg, ext1, ext2, in);
    763     mLock.lock();
    764 }
    765 
    766 void NuPlayerDriver::notifySetDataSourceCompleted(status_t err) {
    767     Mutex::Autolock autoLock(mLock);
    768 
    769     CHECK_EQ(mState, STATE_SET_DATASOURCE_PENDING);
    770 
    771     mAsyncResult = err;
    772     mState = (err == OK) ? STATE_UNPREPARED : STATE_IDLE;
    773     mCondition.broadcast();
    774 }
    775 
    776 void NuPlayerDriver::notifyPrepareCompleted(status_t err) {
    777     Mutex::Autolock autoLock(mLock);
    778 
    779     if (mState != STATE_PREPARING) {
    780         // We were preparing asynchronously when the client called
    781         // reset(), we sent a premature "prepared" notification and
    782         // then initiated the reset. This notification is stale.
    783         CHECK(mState == STATE_RESET_IN_PROGRESS || mState == STATE_IDLE);
    784         return;
    785     }
    786 
    787     CHECK_EQ(mState, STATE_PREPARING);
    788 
    789     mAsyncResult = err;
    790 
    791     if (err == OK) {
    792         // update state before notifying client, so that if client calls back into NuPlayerDriver
    793         // in response, NuPlayerDriver has the right state
    794         mState = STATE_PREPARED;
    795         if (mIsAsyncPrepare) {
    796             notifyListener_l(MEDIA_PREPARED);
    797         }
    798     } else {
    799         mState = STATE_UNPREPARED;
    800         if (mIsAsyncPrepare) {
    801             notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
    802         }
    803     }
    804 
    805     sp<MetaData> meta = mPlayer->getFileMeta();
    806     int32_t loop;
    807     if (meta != NULL
    808             && meta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {
    809         mAutoLoop = true;
    810     }
    811 
    812     mCondition.broadcast();
    813 }
    814 
    815 void NuPlayerDriver::notifyFlagsChanged(uint32_t flags) {
    816     Mutex::Autolock autoLock(mLock);
    817 
    818     mPlayerFlags = flags;
    819 }
    820 
    821 }  // namespace android
    822