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