Home | History | Annotate | Download | only in libmedia
      1 /* mediaplayer.cpp
      2 **
      3 ** Copyright 2006, The Android Open Source Project
      4 **
      5 ** Licensed under the Apache License, Version 2.0 (the "License");
      6 ** you may not use this file except in compliance with the License.
      7 ** You may obtain a copy of the License at
      8 **
      9 **     http://www.apache.org/licenses/LICENSE-2.0
     10 **
     11 ** Unless required by applicable law or agreed to in writing, software
     12 ** distributed under the License is distributed on an "AS IS" BASIS,
     13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 ** See the License for the specific language governing permissions and
     15 ** limitations under the License.
     16 */
     17 
     18 //#define LOG_NDEBUG 0
     19 #define LOG_TAG "MediaPlayer"
     20 #include <utils/Log.h>
     21 
     22 #include <sys/types.h>
     23 #include <sys/stat.h>
     24 #include <unistd.h>
     25 #include <fcntl.h>
     26 
     27 #include <binder/IServiceManager.h>
     28 #include <binder/IPCThreadState.h>
     29 
     30 #include <gui/SurfaceTextureClient.h>
     31 
     32 #include <media/mediaplayer.h>
     33 #include <media/AudioTrack.h>
     34 
     35 #include <surfaceflinger/Surface.h>
     36 
     37 #include <binder/MemoryBase.h>
     38 
     39 #include <utils/KeyedVector.h>
     40 #include <utils/String8.h>
     41 
     42 #include <system/audio.h>
     43 #include <system/window.h>
     44 
     45 namespace android {
     46 
     47 MediaPlayer::MediaPlayer()
     48 {
     49     LOGV("constructor");
     50     mListener = NULL;
     51     mCookie = NULL;
     52     mDuration = -1;
     53     mStreamType = AUDIO_STREAM_MUSIC;
     54     mCurrentPosition = -1;
     55     mSeekPosition = -1;
     56     mCurrentState = MEDIA_PLAYER_IDLE;
     57     mPrepareSync = false;
     58     mPrepareStatus = NO_ERROR;
     59     mLoop = false;
     60     mLeftVolume = mRightVolume = 1.0;
     61     mVideoWidth = mVideoHeight = 0;
     62     mLockThreadId = 0;
     63     mAudioSessionId = AudioSystem::newAudioSessionId();
     64     AudioSystem::acquireAudioSessionId(mAudioSessionId);
     65     mSendLevel = 0;
     66 }
     67 
     68 MediaPlayer::~MediaPlayer()
     69 {
     70     LOGV("destructor");
     71     AudioSystem::releaseAudioSessionId(mAudioSessionId);
     72     disconnect();
     73     IPCThreadState::self()->flushCommands();
     74 }
     75 
     76 void MediaPlayer::disconnect()
     77 {
     78     LOGV("disconnect");
     79     sp<IMediaPlayer> p;
     80     {
     81         Mutex::Autolock _l(mLock);
     82         p = mPlayer;
     83         mPlayer.clear();
     84     }
     85 
     86     if (p != 0) {
     87         p->disconnect();
     88     }
     89 }
     90 
     91 // always call with lock held
     92 void MediaPlayer::clear_l()
     93 {
     94     mDuration = -1;
     95     mCurrentPosition = -1;
     96     mSeekPosition = -1;
     97     mVideoWidth = mVideoHeight = 0;
     98 }
     99 
    100 status_t MediaPlayer::setListener(const sp<MediaPlayerListener>& listener)
    101 {
    102     LOGV("setListener");
    103     Mutex::Autolock _l(mLock);
    104     mListener = listener;
    105     return NO_ERROR;
    106 }
    107 
    108 
    109 status_t MediaPlayer::attachNewPlayer(const sp<IMediaPlayer>& player)
    110 {
    111     status_t err = UNKNOWN_ERROR;
    112     sp<IMediaPlayer> p;
    113     { // scope for the lock
    114         Mutex::Autolock _l(mLock);
    115 
    116         if ( !( (mCurrentState & MEDIA_PLAYER_IDLE) ||
    117                 (mCurrentState == MEDIA_PLAYER_STATE_ERROR ) ) ) {
    118             LOGE("attachNewPlayer called in state %d", mCurrentState);
    119             return INVALID_OPERATION;
    120         }
    121 
    122         clear_l();
    123         p = mPlayer;
    124         mPlayer = player;
    125         if (player != 0) {
    126             mCurrentState = MEDIA_PLAYER_INITIALIZED;
    127             err = NO_ERROR;
    128         } else {
    129             LOGE("Unable to to create media player");
    130         }
    131     }
    132 
    133     if (p != 0) {
    134         p->disconnect();
    135     }
    136 
    137     return err;
    138 }
    139 
    140 status_t MediaPlayer::setDataSource(
    141         const char *url, const KeyedVector<String8, String8> *headers)
    142 {
    143     LOGV("setDataSource(%s)", url);
    144     status_t err = BAD_VALUE;
    145     if (url != NULL) {
    146         const sp<IMediaPlayerService>& service(getMediaPlayerService());
    147         if (service != 0) {
    148             sp<IMediaPlayer> player(service->create(getpid(), this, mAudioSessionId));
    149             if (NO_ERROR != player->setDataSource(url, headers)) {
    150                 player.clear();
    151             }
    152             err = attachNewPlayer(player);
    153         }
    154     }
    155     return err;
    156 }
    157 
    158 status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
    159 {
    160     LOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
    161     status_t err = UNKNOWN_ERROR;
    162     const sp<IMediaPlayerService>& service(getMediaPlayerService());
    163     if (service != 0) {
    164         sp<IMediaPlayer> player(service->create(getpid(), this, mAudioSessionId));
    165         if (NO_ERROR != player->setDataSource(fd, offset, length)) {
    166             player.clear();
    167         }
    168         err = attachNewPlayer(player);
    169     }
    170     return err;
    171 }
    172 
    173 status_t MediaPlayer::setDataSource(const sp<IStreamSource> &source)
    174 {
    175     LOGV("setDataSource");
    176     status_t err = UNKNOWN_ERROR;
    177     const sp<IMediaPlayerService>& service(getMediaPlayerService());
    178     if (service != 0) {
    179         sp<IMediaPlayer> player(service->create(getpid(), this, mAudioSessionId));
    180         if (NO_ERROR != player->setDataSource(source)) {
    181             player.clear();
    182         }
    183         err = attachNewPlayer(player);
    184     }
    185     return err;
    186 }
    187 
    188 status_t MediaPlayer::invoke(const Parcel& request, Parcel *reply)
    189 {
    190     Mutex::Autolock _l(mLock);
    191     const bool hasBeenInitialized =
    192             (mCurrentState != MEDIA_PLAYER_STATE_ERROR) &&
    193             ((mCurrentState & MEDIA_PLAYER_IDLE) != MEDIA_PLAYER_IDLE);
    194     if ((mPlayer != NULL) && hasBeenInitialized) {
    195          LOGV("invoke %d", request.dataSize());
    196          return  mPlayer->invoke(request, reply);
    197     }
    198     LOGE("invoke failed: wrong state %X", mCurrentState);
    199     return INVALID_OPERATION;
    200 }
    201 
    202 status_t MediaPlayer::setMetadataFilter(const Parcel& filter)
    203 {
    204     LOGD("setMetadataFilter");
    205     Mutex::Autolock lock(mLock);
    206     if (mPlayer == NULL) {
    207         return NO_INIT;
    208     }
    209     return mPlayer->setMetadataFilter(filter);
    210 }
    211 
    212 status_t MediaPlayer::getMetadata(bool update_only, bool apply_filter, Parcel *metadata)
    213 {
    214     LOGD("getMetadata");
    215     Mutex::Autolock lock(mLock);
    216     if (mPlayer == NULL) {
    217         return NO_INIT;
    218     }
    219     return mPlayer->getMetadata(update_only, apply_filter, metadata);
    220 }
    221 
    222 status_t MediaPlayer::setVideoSurface(const sp<Surface>& surface)
    223 {
    224     LOGV("setVideoSurface");
    225     Mutex::Autolock _l(mLock);
    226     if (mPlayer == 0) return NO_INIT;
    227     return mPlayer->setVideoSurface(surface);
    228 }
    229 
    230 status_t MediaPlayer::setVideoSurfaceTexture(
    231         const sp<ISurfaceTexture>& surfaceTexture)
    232 {
    233     LOGV("setVideoSurfaceTexture");
    234     Mutex::Autolock _l(mLock);
    235     if (mPlayer == 0) return NO_INIT;
    236     return mPlayer->setVideoSurfaceTexture(surfaceTexture);
    237 }
    238 
    239 // must call with lock held
    240 status_t MediaPlayer::prepareAsync_l()
    241 {
    242     if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_INITIALIZED | MEDIA_PLAYER_STOPPED) ) ) {
    243         mPlayer->setAudioStreamType(mStreamType);
    244         mCurrentState = MEDIA_PLAYER_PREPARING;
    245         return mPlayer->prepareAsync();
    246     }
    247     LOGE("prepareAsync called in state %d", mCurrentState);
    248     return INVALID_OPERATION;
    249 }
    250 
    251 // TODO: In case of error, prepareAsync provides the caller with 2 error codes,
    252 // one defined in the Android framework and one provided by the implementation
    253 // that generated the error. The sync version of prepare returns only 1 error
    254 // code.
    255 status_t MediaPlayer::prepare()
    256 {
    257     LOGV("prepare");
    258     Mutex::Autolock _l(mLock);
    259     mLockThreadId = getThreadId();
    260     if (mPrepareSync) {
    261         mLockThreadId = 0;
    262         return -EALREADY;
    263     }
    264     mPrepareSync = true;
    265     status_t ret = prepareAsync_l();
    266     if (ret != NO_ERROR) {
    267         mLockThreadId = 0;
    268         return ret;
    269     }
    270 
    271     if (mPrepareSync) {
    272         mSignal.wait(mLock);  // wait for prepare done
    273         mPrepareSync = false;
    274     }
    275     LOGV("prepare complete - status=%d", mPrepareStatus);
    276     mLockThreadId = 0;
    277     return mPrepareStatus;
    278 }
    279 
    280 status_t MediaPlayer::prepareAsync()
    281 {
    282     LOGV("prepareAsync");
    283     Mutex::Autolock _l(mLock);
    284     return prepareAsync_l();
    285 }
    286 
    287 status_t MediaPlayer::start()
    288 {
    289     LOGV("start");
    290     Mutex::Autolock _l(mLock);
    291     if (mCurrentState & MEDIA_PLAYER_STARTED)
    292         return NO_ERROR;
    293     if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_PREPARED |
    294                     MEDIA_PLAYER_PLAYBACK_COMPLETE | MEDIA_PLAYER_PAUSED ) ) ) {
    295         mPlayer->setLooping(mLoop);
    296         mPlayer->setVolume(mLeftVolume, mRightVolume);
    297         mPlayer->setAuxEffectSendLevel(mSendLevel);
    298         mCurrentState = MEDIA_PLAYER_STARTED;
    299         status_t ret = mPlayer->start();
    300         if (ret != NO_ERROR) {
    301             mCurrentState = MEDIA_PLAYER_STATE_ERROR;
    302         } else {
    303             if (mCurrentState == MEDIA_PLAYER_PLAYBACK_COMPLETE) {
    304                 LOGV("playback completed immediately following start()");
    305             }
    306         }
    307         return ret;
    308     }
    309     LOGE("start called in state %d", mCurrentState);
    310     return INVALID_OPERATION;
    311 }
    312 
    313 status_t MediaPlayer::stop()
    314 {
    315     LOGV("stop");
    316     Mutex::Autolock _l(mLock);
    317     if (mCurrentState & MEDIA_PLAYER_STOPPED) return NO_ERROR;
    318     if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED |
    319                     MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE ) ) ) {
    320         status_t ret = mPlayer->stop();
    321         if (ret != NO_ERROR) {
    322             mCurrentState = MEDIA_PLAYER_STATE_ERROR;
    323         } else {
    324             mCurrentState = MEDIA_PLAYER_STOPPED;
    325         }
    326         return ret;
    327     }
    328     LOGE("stop called in state %d", mCurrentState);
    329     return INVALID_OPERATION;
    330 }
    331 
    332 status_t MediaPlayer::pause()
    333 {
    334     LOGV("pause");
    335     Mutex::Autolock _l(mLock);
    336     if (mCurrentState & (MEDIA_PLAYER_PAUSED|MEDIA_PLAYER_PLAYBACK_COMPLETE))
    337         return NO_ERROR;
    338     if ((mPlayer != 0) && (mCurrentState & MEDIA_PLAYER_STARTED)) {
    339         status_t ret = mPlayer->pause();
    340         if (ret != NO_ERROR) {
    341             mCurrentState = MEDIA_PLAYER_STATE_ERROR;
    342         } else {
    343             mCurrentState = MEDIA_PLAYER_PAUSED;
    344         }
    345         return ret;
    346     }
    347     LOGE("pause called in state %d", mCurrentState);
    348     return INVALID_OPERATION;
    349 }
    350 
    351 bool MediaPlayer::isPlaying()
    352 {
    353     Mutex::Autolock _l(mLock);
    354     if (mPlayer != 0) {
    355         bool temp = false;
    356         mPlayer->isPlaying(&temp);
    357         LOGV("isPlaying: %d", temp);
    358         if ((mCurrentState & MEDIA_PLAYER_STARTED) && ! temp) {
    359             LOGE("internal/external state mismatch corrected");
    360             mCurrentState = MEDIA_PLAYER_PAUSED;
    361         }
    362         return temp;
    363     }
    364     LOGV("isPlaying: no active player");
    365     return false;
    366 }
    367 
    368 status_t MediaPlayer::getVideoWidth(int *w)
    369 {
    370     LOGV("getVideoWidth");
    371     Mutex::Autolock _l(mLock);
    372     if (mPlayer == 0) return INVALID_OPERATION;
    373     *w = mVideoWidth;
    374     return NO_ERROR;
    375 }
    376 
    377 status_t MediaPlayer::getVideoHeight(int *h)
    378 {
    379     LOGV("getVideoHeight");
    380     Mutex::Autolock _l(mLock);
    381     if (mPlayer == 0) return INVALID_OPERATION;
    382     *h = mVideoHeight;
    383     return NO_ERROR;
    384 }
    385 
    386 status_t MediaPlayer::getCurrentPosition(int *msec)
    387 {
    388     LOGV("getCurrentPosition");
    389     Mutex::Autolock _l(mLock);
    390     if (mPlayer != 0) {
    391         if (mCurrentPosition >= 0) {
    392             LOGV("Using cached seek position: %d", mCurrentPosition);
    393             *msec = mCurrentPosition;
    394             return NO_ERROR;
    395         }
    396         return mPlayer->getCurrentPosition(msec);
    397     }
    398     return INVALID_OPERATION;
    399 }
    400 
    401 status_t MediaPlayer::getDuration_l(int *msec)
    402 {
    403     LOGV("getDuration");
    404     bool isValidState = (mCurrentState & (MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_STOPPED | MEDIA_PLAYER_PLAYBACK_COMPLETE));
    405     if (mPlayer != 0 && isValidState) {
    406         status_t ret = NO_ERROR;
    407         if (mDuration <= 0)
    408             ret = mPlayer->getDuration(&mDuration);
    409         if (msec)
    410             *msec = mDuration;
    411         return ret;
    412     }
    413     LOGE("Attempt to call getDuration without a valid mediaplayer");
    414     return INVALID_OPERATION;
    415 }
    416 
    417 status_t MediaPlayer::getDuration(int *msec)
    418 {
    419     Mutex::Autolock _l(mLock);
    420     return getDuration_l(msec);
    421 }
    422 
    423 status_t MediaPlayer::seekTo_l(int msec)
    424 {
    425     LOGV("seekTo %d", msec);
    426     if ((mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_PAUSED |  MEDIA_PLAYER_PLAYBACK_COMPLETE) ) ) {
    427         if ( msec < 0 ) {
    428             LOGW("Attempt to seek to invalid position: %d", msec);
    429             msec = 0;
    430         } else if ((mDuration > 0) && (msec > mDuration)) {
    431             LOGW("Attempt to seek to past end of file: request = %d, EOF = %d", msec, mDuration);
    432             msec = mDuration;
    433         }
    434         // cache duration
    435         mCurrentPosition = msec;
    436         if (mSeekPosition < 0) {
    437             getDuration_l(NULL);
    438             mSeekPosition = msec;
    439             return mPlayer->seekTo(msec);
    440         }
    441         else {
    442             LOGV("Seek in progress - queue up seekTo[%d]", msec);
    443             return NO_ERROR;
    444         }
    445     }
    446     LOGE("Attempt to perform seekTo in wrong state: mPlayer=%p, mCurrentState=%u", mPlayer.get(), mCurrentState);
    447     return INVALID_OPERATION;
    448 }
    449 
    450 status_t MediaPlayer::seekTo(int msec)
    451 {
    452     mLockThreadId = getThreadId();
    453     Mutex::Autolock _l(mLock);
    454     status_t result = seekTo_l(msec);
    455     mLockThreadId = 0;
    456 
    457     return result;
    458 }
    459 
    460 status_t MediaPlayer::reset_l()
    461 {
    462     mLoop = false;
    463     if (mCurrentState == MEDIA_PLAYER_IDLE) return NO_ERROR;
    464     mPrepareSync = false;
    465     if (mPlayer != 0) {
    466         status_t ret = mPlayer->reset();
    467         if (ret != NO_ERROR) {
    468             LOGE("reset() failed with return code (%d)", ret);
    469             mCurrentState = MEDIA_PLAYER_STATE_ERROR;
    470         } else {
    471             mCurrentState = MEDIA_PLAYER_IDLE;
    472         }
    473         // setDataSource has to be called again to create a
    474         // new mediaplayer.
    475         mPlayer = 0;
    476         return ret;
    477     }
    478     clear_l();
    479     return NO_ERROR;
    480 }
    481 
    482 status_t MediaPlayer::reset()
    483 {
    484     LOGV("reset");
    485     Mutex::Autolock _l(mLock);
    486     return reset_l();
    487 }
    488 
    489 status_t MediaPlayer::setAudioStreamType(int type)
    490 {
    491     LOGV("MediaPlayer::setAudioStreamType");
    492     Mutex::Autolock _l(mLock);
    493     if (mStreamType == type) return NO_ERROR;
    494     if (mCurrentState & ( MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED |
    495                 MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE ) ) {
    496         // Can't change the stream type after prepare
    497         LOGE("setAudioStream called in state %d", mCurrentState);
    498         return INVALID_OPERATION;
    499     }
    500     // cache
    501     mStreamType = type;
    502     return OK;
    503 }
    504 
    505 status_t MediaPlayer::setLooping(int loop)
    506 {
    507     LOGV("MediaPlayer::setLooping");
    508     Mutex::Autolock _l(mLock);
    509     mLoop = (loop != 0);
    510     if (mPlayer != 0) {
    511         return mPlayer->setLooping(loop);
    512     }
    513     return OK;
    514 }
    515 
    516 bool MediaPlayer::isLooping() {
    517     LOGV("isLooping");
    518     Mutex::Autolock _l(mLock);
    519     if (mPlayer != 0) {
    520         return mLoop;
    521     }
    522     LOGV("isLooping: no active player");
    523     return false;
    524 }
    525 
    526 status_t MediaPlayer::setVolume(float leftVolume, float rightVolume)
    527 {
    528     LOGV("MediaPlayer::setVolume(%f, %f)", leftVolume, rightVolume);
    529     Mutex::Autolock _l(mLock);
    530     mLeftVolume = leftVolume;
    531     mRightVolume = rightVolume;
    532     if (mPlayer != 0) {
    533         return mPlayer->setVolume(leftVolume, rightVolume);
    534     }
    535     return OK;
    536 }
    537 
    538 status_t MediaPlayer::setAudioSessionId(int sessionId)
    539 {
    540     LOGV("MediaPlayer::setAudioSessionId(%d)", sessionId);
    541     Mutex::Autolock _l(mLock);
    542     if (!(mCurrentState & MEDIA_PLAYER_IDLE)) {
    543         LOGE("setAudioSessionId called in state %d", mCurrentState);
    544         return INVALID_OPERATION;
    545     }
    546     if (sessionId < 0) {
    547         return BAD_VALUE;
    548     }
    549     if (sessionId != mAudioSessionId) {
    550       AudioSystem::releaseAudioSessionId(mAudioSessionId);
    551       AudioSystem::acquireAudioSessionId(sessionId);
    552       mAudioSessionId = sessionId;
    553     }
    554     return NO_ERROR;
    555 }
    556 
    557 int MediaPlayer::getAudioSessionId()
    558 {
    559     Mutex::Autolock _l(mLock);
    560     return mAudioSessionId;
    561 }
    562 
    563 status_t MediaPlayer::setAuxEffectSendLevel(float level)
    564 {
    565     LOGV("MediaPlayer::setAuxEffectSendLevel(%f)", level);
    566     Mutex::Autolock _l(mLock);
    567     mSendLevel = level;
    568     if (mPlayer != 0) {
    569         return mPlayer->setAuxEffectSendLevel(level);
    570     }
    571     return OK;
    572 }
    573 
    574 status_t MediaPlayer::attachAuxEffect(int effectId)
    575 {
    576     LOGV("MediaPlayer::attachAuxEffect(%d)", effectId);
    577     Mutex::Autolock _l(mLock);
    578     if (mPlayer == 0 ||
    579         (mCurrentState & MEDIA_PLAYER_IDLE) ||
    580         (mCurrentState == MEDIA_PLAYER_STATE_ERROR )) {
    581         LOGE("attachAuxEffect called in state %d", mCurrentState);
    582         return INVALID_OPERATION;
    583     }
    584 
    585     return mPlayer->attachAuxEffect(effectId);
    586 }
    587 
    588 status_t MediaPlayer::setParameter(int key, const Parcel& request)
    589 {
    590     LOGV("MediaPlayer::setParameter(%d)", key);
    591     Mutex::Autolock _l(mLock);
    592     if (mPlayer != NULL) {
    593         return  mPlayer->setParameter(key, request);
    594     }
    595     LOGV("setParameter: no active player");
    596     return INVALID_OPERATION;
    597 }
    598 
    599 status_t MediaPlayer::getParameter(int key, Parcel *reply)
    600 {
    601     LOGV("MediaPlayer::getParameter(%d)", key);
    602     Mutex::Autolock _l(mLock);
    603     if (mPlayer != NULL) {
    604          return  mPlayer->getParameter(key, reply);
    605     }
    606     LOGV("getParameter: no active player");
    607     return INVALID_OPERATION;
    608 }
    609 
    610 void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj)
    611 {
    612     LOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
    613     bool send = true;
    614     bool locked = false;
    615 
    616     // TODO: In the future, we might be on the same thread if the app is
    617     // running in the same process as the media server. In that case,
    618     // this will deadlock.
    619     //
    620     // The threadId hack below works around this for the care of prepare
    621     // and seekTo within the same process.
    622     // FIXME: Remember, this is a hack, it's not even a hack that is applied
    623     // consistently for all use-cases, this needs to be revisited.
    624      if (mLockThreadId != getThreadId()) {
    625         mLock.lock();
    626         locked = true;
    627     }
    628 
    629     // Allows calls from JNI in idle state to notify errors
    630     if (!(msg == MEDIA_ERROR && mCurrentState == MEDIA_PLAYER_IDLE) && mPlayer == 0) {
    631         LOGV("notify(%d, %d, %d) callback on disconnected mediaplayer", msg, ext1, ext2);
    632         if (locked) mLock.unlock();   // release the lock when done.
    633         return;
    634     }
    635 
    636     switch (msg) {
    637     case MEDIA_NOP: // interface test message
    638         break;
    639     case MEDIA_PREPARED:
    640         LOGV("prepared");
    641         mCurrentState = MEDIA_PLAYER_PREPARED;
    642         if (mPrepareSync) {
    643             LOGV("signal application thread");
    644             mPrepareSync = false;
    645             mPrepareStatus = NO_ERROR;
    646             mSignal.signal();
    647         }
    648         break;
    649     case MEDIA_PLAYBACK_COMPLETE:
    650         LOGV("playback complete");
    651         if (mCurrentState == MEDIA_PLAYER_IDLE) {
    652             LOGE("playback complete in idle state");
    653         }
    654         if (!mLoop) {
    655             mCurrentState = MEDIA_PLAYER_PLAYBACK_COMPLETE;
    656         }
    657         break;
    658     case MEDIA_ERROR:
    659         // Always log errors.
    660         // ext1: Media framework error code.
    661         // ext2: Implementation dependant error code.
    662         LOGE("error (%d, %d)", ext1, ext2);
    663         mCurrentState = MEDIA_PLAYER_STATE_ERROR;
    664         if (mPrepareSync)
    665         {
    666             LOGV("signal application thread");
    667             mPrepareSync = false;
    668             mPrepareStatus = ext1;
    669             mSignal.signal();
    670             send = false;
    671         }
    672         break;
    673     case MEDIA_INFO:
    674         // ext1: Media framework error code.
    675         // ext2: Implementation dependant error code.
    676         if (ext1 != MEDIA_INFO_VIDEO_TRACK_LAGGING) {
    677             LOGW("info/warning (%d, %d)", ext1, ext2);
    678         }
    679         break;
    680     case MEDIA_SEEK_COMPLETE:
    681         LOGV("Received seek complete");
    682         if (mSeekPosition != mCurrentPosition) {
    683             LOGV("Executing queued seekTo(%d)", mSeekPosition);
    684             mSeekPosition = -1;
    685             seekTo_l(mCurrentPosition);
    686         }
    687         else {
    688             LOGV("All seeks complete - return to regularly scheduled program");
    689             mCurrentPosition = mSeekPosition = -1;
    690         }
    691         break;
    692     case MEDIA_BUFFERING_UPDATE:
    693         LOGV("buffering %d", ext1);
    694         break;
    695     case MEDIA_SET_VIDEO_SIZE:
    696         LOGV("New video size %d x %d", ext1, ext2);
    697         mVideoWidth = ext1;
    698         mVideoHeight = ext2;
    699         break;
    700     case MEDIA_TIMED_TEXT:
    701         LOGV("Received timed text message");
    702         break;
    703     default:
    704         LOGV("unrecognized message: (%d, %d, %d)", msg, ext1, ext2);
    705         break;
    706     }
    707 
    708     sp<MediaPlayerListener> listener = mListener;
    709     if (locked) mLock.unlock();
    710 
    711     // this prevents re-entrant calls into client code
    712     if ((listener != 0) && send) {
    713         Mutex::Autolock _l(mNotifyLock);
    714         LOGV("callback application");
    715         listener->notify(msg, ext1, ext2, obj);
    716         LOGV("back from callback");
    717     }
    718 }
    719 
    720 /*static*/ sp<IMemory> MediaPlayer::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
    721 {
    722     LOGV("decode(%s)", url);
    723     sp<IMemory> p;
    724     const sp<IMediaPlayerService>& service = getMediaPlayerService();
    725     if (service != 0) {
    726         p = service->decode(url, pSampleRate, pNumChannels, pFormat);
    727     } else {
    728         LOGE("Unable to locate media service");
    729     }
    730     return p;
    731 
    732 }
    733 
    734 void MediaPlayer::died()
    735 {
    736     LOGV("died");
    737     notify(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED, 0);
    738 }
    739 
    740 /*static*/ sp<IMemory> MediaPlayer::decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
    741 {
    742     LOGV("decode(%d, %lld, %lld)", fd, offset, length);
    743     sp<IMemory> p;
    744     const sp<IMediaPlayerService>& service = getMediaPlayerService();
    745     if (service != 0) {
    746         p = service->decode(fd, offset, length, pSampleRate, pNumChannels, pFormat);
    747     } else {
    748         LOGE("Unable to locate media service");
    749     }
    750     return p;
    751 
    752 }
    753 
    754 }; // namespace android
    755