Home | History | Annotate | Download | only in android
      1 /*
      2  * Copyright (C) 2011 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 USE_LOG SLAndroidLogLevel_Verbose
     18 
     19 #include "sles_allinclusive.h"
     20 #include "android_GenericMediaPlayer.h"
     21 
     22 #include <media/IMediaPlayerService.h>
     23 #include <surfaceflinger/ISurfaceComposer.h>
     24 #include <surfaceflinger/SurfaceComposerClient.h>
     25 #include <media/stagefright/foundation/ADebug.h>
     26 
     27 // default delay in Us used when reposting an event when the player is not ready to accept
     28 // the command yet. This is for instance used when seeking on a MediaPlayer that's still preparing
     29 #define DEFAULT_COMMAND_DELAY_FOR_REPOST_US (100*1000) // 100ms
     30 
     31 // table of prefixes for known distant protocols; these are immediately dispatched to mediaserver
     32 static const char* const kDistantProtocolPrefix[] = { "http://", "https://", "rtsp://"};
     33 #define NB_DISTANT_PROTOCOLS (sizeof(kDistantProtocolPrefix)/sizeof(kDistantProtocolPrefix[0]))
     34 
     35 // is the specified URI a known distant protocol?
     36 bool isDistantProtocol(const char *uri)
     37 {
     38     for (unsigned int i = 0; i < NB_DISTANT_PROTOCOLS; i++) {
     39         if (!strncasecmp(uri, kDistantProtocolPrefix[i], strlen(kDistantProtocolPrefix[i]))) {
     40             return true;
     41         }
     42     }
     43     return false;
     44 }
     45 
     46 namespace android {
     47 
     48 //--------------------------------------------------------------------------------------------------
     49 MediaPlayerNotificationClient::MediaPlayerNotificationClient(GenericMediaPlayer* gmp) :
     50     mGenericMediaPlayer(gmp),
     51     mPlayerPrepared(PREPARE_NOT_STARTED)
     52 {
     53     SL_LOGV("MediaPlayerNotificationClient::MediaPlayerNotificationClient()");
     54 }
     55 
     56 MediaPlayerNotificationClient::~MediaPlayerNotificationClient() {
     57     SL_LOGV("MediaPlayerNotificationClient::~MediaPlayerNotificationClient()");
     58 }
     59 
     60 // Map a MEDIA_* enum to a string
     61 static const char *media_to_string(int msg)
     62 {
     63     switch (msg) {
     64 #define _(x) case MEDIA_##x: return "MEDIA_" #x;
     65       _(PREPARED)
     66       _(SET_VIDEO_SIZE)
     67       _(SEEK_COMPLETE)
     68       _(PLAYBACK_COMPLETE)
     69       _(BUFFERING_UPDATE)
     70       _(ERROR)
     71       _(NOP)
     72       _(TIMED_TEXT)
     73       _(INFO)
     74 #undef _
     75     default:
     76         return NULL;
     77     }
     78 }
     79 
     80 //--------------------------------------------------
     81 // IMediaPlayerClient implementation
     82 void MediaPlayerNotificationClient::notify(int msg, int ext1, int ext2, const Parcel *obj) {
     83     SL_LOGV("MediaPlayerNotificationClient::notify(msg=%s (%d), ext1=%d, ext2=%d)",
     84             media_to_string(msg), msg, ext1, ext2);
     85 
     86     sp<GenericMediaPlayer> genericMediaPlayer(mGenericMediaPlayer.promote());
     87     if (genericMediaPlayer == NULL) {
     88         SL_LOGW("MediaPlayerNotificationClient::notify after GenericMediaPlayer destroyed");
     89         return;
     90     }
     91 
     92     switch (msg) {
     93       case MEDIA_PREPARED:
     94         {
     95         Mutex::Autolock _l(mLock);
     96         if (PREPARE_IN_PROGRESS == mPlayerPrepared) {
     97             mPlayerPrepared = PREPARE_COMPLETED_SUCCESSFULLY;
     98             mPlayerPreparedCondition.signal();
     99         } else {
    100             SL_LOGE("Unexpected MEDIA_PREPARED");
    101         }
    102         }
    103         break;
    104 
    105       case MEDIA_SET_VIDEO_SIZE:
    106         // only send video size updates if the player was flagged as having video, to avoid
    107         // sending video size updates of (0,0)
    108         // We're running on a different thread than genericMediaPlayer's ALooper thread,
    109         // so it would normally be racy to access fields within genericMediaPlayer.
    110         // But in this case mHasVideo is const, so it is safe to access.
    111         // Or alternatively, we could notify unconditionally and let it decide whether to handle.
    112         if (genericMediaPlayer->mHasVideo) {
    113             genericMediaPlayer->notify(PLAYEREVENT_VIDEO_SIZE_UPDATE,
    114                     (int32_t)ext1, (int32_t)ext2, true /*async*/);
    115         }
    116         break;
    117 
    118       case MEDIA_SEEK_COMPLETE:
    119         genericMediaPlayer->seekComplete();
    120         break;
    121 
    122       case MEDIA_PLAYBACK_COMPLETE:
    123         genericMediaPlayer->notify(PLAYEREVENT_ENDOFSTREAM, 1, true /*async*/);
    124         break;
    125 
    126       case MEDIA_BUFFERING_UPDATE:
    127         // values received from Android framework for buffer fill level use percent,
    128         //   while SL/XA use permille, so does GenericPlayer
    129         genericMediaPlayer->bufferingUpdate(ext1 * 10 /*fillLevelPerMille*/);
    130         break;
    131 
    132       case MEDIA_ERROR:
    133         {
    134         Mutex::Autolock _l(mLock);
    135         if (PREPARE_IN_PROGRESS == mPlayerPrepared) {
    136             mPlayerPrepared = PREPARE_COMPLETED_UNSUCCESSFULLY;
    137             mPlayerPreparedCondition.signal();
    138         } else {
    139             // inform client of errors after preparation
    140             genericMediaPlayer->notify(PLAYEREVENT_ERRORAFTERPREPARE, ext1, true /*async*/);
    141         }
    142         }
    143         break;
    144 
    145       case MEDIA_NOP:
    146       case MEDIA_TIMED_TEXT:
    147       case MEDIA_INFO:
    148         break;
    149 
    150       default: { }
    151     }
    152 
    153 }
    154 
    155 //--------------------------------------------------
    156 void MediaPlayerNotificationClient::beforePrepare()
    157 {
    158     Mutex::Autolock _l(mLock);
    159     assert(mPlayerPrepared == PREPARE_NOT_STARTED);
    160     mPlayerPrepared = PREPARE_IN_PROGRESS;
    161 }
    162 
    163 //--------------------------------------------------
    164 bool MediaPlayerNotificationClient::blockUntilPlayerPrepared() {
    165     Mutex::Autolock _l(mLock);
    166     assert(mPlayerPrepared != PREPARE_NOT_STARTED);
    167     while (mPlayerPrepared == PREPARE_IN_PROGRESS) {
    168         mPlayerPreparedCondition.wait(mLock);
    169     }
    170     assert(mPlayerPrepared == PREPARE_COMPLETED_SUCCESSFULLY ||
    171             mPlayerPrepared == PREPARE_COMPLETED_UNSUCCESSFULLY);
    172     return mPlayerPrepared == PREPARE_COMPLETED_SUCCESSFULLY;
    173 }
    174 
    175 //--------------------------------------------------------------------------------------------------
    176 GenericMediaPlayer::GenericMediaPlayer(const AudioPlayback_Parameters* params, bool hasVideo) :
    177     GenericPlayer(params),
    178     mHasVideo(hasVideo),
    179     mSeekTimeMsec(0),
    180     mVideoSurface(0),
    181     mVideoSurfaceTexture(0),
    182     mPlayer(0),
    183     mPlayerClient(new MediaPlayerNotificationClient(this))
    184 {
    185     SL_LOGD("GenericMediaPlayer::GenericMediaPlayer()");
    186 
    187 }
    188 
    189 GenericMediaPlayer::~GenericMediaPlayer() {
    190     SL_LOGD("GenericMediaPlayer::~GenericMediaPlayer()");
    191 }
    192 
    193 void GenericMediaPlayer::preDestroy() {
    194     // FIXME can't access mPlayer from outside the looper (no mutex!) so using mPreparedPlayer
    195     sp<IMediaPlayer> player;
    196     getPreparedPlayer(player);
    197     if (player != NULL) {
    198         player->stop();
    199         // causes CHECK failure in Nuplayer, but commented out in the subclass preDestroy
    200         // randomly causes a NPE in StagefrightPlayer, heap corruption, or app hang
    201         //player->setDataSource(NULL);
    202         player->setVideoSurface(NULL);
    203         player->disconnect();
    204         // release all references to the IMediaPlayer
    205         // FIXME illegal if not on looper
    206         //mPlayer.clear();
    207         {
    208             Mutex::Autolock _l(mPreparedPlayerLock);
    209             mPreparedPlayer.clear();
    210         }
    211     }
    212     GenericPlayer::preDestroy();
    213 }
    214 
    215 //--------------------------------------------------
    216 // overridden from GenericPlayer
    217 // pre-condition:
    218 //   msec != NULL
    219 // post-condition
    220 //   *msec ==
    221 //                  ANDROID_UNKNOWN_TIME if position is unknown at time of query,
    222 //               or the current MediaPlayer position
    223 void GenericMediaPlayer::getPositionMsec(int* msec) {
    224     SL_LOGD("GenericMediaPlayer::getPositionMsec()");
    225     sp<IMediaPlayer> player;
    226     getPreparedPlayer(player);
    227     // To avoid deadlock, directly call the MediaPlayer object
    228     if (player == 0 || player->getCurrentPosition(msec) != NO_ERROR) {
    229         *msec = ANDROID_UNKNOWN_TIME;
    230     }
    231 }
    232 
    233 //--------------------------------------------------
    234 void GenericMediaPlayer::setVideoSurface(const sp<Surface> &surface) {
    235     SL_LOGV("GenericMediaPlayer::setVideoSurface()");
    236     // FIXME bug - race condition, should do in looper
    237     if (mVideoSurface.get() == surface.get()) {
    238         return;
    239     }
    240     if ((mStateFlags & kFlagPrepared) && (mPlayer != 0)) {
    241         mPlayer->setVideoSurface(surface);
    242     }
    243     mVideoSurface = surface;
    244     mVideoSurfaceTexture = NULL;
    245 }
    246 
    247 void GenericMediaPlayer::setVideoSurfaceTexture(const sp<ISurfaceTexture> &surfaceTexture) {
    248     SL_LOGV("GenericMediaPlayer::setVideoSurfaceTexture()");
    249     // FIXME bug - race condition, should do in looper
    250     if (mVideoSurfaceTexture.get() == surfaceTexture.get()) {
    251         return;
    252     }
    253     if ((mStateFlags & kFlagPrepared) && (mPlayer != 0)) {
    254         mPlayer->setVideoSurfaceTexture(surfaceTexture);
    255     }
    256     mVideoSurfaceTexture = surfaceTexture;
    257     mVideoSurface = NULL;
    258 }
    259 
    260 
    261 //--------------------------------------------------
    262 // Event handlers
    263 
    264 // blocks until mPlayer is prepared
    265 void GenericMediaPlayer::onPrepare() {
    266     SL_LOGD("GenericMediaPlayer::onPrepare()");
    267     // Attempt to prepare at most once, and only if there is a MediaPlayer
    268     if (!(mStateFlags & (kFlagPrepared | kFlagPreparedUnsuccessfully)) && (mPlayer != 0)) {
    269         if (mHasVideo) {
    270             if (mVideoSurface != 0) {
    271                 mPlayer->setVideoSurface(mVideoSurface);
    272             } else if (mVideoSurfaceTexture != 0) {
    273                 mPlayer->setVideoSurfaceTexture(mVideoSurfaceTexture);
    274             }
    275         }
    276         mPlayer->setAudioStreamType(mPlaybackParams.streamType);
    277         mPlayerClient->beforePrepare();
    278         mPlayer->prepareAsync();
    279         if (mPlayerClient->blockUntilPlayerPrepared()) {
    280             mStateFlags |= kFlagPrepared;
    281             afterMediaPlayerPreparedSuccessfully();
    282         } else {
    283             mStateFlags |= kFlagPreparedUnsuccessfully;
    284         }
    285     }
    286     GenericPlayer::onPrepare();
    287     SL_LOGD("GenericMediaPlayer::onPrepare() done, mStateFlags=0x%x", mStateFlags);
    288 }
    289 
    290 
    291 void GenericMediaPlayer::onPlay() {
    292     SL_LOGD("GenericMediaPlayer::onPlay()");
    293     if (((mStateFlags & (kFlagPrepared | kFlagPlaying)) == kFlagPrepared) && (mPlayer != 0)) {
    294         mPlayer->start();
    295     }
    296     GenericPlayer::onPlay();
    297 }
    298 
    299 
    300 void GenericMediaPlayer::onPause() {
    301     SL_LOGD("GenericMediaPlayer::onPause()");
    302     if (!(~mStateFlags & (kFlagPrepared | kFlagPlaying)) && (mPlayer != 0)) {
    303         mPlayer->pause();
    304     }
    305     GenericPlayer::onPause();
    306 }
    307 
    308 
    309 void GenericMediaPlayer::onSeekComplete() {
    310     SL_LOGV("GenericMediaPlayer::onSeekComplete()");
    311     // did we initiate the seek?
    312     if (!(mStateFlags & kFlagSeeking)) {
    313         // no, are we looping?
    314         if (mStateFlags & kFlagLooping) {
    315             // yes, per OpenSL ES 1.0.1 and 1.1 do NOT report it to client
    316             // notify(PLAYEREVENT_ENDOFSTREAM, 1, true /*async*/);
    317         // no, well that's surprising, but it's probably just a benign race condition
    318         } else {
    319             SL_LOGW("Unexpected seek complete event ignored");
    320         }
    321     }
    322     GenericPlayer::onSeekComplete();
    323 }
    324 
    325 
    326 /**
    327  * pre-condition: WHATPARAM_SEEK_SEEKTIME_MS parameter value >= 0
    328  */
    329 void GenericMediaPlayer::onSeek(const sp<AMessage> &msg) {
    330     SL_LOGV("GenericMediaPlayer::onSeek");
    331     int64_t timeMsec = ANDROID_UNKNOWN_TIME;
    332     if (!msg->findInt64(WHATPARAM_SEEK_SEEKTIME_MS, &timeMsec)) {
    333         // invalid command, drop it
    334         return;
    335     }
    336     if ((mStateFlags & kFlagSeeking) && (timeMsec == mSeekTimeMsec) &&
    337             (timeMsec != ANDROID_UNKNOWN_TIME)) {
    338         // already seeking to the same non-unknown time, cancel this command
    339         return;
    340     } else if (mStateFlags & kFlagPreparedUnsuccessfully) {
    341         // discard seeks after unsuccessful prepare
    342     } else if (!(mStateFlags & kFlagPrepared)) {
    343         // we are not ready to accept a seek command at this time, retry later
    344         msg->post(DEFAULT_COMMAND_DELAY_FOR_REPOST_US);
    345     } else {
    346         if (mPlayer != 0) {
    347             mStateFlags |= kFlagSeeking;
    348             mSeekTimeMsec = (int32_t)timeMsec;
    349             // seek to unknown time is used by StreamPlayer after discontinuity
    350             if (timeMsec == ANDROID_UNKNOWN_TIME) {
    351                 // FIXME simulate a MEDIA_SEEK_COMPLETE event in 250 ms;
    352                 // this is a terrible hack to make up for mediaserver not sending one
    353                 (new AMessage(kWhatSeekComplete, id()))->post(250000);
    354             } else if (OK != mPlayer->seekTo(timeMsec)) {
    355                 mStateFlags &= ~kFlagSeeking;
    356                 mSeekTimeMsec = ANDROID_UNKNOWN_TIME;
    357             }
    358         }
    359     }
    360 }
    361 
    362 
    363 void GenericMediaPlayer::onLoop(const sp<AMessage> &msg) {
    364     SL_LOGV("GenericMediaPlayer::onLoop");
    365     int32_t loop = 0;
    366     if (msg->findInt32(WHATPARAM_LOOP_LOOPING, &loop)) {
    367         if (loop) {
    368             mStateFlags |= kFlagLooping;
    369         } else {
    370             mStateFlags &= ~kFlagLooping;
    371         }
    372         // if we have a MediaPlayer then tell it now, otherwise we'll tell it after it's created
    373         if (mPlayer != 0) {
    374             (void) mPlayer->setLooping(loop);
    375         }
    376     }
    377 }
    378 
    379 
    380 void GenericMediaPlayer::onVolumeUpdate() {
    381     SL_LOGD("GenericMediaPlayer::onVolumeUpdate()");
    382     // use settings lock to read the volume settings
    383     Mutex::Autolock _l(mSettingsLock);
    384     if (mPlayer != 0) {
    385         mPlayer->setVolume(mAndroidAudioLevels.mFinalVolume[0],
    386                 mAndroidAudioLevels.mFinalVolume[1]);
    387     }
    388 }
    389 
    390 
    391 void GenericMediaPlayer::onAttachAuxEffect(const sp<AMessage> &msg) {
    392     SL_LOGD("GenericMediaPlayer::onAttachAuxEffect()");
    393     int32_t effectId = 0;
    394     if (msg->findInt32(WHATPARAM_ATTACHAUXEFFECT, &effectId)) {
    395         if (mPlayer != 0) {
    396             status_t status;
    397             status = mPlayer->attachAuxEffect(effectId);
    398             // attachAuxEffect returns a status but we have no way to report it back to app
    399             (void) status;
    400         }
    401     }
    402 }
    403 
    404 
    405 void GenericMediaPlayer::onSetAuxEffectSendLevel(const sp<AMessage> &msg) {
    406     SL_LOGD("GenericMediaPlayer::onSetAuxEffectSendLevel()");
    407     float level = 0.0f;
    408     if (msg->findFloat(WHATPARAM_SETAUXEFFECTSENDLEVEL, &level)) {
    409         if (mPlayer != 0) {
    410             status_t status;
    411             status = mPlayer->setAuxEffectSendLevel(level);
    412             // setAuxEffectSendLevel returns a status but we have no way to report it back to app
    413             (void) status;
    414         }
    415     }
    416 }
    417 
    418 
    419 void GenericMediaPlayer::onBufferingUpdate(const sp<AMessage> &msg) {
    420     int32_t fillLevel = 0;
    421     if (msg->findInt32(WHATPARAM_BUFFERING_UPDATE, &fillLevel)) {
    422         SL_LOGD("GenericMediaPlayer::onBufferingUpdate(fillLevel=%d)", fillLevel);
    423 
    424         Mutex::Autolock _l(mSettingsLock);
    425         mCacheFill = fillLevel;
    426         // handle cache fill update
    427         if (mCacheFill - mLastNotifiedCacheFill >= mCacheFillNotifThreshold) {
    428             notifyCacheFill();
    429         }
    430         // handle prefetch status update
    431         //   compute how much time ahead of position is buffered
    432         int durationMsec, positionMsec = -1;
    433         if ((mStateFlags & kFlagPrepared) && (mPlayer != 0)
    434                 && (OK == mPlayer->getDuration(&durationMsec))
    435                         && (OK == mPlayer->getCurrentPosition(&positionMsec))) {
    436             if ((-1 != durationMsec) && (-1 != positionMsec)) {
    437                 // evaluate prefetch status based on buffer time thresholds
    438                 int64_t bufferedDurationMsec = (durationMsec * fillLevel / 100) - positionMsec;
    439                 CacheStatus_t newCacheStatus = mCacheStatus;
    440                 if (bufferedDurationMsec > DURATION_CACHED_HIGH_MS) {
    441                     newCacheStatus = kStatusHigh;
    442                 } else if (bufferedDurationMsec > DURATION_CACHED_MED_MS) {
    443                     newCacheStatus = kStatusEnough;
    444                 } else if (bufferedDurationMsec > DURATION_CACHED_LOW_MS) {
    445                     newCacheStatus = kStatusIntermediate;
    446                 } else if (bufferedDurationMsec == 0) {
    447                     newCacheStatus = kStatusEmpty;
    448                 } else {
    449                     newCacheStatus = kStatusLow;
    450                 }
    451 
    452                 if (newCacheStatus != mCacheStatus) {
    453                     mCacheStatus = newCacheStatus;
    454                     notifyStatus();
    455                 }
    456             }
    457         }
    458     } else {
    459         SL_LOGV("GenericMediaPlayer::onBufferingUpdate(fillLevel=unknown)");
    460     }
    461 }
    462 
    463 
    464 //--------------------------------------------------
    465 /**
    466  * called from GenericMediaPlayer::onPrepare after the MediaPlayer mPlayer is prepared successfully
    467  * pre-conditions:
    468  *  mPlayer != 0
    469  *  mPlayer is prepared successfully
    470  */
    471 void GenericMediaPlayer::afterMediaPlayerPreparedSuccessfully() {
    472     SL_LOGV("GenericMediaPlayer::afterMediaPlayerPrepared()");
    473     assert(mPlayer != 0);
    474     assert(mStateFlags & kFlagPrepared);
    475     // Mark this player as prepared successfully, so safe to directly call getCurrentPosition
    476     {
    477         Mutex::Autolock _l(mPreparedPlayerLock);
    478         assert(mPreparedPlayer == 0);
    479         mPreparedPlayer = mPlayer;
    480     }
    481     // retrieve channel count
    482     int32_t channelCount;
    483     Parcel *reply = new Parcel();
    484     status_t status = mPlayer->getParameter(KEY_PARAMETER_AUDIO_CHANNEL_COUNT, reply);
    485     if (status == NO_ERROR) {
    486         channelCount = reply->readInt32();
    487     } else {
    488         // FIXME MPEG-2 TS doesn't yet implement this key, so default to stereo
    489         channelCount = 2;
    490     }
    491     if (UNKNOWN_NUMCHANNELS != channelCount) {
    492         // now that we know the channel count, re-calculate the volumes
    493         notify(PLAYEREVENT_CHANNEL_COUNT, channelCount, true /*async*/);
    494     } else {
    495         LOGW("channel count is still unknown after prepare");
    496     }
    497     delete reply;
    498     // retrieve duration
    499     {
    500         Mutex::Autolock _l(mSettingsLock);
    501         int msec = 0;
    502         if (OK == mPlayer->getDuration(&msec)) {
    503             mDurationMsec = msec;
    504         }
    505     }
    506     // now that we have a MediaPlayer, set the looping flag
    507     if (mStateFlags & kFlagLooping) {
    508         (void) mPlayer->setLooping(1);
    509     }
    510     // when the MediaPlayer mPlayer is prepared, there is "sufficient data" in the playback buffers
    511     // if the data source was local, and the buffers are considered full so we need to notify that
    512     bool isLocalSource = true;
    513     if (kDataLocatorUri == mDataLocatorType) {
    514         isLocalSource = !isDistantProtocol(mDataLocator.uriRef);
    515     }
    516     if (isLocalSource) {
    517         SL_LOGD("media player prepared on local source");
    518         {
    519             Mutex::Autolock _l(mSettingsLock);
    520             mCacheStatus = kStatusHigh;
    521             mCacheFill = 1000;
    522             notifyStatus();
    523             notifyCacheFill();
    524         }
    525     } else {
    526         SL_LOGD("media player prepared on non-local source");
    527     }
    528 }
    529 
    530 
    531 //--------------------------------------------------
    532 // If player is prepared successfully, set output parameter to that reference, otherwise NULL
    533 void GenericMediaPlayer::getPreparedPlayer(sp<IMediaPlayer> &preparedPlayer)
    534 {
    535     Mutex::Autolock _l(mPreparedPlayerLock);
    536     preparedPlayer = mPreparedPlayer;
    537 }
    538 
    539 } // namespace android
    540