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     mVideoSurfaceTexture(0),
    181     mPlayer(0),
    182     mPlayerClient(new MediaPlayerNotificationClient(this)),
    183     mPlayerDeathNotifier(new MediaPlayerDeathNotifier(mPlayerClient))
    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->setVideoSurfaceTexture(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::setVideoSurfaceTexture(const sp<ISurfaceTexture> &surfaceTexture) {
    235     SL_LOGV("GenericMediaPlayer::setVideoSurfaceTexture()");
    236     // FIXME bug - race condition, should do in looper
    237     if (mVideoSurfaceTexture.get() == surfaceTexture.get()) {
    238         return;
    239     }
    240     if ((mStateFlags & kFlagPrepared) && (mPlayer != 0)) {
    241         mPlayer->setVideoSurfaceTexture(surfaceTexture);
    242     }
    243     mVideoSurfaceTexture = surfaceTexture;
    244 }
    245 
    246 
    247 //--------------------------------------------------
    248 // Event handlers
    249 
    250 // blocks until mPlayer is prepared
    251 void GenericMediaPlayer::onPrepare() {
    252     SL_LOGD("GenericMediaPlayer::onPrepare()");
    253     // Attempt to prepare at most once, and only if there is a MediaPlayer
    254     if (!(mStateFlags & (kFlagPrepared | kFlagPreparedUnsuccessfully)) && (mPlayer != 0)) {
    255         if (mHasVideo) {
    256             if (mVideoSurfaceTexture != 0) {
    257                 mPlayer->setVideoSurfaceTexture(mVideoSurfaceTexture);
    258             }
    259         }
    260         mPlayer->setAudioStreamType(mPlaybackParams.streamType);
    261         mPlayerClient->beforePrepare();
    262         mPlayer->prepareAsync();
    263         if (mPlayerClient->blockUntilPlayerPrepared()) {
    264             mStateFlags |= kFlagPrepared;
    265             afterMediaPlayerPreparedSuccessfully();
    266         } else {
    267             mStateFlags |= kFlagPreparedUnsuccessfully;
    268         }
    269     }
    270     GenericPlayer::onPrepare();
    271     SL_LOGD("GenericMediaPlayer::onPrepare() done, mStateFlags=0x%x", mStateFlags);
    272 }
    273 
    274 
    275 void GenericMediaPlayer::onPlay() {
    276     SL_LOGD("GenericMediaPlayer::onPlay()");
    277     if (((mStateFlags & (kFlagPrepared | kFlagPlaying)) == kFlagPrepared) && (mPlayer != 0)) {
    278         mPlayer->start();
    279     }
    280     GenericPlayer::onPlay();
    281 }
    282 
    283 
    284 void GenericMediaPlayer::onPause() {
    285     SL_LOGD("GenericMediaPlayer::onPause()");
    286     if (!(~mStateFlags & (kFlagPrepared | kFlagPlaying)) && (mPlayer != 0)) {
    287         mPlayer->pause();
    288     }
    289     GenericPlayer::onPause();
    290 }
    291 
    292 
    293 void GenericMediaPlayer::onSeekComplete() {
    294     SL_LOGV("GenericMediaPlayer::onSeekComplete()");
    295     // did we initiate the seek?
    296     if (!(mStateFlags & kFlagSeeking)) {
    297         // no, are we looping?
    298         if (mStateFlags & kFlagLooping) {
    299             // yes, per OpenSL ES 1.0.1 and 1.1 do NOT report it to client
    300             // notify(PLAYEREVENT_ENDOFSTREAM, 1, true /*async*/);
    301         // no, well that's surprising, but it's probably just a benign race condition
    302         } else {
    303             SL_LOGW("Unexpected seek complete event ignored");
    304         }
    305     }
    306     GenericPlayer::onSeekComplete();
    307 }
    308 
    309 
    310 /**
    311  * pre-condition: WHATPARAM_SEEK_SEEKTIME_MS parameter value >= 0
    312  */
    313 void GenericMediaPlayer::onSeek(const sp<AMessage> &msg) {
    314     SL_LOGV("GenericMediaPlayer::onSeek");
    315     int64_t timeMsec = ANDROID_UNKNOWN_TIME;
    316     if (!msg->findInt64(WHATPARAM_SEEK_SEEKTIME_MS, &timeMsec)) {
    317         // invalid command, drop it
    318         return;
    319     }
    320     if ((mStateFlags & kFlagSeeking) && (timeMsec == mSeekTimeMsec) &&
    321             (timeMsec != ANDROID_UNKNOWN_TIME)) {
    322         // already seeking to the same non-unknown time, cancel this command
    323         return;
    324     } else if (mStateFlags & kFlagPreparedUnsuccessfully) {
    325         // discard seeks after unsuccessful prepare
    326     } else if (!(mStateFlags & kFlagPrepared)) {
    327         // we are not ready to accept a seek command at this time, retry later
    328         msg->post(DEFAULT_COMMAND_DELAY_FOR_REPOST_US);
    329     } else {
    330         if (mPlayer != 0) {
    331             mStateFlags |= kFlagSeeking;
    332             mSeekTimeMsec = (int32_t)timeMsec;
    333             // seek to unknown time is used by StreamPlayer after discontinuity
    334             if (timeMsec == ANDROID_UNKNOWN_TIME) {
    335                 // FIXME simulate a MEDIA_SEEK_COMPLETE event in 250 ms;
    336                 // this is a terrible hack to make up for mediaserver not sending one
    337                 (new AMessage(kWhatSeekComplete, id()))->post(250000);
    338             } else if (OK != mPlayer->seekTo(timeMsec)) {
    339                 mStateFlags &= ~kFlagSeeking;
    340                 mSeekTimeMsec = ANDROID_UNKNOWN_TIME;
    341             }
    342         }
    343     }
    344 }
    345 
    346 
    347 void GenericMediaPlayer::onLoop(const sp<AMessage> &msg) {
    348     SL_LOGV("GenericMediaPlayer::onLoop");
    349     int32_t loop = 0;
    350     if (msg->findInt32(WHATPARAM_LOOP_LOOPING, &loop)) {
    351         if (loop) {
    352             mStateFlags |= kFlagLooping;
    353         } else {
    354             mStateFlags &= ~kFlagLooping;
    355         }
    356         // if we have a MediaPlayer then tell it now, otherwise we'll tell it after it's created
    357         if (mPlayer != 0) {
    358             (void) mPlayer->setLooping(loop);
    359         }
    360     }
    361 }
    362 
    363 
    364 void GenericMediaPlayer::onVolumeUpdate() {
    365     SL_LOGD("GenericMediaPlayer::onVolumeUpdate()");
    366     // use settings lock to read the volume settings
    367     Mutex::Autolock _l(mSettingsLock);
    368     if (mPlayer != 0) {
    369         mPlayer->setVolume(mAndroidAudioLevels.mFinalVolume[0],
    370                 mAndroidAudioLevels.mFinalVolume[1]);
    371     }
    372 }
    373 
    374 
    375 void GenericMediaPlayer::onAttachAuxEffect(const sp<AMessage> &msg) {
    376     SL_LOGD("GenericMediaPlayer::onAttachAuxEffect()");
    377     int32_t effectId = 0;
    378     if (msg->findInt32(WHATPARAM_ATTACHAUXEFFECT, &effectId)) {
    379         if (mPlayer != 0) {
    380             status_t status;
    381             status = mPlayer->attachAuxEffect(effectId);
    382             // attachAuxEffect returns a status but we have no way to report it back to app
    383             (void) status;
    384         }
    385     }
    386 }
    387 
    388 
    389 void GenericMediaPlayer::onSetAuxEffectSendLevel(const sp<AMessage> &msg) {
    390     SL_LOGD("GenericMediaPlayer::onSetAuxEffectSendLevel()");
    391     float level = 0.0f;
    392     if (msg->findFloat(WHATPARAM_SETAUXEFFECTSENDLEVEL, &level)) {
    393         if (mPlayer != 0) {
    394             status_t status;
    395             status = mPlayer->setAuxEffectSendLevel(level);
    396             // setAuxEffectSendLevel returns a status but we have no way to report it back to app
    397             (void) status;
    398         }
    399     }
    400 }
    401 
    402 
    403 void GenericMediaPlayer::onBufferingUpdate(const sp<AMessage> &msg) {
    404     int32_t fillLevel = 0;
    405     if (msg->findInt32(WHATPARAM_BUFFERING_UPDATE, &fillLevel)) {
    406         SL_LOGD("GenericMediaPlayer::onBufferingUpdate(fillLevel=%d)", fillLevel);
    407 
    408         Mutex::Autolock _l(mSettingsLock);
    409         mCacheFill = fillLevel;
    410         // handle cache fill update
    411         if (mCacheFill - mLastNotifiedCacheFill >= mCacheFillNotifThreshold) {
    412             notifyCacheFill();
    413         }
    414         // handle prefetch status update
    415         //   compute how much time ahead of position is buffered
    416         int durationMsec, positionMsec = -1;
    417         if ((mStateFlags & kFlagPrepared) && (mPlayer != 0)
    418                 && (OK == mPlayer->getDuration(&durationMsec))
    419                         && (OK == mPlayer->getCurrentPosition(&positionMsec))) {
    420             if ((-1 != durationMsec) && (-1 != positionMsec)) {
    421                 // evaluate prefetch status based on buffer time thresholds
    422                 int64_t bufferedDurationMsec = (durationMsec * fillLevel / 100) - positionMsec;
    423                 CacheStatus_t newCacheStatus = mCacheStatus;
    424                 if (bufferedDurationMsec > DURATION_CACHED_HIGH_MS) {
    425                     newCacheStatus = kStatusHigh;
    426                 } else if (bufferedDurationMsec > DURATION_CACHED_MED_MS) {
    427                     newCacheStatus = kStatusEnough;
    428                 } else if (bufferedDurationMsec > DURATION_CACHED_LOW_MS) {
    429                     newCacheStatus = kStatusIntermediate;
    430                 } else if (bufferedDurationMsec == 0) {
    431                     newCacheStatus = kStatusEmpty;
    432                 } else {
    433                     newCacheStatus = kStatusLow;
    434                 }
    435 
    436                 if (newCacheStatus != mCacheStatus) {
    437                     mCacheStatus = newCacheStatus;
    438                     notifyStatus();
    439                 }
    440             }
    441         }
    442     } else {
    443         SL_LOGV("GenericMediaPlayer::onBufferingUpdate(fillLevel=unknown)");
    444     }
    445 }
    446 
    447 
    448 //--------------------------------------------------
    449 /**
    450  * called from GenericMediaPlayer::onPrepare after the MediaPlayer mPlayer is prepared successfully
    451  * pre-conditions:
    452  *  mPlayer != 0
    453  *  mPlayer is prepared successfully
    454  */
    455 void GenericMediaPlayer::afterMediaPlayerPreparedSuccessfully() {
    456     SL_LOGV("GenericMediaPlayer::afterMediaPlayerPrepared()");
    457     assert(mPlayer != 0);
    458     assert(mStateFlags & kFlagPrepared);
    459     // Mark this player as prepared successfully, so safe to directly call getCurrentPosition
    460     {
    461         Mutex::Autolock _l(mPreparedPlayerLock);
    462         assert(mPreparedPlayer == 0);
    463         mPreparedPlayer = mPlayer;
    464     }
    465     // retrieve channel count
    466     int32_t channelCount;
    467     Parcel *reply = new Parcel();
    468     status_t status = mPlayer->getParameter(KEY_PARAMETER_AUDIO_CHANNEL_COUNT, reply);
    469     if (status == NO_ERROR) {
    470         channelCount = reply->readInt32();
    471     } else {
    472         // FIXME MPEG-2 TS doesn't yet implement this key, so default to stereo
    473         channelCount = 2;
    474     }
    475     if (UNKNOWN_NUMCHANNELS != channelCount) {
    476         // now that we know the channel count, re-calculate the volumes
    477         notify(PLAYEREVENT_CHANNEL_COUNT, channelCount, true /*async*/);
    478     } else {
    479         LOGW("channel count is still unknown after prepare");
    480     }
    481     delete reply;
    482     // retrieve duration
    483     {
    484         int msec = 0;
    485         if (OK == mPlayer->getDuration(&msec)) {
    486             Mutex::Autolock _l(mSettingsLock);
    487             mDurationMsec = msec;
    488         }
    489     }
    490     // now that we have a MediaPlayer, set the looping flag
    491     if (mStateFlags & kFlagLooping) {
    492         (void) mPlayer->setLooping(1);
    493     }
    494     // when the MediaPlayer mPlayer is prepared, there is "sufficient data" in the playback buffers
    495     // if the data source was local, and the buffers are considered full so we need to notify that
    496     bool isLocalSource = true;
    497     if (kDataLocatorUri == mDataLocatorType) {
    498         isLocalSource = !isDistantProtocol(mDataLocator.uriRef);
    499     }
    500     if (isLocalSource) {
    501         SL_LOGD("media player prepared on local source");
    502         {
    503             Mutex::Autolock _l(mSettingsLock);
    504             mCacheStatus = kStatusHigh;
    505             mCacheFill = 1000;
    506             notifyStatus();
    507             notifyCacheFill();
    508         }
    509     } else {
    510         SL_LOGD("media player prepared on non-local source");
    511     }
    512 }
    513 
    514 
    515 //--------------------------------------------------
    516 // If player is prepared successfully, set output parameter to that reference, otherwise NULL
    517 void GenericMediaPlayer::getPreparedPlayer(sp<IMediaPlayer> &preparedPlayer)
    518 {
    519     Mutex::Autolock _l(mPreparedPlayerLock);
    520     preparedPlayer = mPreparedPlayer;
    521 }
    522 
    523 } // namespace android
    524