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