Home | History | Annotate | Download | only in android
      1 /*
      2  * Copyright (C) 2010 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 #include "sles_allinclusive.h"
     18 #include "utils/RefBase.h"
     19 #include "android_prompts.h"
     20 // LocAVPlayer and StreamPlayer derive from GenericMediaPlayer,
     21 //    so no need to #include "android_GenericMediaPlayer.h"
     22 #include "android_LocAVPlayer.h"
     23 #include "android_StreamPlayer.h"
     24 
     25 
     26 //-----------------------------------------------------------------------------
     27 static void player_handleMediaPlayerEventNotifications(int event, int data1, int data2, void* user)
     28 {
     29 
     30     // FIXME This code is derived from similar code in sfplayer_handlePrefetchEvent.  The two
     31     // versions are quite similar, but still different enough that they need to be separate.
     32     // At some point they should be re-factored and merged if feasible.
     33     // As with other OpenMAX AL implementation code, this copy mostly uses SL_ symbols
     34     // rather than XA_ unless the difference is significant.
     35 
     36     if (NULL == user) {
     37         return;
     38     }
     39 
     40     CMediaPlayer* mp = (CMediaPlayer*) user;
     41     if (!android::CallbackProtector::enterCbIfOk(mp->mCallbackProtector)) {
     42         // it is not safe to enter the callback (the media player is about to go away)
     43         return;
     44     }
     45     union {
     46         char c[sizeof(int)];
     47         int i;
     48     } u;
     49     u.i = event;
     50     SL_LOGV("player_handleMediaPlayerEventNotifications(event='%c%c%c%c' (%d), data1=%d, data2=%d, "
     51             "user=%p) from AVPlayer", u.c[3], u.c[2], u.c[1], u.c[0], event, data1, data2, user);
     52     switch(event) {
     53 
     54       case android::GenericPlayer::kEventPrepared: {
     55 
     56         SL_LOGV("Received AVPlayer::kEventPrepared for CMediaPlayer %p", mp);
     57 
     58         // assume no callback
     59         slPrefetchCallback callback = NULL;
     60         void* callbackPContext = NULL;
     61 
     62         object_lock_exclusive(&mp->mObject);
     63         // mark object as prepared; same state is used for successfully or unsuccessful prepare
     64         mp->mAndroidObjState = ANDROID_READY;
     65 
     66         // AVPlayer prepare() failed prefetching, there is no event in XAPrefetchStatus to
     67         //  indicate a prefetch error, so we signal it by sending simulataneously two events:
     68         //  - SL_PREFETCHEVENT_FILLLEVELCHANGE with a level of 0
     69         //  - SL_PREFETCHEVENT_STATUSCHANGE with a status of SL_PREFETCHSTATUS_UNDERFLOW
     70         if (PLAYER_SUCCESS != data1 && IsInterfaceInitialized(&mp->mObject, MPH_XAPREFETCHSTATUS)) {
     71             mp->mPrefetchStatus.mLevel = 0;
     72             mp->mPrefetchStatus.mStatus = SL_PREFETCHSTATUS_UNDERFLOW;
     73             if (!(~mp->mPrefetchStatus.mCallbackEventsMask &
     74                     (SL_PREFETCHEVENT_FILLLEVELCHANGE | SL_PREFETCHEVENT_STATUSCHANGE))) {
     75                 callback = mp->mPrefetchStatus.mCallback;
     76                 callbackPContext = mp->mPrefetchStatus.mContext;
     77             }
     78         }
     79         object_unlock_exclusive(&mp->mObject);
     80 
     81         // callback with no lock held
     82         if (NULL != callback) {
     83             (*callback)(&mp->mPrefetchStatus.mItf, callbackPContext,
     84                     SL_PREFETCHEVENT_FILLLEVELCHANGE | SL_PREFETCHEVENT_STATUSCHANGE);
     85         }
     86 
     87         break;
     88       }
     89 
     90       case android::GenericPlayer::kEventHasVideoSize: {
     91         SL_LOGV("Received AVPlayer::kEventHasVideoSize (%d,%d) for CMediaPlayer %p",
     92                 data1, data2, mp);
     93 
     94         object_lock_exclusive(&mp->mObject);
     95 
     96         // remove an existing video info entry (here we only have one video stream)
     97         for(size_t i=0 ; i < mp->mStreamInfo.mStreamInfoTable.size() ; i++) {
     98             if (XA_DOMAINTYPE_VIDEO == mp->mStreamInfo.mStreamInfoTable.itemAt(i).domain) {
     99                 mp->mStreamInfo.mStreamInfoTable.removeAt(i);
    100                 break;
    101             }
    102         }
    103         // update the stream information with a new video info entry
    104         StreamInfo streamInfo;
    105         streamInfo.domain = XA_DOMAINTYPE_VIDEO;
    106         streamInfo.videoInfo.codecId = 0;// unknown, we don't have that info FIXME
    107         streamInfo.videoInfo.width = (XAuint32)data1;
    108         streamInfo.videoInfo.height = (XAuint32)data2;
    109         streamInfo.videoInfo.bitRate = 0;// unknown, we don't have that info FIXME
    110         streamInfo.videoInfo.frameRate = 0;
    111         streamInfo.videoInfo.duration = XA_TIME_UNKNOWN;
    112         StreamInfo &contInfo = mp->mStreamInfo.mStreamInfoTable.editItemAt(0);
    113         contInfo.containerInfo.numStreams = 1;
    114         ssize_t index = mp->mStreamInfo.mStreamInfoTable.add(streamInfo);
    115 
    116         xaStreamEventChangeCallback callback = mp->mStreamInfo.mCallback;
    117         void* callbackPContext = mp->mStreamInfo.mContext;
    118 
    119         object_unlock_exclusive(&mp->mObject);
    120 
    121         // enqueue notification (outside of lock) that the stream information has been updated
    122         if ((NULL != callback) && (index >= 0)) {
    123 #ifndef USE_ASYNCHRONOUS_STREAMCBEVENT_PROPERTYCHANGE_CALLBACK
    124             (*callback)(&mp->mStreamInfo.mItf, XA_STREAMCBEVENT_PROPERTYCHANGE /*eventId*/,
    125                     1 /*streamIndex, only one stream supported here, 0 is reserved*/,
    126                     NULL /*pEventData, always NULL in OpenMAX AL 1.0.1*/,
    127                     callbackPContext /*pContext*/);
    128 #else
    129             SLresult res = EnqueueAsyncCallback_piipp(mp, callback,
    130                     /*p1*/ &mp->mStreamInfo.mItf,
    131                     /*i1*/ XA_STREAMCBEVENT_PROPERTYCHANGE /*eventId*/,
    132                     /*i2*/ 1 /*streamIndex, only one stream supported here, 0 is reserved*/,
    133                     /*p2*/ NULL /*pEventData, always NULL in OpenMAX AL 1.0.1*/,
    134                     /*p3*/ callbackPContext /*pContext*/);
    135             LOGW_IF(SL_RESULT_SUCCESS != res,
    136                         "Callback %p(%p, XA_STREAMCBEVENT_PROPERTYCHANGE, 1, NULL, %p) dropped",
    137                         callback, &mp->mStreamInfo.mItf, callbackPContext);
    138 #endif
    139         }
    140         break;
    141       }
    142 
    143       case android::GenericPlayer::kEventEndOfStream: {
    144         SL_LOGV("Received AVPlayer::kEventEndOfStream for CMediaPlayer %p", mp);
    145 
    146         object_lock_exclusive(&mp->mObject);
    147         // should be xaPlayCallback but we're sharing the itf between SL and AL
    148         slPlayCallback playCallback = NULL;
    149         void * playContext = NULL;
    150         // XAPlayItf callback or no callback?
    151         if (mp->mPlay.mEventFlags & XA_PLAYEVENT_HEADATEND) {
    152             playCallback = mp->mPlay.mCallback;
    153             playContext = mp->mPlay.mContext;
    154         }
    155         mp->mPlay.mState = XA_PLAYSTATE_PAUSED;
    156         object_unlock_exclusive(&mp->mObject);
    157 
    158         // enqueue callback with no lock held
    159         if (NULL != playCallback) {
    160 #ifndef USE_ASYNCHRONOUS_PLAY_CALLBACK
    161             (*playCallback)(&mp->mPlay.mItf, playContext, XA_PLAYEVENT_HEADATEND);
    162 #else
    163             SLresult res = EnqueueAsyncCallback_ppi(mp, playCallback, &mp->mPlay.mItf, playContext,
    164                     XA_PLAYEVENT_HEADATEND);
    165             LOGW_IF(SL_RESULT_SUCCESS != res,
    166                     "Callback %p(%p, %p, SL_PLAYEVENT_HEADATEND) dropped", playCallback,
    167                     &mp->mPlay.mItf, playContext);
    168 #endif
    169         }
    170         break;
    171       }
    172 
    173       case android::GenericPlayer::kEventChannelCount: {
    174         SL_LOGV("kEventChannelCount channels = %d", data1);
    175         object_lock_exclusive(&mp->mObject);
    176         if (UNKNOWN_NUMCHANNELS == mp->mNumChannels && UNKNOWN_NUMCHANNELS != data1) {
    177             mp->mNumChannels = data1;
    178             android_Player_volumeUpdate(mp);
    179         }
    180         object_unlock_exclusive(&mp->mObject);
    181       }
    182       break;
    183 
    184       case android::GenericPlayer::kEventPrefetchFillLevelUpdate: {
    185         SL_LOGV("kEventPrefetchFillLevelUpdate");
    186         if (!IsInterfaceInitialized(&mp->mObject, MPH_XAPREFETCHSTATUS)) {
    187             break;
    188         }
    189         slPrefetchCallback callback = NULL;
    190         void* callbackPContext = NULL;
    191 
    192         // SLPrefetchStatusItf callback or no callback?
    193         interface_lock_exclusive(&mp->mPrefetchStatus);
    194         if (mp->mPrefetchStatus.mCallbackEventsMask & SL_PREFETCHEVENT_FILLLEVELCHANGE) {
    195             callback = mp->mPrefetchStatus.mCallback;
    196             callbackPContext = mp->mPrefetchStatus.mContext;
    197         }
    198         mp->mPrefetchStatus.mLevel = (SLpermille)data1;
    199         interface_unlock_exclusive(&mp->mPrefetchStatus);
    200 
    201         // callback with no lock held
    202         if (NULL != callback) {
    203             (*callback)(&mp->mPrefetchStatus.mItf, callbackPContext,
    204                     SL_PREFETCHEVENT_FILLLEVELCHANGE);
    205         }
    206       }
    207       break;
    208 
    209       case android::GenericPlayer::kEventPrefetchStatusChange: {
    210         SL_LOGV("kEventPrefetchStatusChange");
    211         if (!IsInterfaceInitialized(&mp->mObject, MPH_XAPREFETCHSTATUS)) {
    212             break;
    213         }
    214         slPrefetchCallback callback = NULL;
    215         void* callbackPContext = NULL;
    216 
    217         // SLPrefetchStatusItf callback or no callback?
    218         object_lock_exclusive(&mp->mObject);
    219         if (mp->mPrefetchStatus.mCallbackEventsMask & SL_PREFETCHEVENT_STATUSCHANGE) {
    220             callback = mp->mPrefetchStatus.mCallback;
    221             callbackPContext = mp->mPrefetchStatus.mContext;
    222         }
    223         if (data1 >= android::kStatusIntermediate) {
    224             mp->mPrefetchStatus.mStatus = SL_PREFETCHSTATUS_SUFFICIENTDATA;
    225         } else if (data1 < android::kStatusIntermediate) {
    226             mp->mPrefetchStatus.mStatus = SL_PREFETCHSTATUS_UNDERFLOW;
    227         }
    228         object_unlock_exclusive(&mp->mObject);
    229 
    230         // callback with no lock held
    231         if (NULL != callback) {
    232             (*callback)(&mp->mPrefetchStatus.mItf, callbackPContext, SL_PREFETCHEVENT_STATUSCHANGE);
    233         }
    234       }
    235       break;
    236 
    237       case android::GenericPlayer::kEventPlay: {
    238         SL_LOGV("kEventPlay");
    239 
    240         interface_lock_shared(&mp->mPlay);
    241         slPlayCallback callback = mp->mPlay.mCallback;
    242         void* callbackPContext = mp->mPlay.mContext;
    243         interface_unlock_shared(&mp->mPlay);
    244 
    245         if (NULL != callback) {
    246             (*callback)(&mp->mPlay.mItf, callbackPContext, (SLuint32) data1); // SL_PLAYEVENT_HEAD*
    247         }
    248       }
    249       break;
    250 
    251       case android::GenericPlayer::kEventErrorAfterPrepare: {
    252         SL_LOGV("kEventErrorAfterPrepare");
    253 
    254         // assume no callback
    255         slPrefetchCallback callback = NULL;
    256         void* callbackPContext = NULL;
    257 
    258         object_lock_exclusive(&mp->mObject);
    259         if (IsInterfaceInitialized(&mp->mObject, MPH_XAPREFETCHSTATUS)) {
    260             mp->mPrefetchStatus.mLevel = 0;
    261             mp->mPrefetchStatus.mStatus = SL_PREFETCHSTATUS_UNDERFLOW;
    262             if (!(~mp->mPrefetchStatus.mCallbackEventsMask &
    263                     (SL_PREFETCHEVENT_FILLLEVELCHANGE | SL_PREFETCHEVENT_STATUSCHANGE))) {
    264                 callback = mp->mPrefetchStatus.mCallback;
    265                 callbackPContext = mp->mPrefetchStatus.mContext;
    266             }
    267         }
    268         object_unlock_exclusive(&mp->mObject);
    269 
    270         // FIXME there's interesting information in data1, but no API to convey it to client
    271         SL_LOGE("Error after prepare: %d", data1);
    272 
    273         // callback with no lock held
    274         if (NULL != callback) {
    275             (*callback)(&mp->mPrefetchStatus.mItf, callbackPContext,
    276                     SL_PREFETCHEVENT_FILLLEVELCHANGE | SL_PREFETCHEVENT_STATUSCHANGE);
    277         }
    278 
    279       }
    280       break;
    281 
    282       default: {
    283         SL_LOGE("Received unknown event %d, data %d from AVPlayer", event, data1);
    284       }
    285     }
    286 
    287     mp->mCallbackProtector->exitCb();
    288 }
    289 
    290 
    291 //-----------------------------------------------------------------------------
    292 XAresult android_Player_checkSourceSink(CMediaPlayer *mp) {
    293 
    294     XAresult result = XA_RESULT_SUCCESS;
    295 
    296     const SLDataSource *pSrc    = &mp->mDataSource.u.mSource;
    297     const SLDataSink *pAudioSnk = &mp->mAudioSink.u.mSink;
    298 
    299     // format check:
    300     const SLuint32 sourceLocatorType = *(SLuint32 *)pSrc->pLocator;
    301     const SLuint32 sourceFormatType  = *(SLuint32 *)pSrc->pFormat;
    302     const SLuint32 audioSinkLocatorType = *(SLuint32 *)pAudioSnk->pLocator;
    303     //const SLuint32 sinkFormatType = *(SLuint32 *)pAudioSnk->pFormat;
    304 
    305     // Source check
    306     switch(sourceLocatorType) {
    307 
    308     case XA_DATALOCATOR_ANDROIDBUFFERQUEUE: {
    309         switch (sourceFormatType) {
    310         case XA_DATAFORMAT_MIME: {
    311             SLDataFormat_MIME *df_mime = (SLDataFormat_MIME *) pSrc->pFormat;
    312             if (SL_CONTAINERTYPE_MPEG_TS != df_mime->containerType) {
    313                 SL_LOGE("Cannot create player with XA_DATALOCATOR_ANDROIDBUFFERQUEUE data source "
    314                         "that is not fed MPEG-2 TS data");
    315                 return SL_RESULT_CONTENT_UNSUPPORTED;
    316             }
    317         } break;
    318         default:
    319             SL_LOGE("Cannot create player with XA_DATALOCATOR_ANDROIDBUFFERQUEUE data source "
    320                     "without SL_DATAFORMAT_MIME format");
    321             return XA_RESULT_CONTENT_UNSUPPORTED;
    322         }
    323     } break;
    324 
    325     case XA_DATALOCATOR_URI: // intended fall-through
    326     case XA_DATALOCATOR_ANDROIDFD:
    327         break;
    328 
    329     default:
    330         SL_LOGE("Cannot create media player with data locator type 0x%x",
    331                 (unsigned) sourceLocatorType);
    332         return SL_RESULT_PARAMETER_INVALID;
    333     }// switch (locatorType)
    334 
    335     // Audio sink check: only playback is supported here
    336     switch(audioSinkLocatorType) {
    337 
    338     case XA_DATALOCATOR_OUTPUTMIX:
    339         break;
    340 
    341     default:
    342         SL_LOGE("Cannot create media player with audio sink data locator of type 0x%x",
    343                 (unsigned) audioSinkLocatorType);
    344         return XA_RESULT_PARAMETER_INVALID;
    345     }// switch (locaaudioSinkLocatorTypeorType)
    346 
    347     return result;
    348 }
    349 
    350 
    351 //-----------------------------------------------------------------------------
    352 XAresult android_Player_create(CMediaPlayer *mp) {
    353 
    354     XAresult result = XA_RESULT_SUCCESS;
    355 
    356     // FIXME verify data source
    357     const SLDataSource *pDataSrc = &mp->mDataSource.u.mSource;
    358     // FIXME verify audio data sink
    359     const SLDataSink *pAudioSnk = &mp->mAudioSink.u.mSink;
    360     // FIXME verify image data sink
    361     const SLDataSink *pVideoSnk = &mp->mImageVideoSink.u.mSink;
    362 
    363     XAuint32 sourceLocator = *(XAuint32 *)pDataSrc->pLocator;
    364     switch(sourceLocator) {
    365     // FIXME support Android simple buffer queue as well
    366     case XA_DATALOCATOR_ANDROIDBUFFERQUEUE:
    367         mp->mAndroidObjType = AUDIOVIDEOPLAYER_FROM_TS_ANDROIDBUFFERQUEUE;
    368         break;
    369     case XA_DATALOCATOR_URI: // intended fall-through
    370     case SL_DATALOCATOR_ANDROIDFD:
    371         mp->mAndroidObjType = AUDIOVIDEOPLAYER_FROM_URIFD;
    372         break;
    373     case XA_DATALOCATOR_ADDRESS: // intended fall-through
    374     default:
    375         SL_LOGE("Unable to create MediaPlayer for data source locator 0x%x", sourceLocator);
    376         result = XA_RESULT_PARAMETER_INVALID;
    377         break;
    378     }
    379 
    380     // FIXME duplicates an initialization also done by higher level
    381     mp->mAndroidObjState = ANDROID_UNINITIALIZED;
    382     mp->mStreamType = ANDROID_DEFAULT_OUTPUT_STREAM_TYPE;
    383     mp->mSessionId = android::AudioSystem::newAudioSessionId();
    384 
    385     mp->mCallbackProtector = new android::CallbackProtector();
    386 
    387     return result;
    388 }
    389 
    390 
    391 //-----------------------------------------------------------------------------
    392 // FIXME abstract out the diff between CMediaPlayer and CAudioPlayer
    393 XAresult android_Player_realize(CMediaPlayer *mp, SLboolean async) {
    394     SL_LOGV("android_Player_realize_l(%p)", mp);
    395     XAresult result = XA_RESULT_SUCCESS;
    396 
    397     const SLDataSource *pDataSrc = &mp->mDataSource.u.mSource;
    398     const SLuint32 sourceLocator = *(SLuint32 *)pDataSrc->pLocator;
    399 
    400     AudioPlayback_Parameters ap_params;
    401     ap_params.sessionId = mp->mSessionId;
    402     ap_params.streamType = mp->mStreamType;
    403 
    404     switch(mp->mAndroidObjType) {
    405     case AUDIOVIDEOPLAYER_FROM_TS_ANDROIDBUFFERQUEUE: {
    406         mp->mAVPlayer = new android::StreamPlayer(&ap_params, true /*hasVideo*/,
    407                 &mp->mAndroidBufferQueue, mp->mCallbackProtector);
    408         mp->mAVPlayer->init(player_handleMediaPlayerEventNotifications, (void*)mp);
    409         }
    410         break;
    411     case AUDIOVIDEOPLAYER_FROM_URIFD: {
    412         mp->mAVPlayer = new android::LocAVPlayer(&ap_params, true /*hasVideo*/);
    413         mp->mAVPlayer->init(player_handleMediaPlayerEventNotifications, (void*)mp);
    414         switch (mp->mDataSource.mLocator.mLocatorType) {
    415         case XA_DATALOCATOR_URI:
    416             ((android::LocAVPlayer*)mp->mAVPlayer.get())->setDataSource(
    417                     (const char*)mp->mDataSource.mLocator.mURI.URI);
    418             break;
    419         case XA_DATALOCATOR_ANDROIDFD: {
    420             int64_t offset = (int64_t)mp->mDataSource.mLocator.mFD.offset;
    421             ((android::LocAVPlayer*)mp->mAVPlayer.get())->setDataSource(
    422                     (int)mp->mDataSource.mLocator.mFD.fd,
    423                     offset == SL_DATALOCATOR_ANDROIDFD_USE_FILE_SIZE ?
    424                             (int64_t)PLAYER_FD_FIND_FILE_SIZE : offset,
    425                     (int64_t)mp->mDataSource.mLocator.mFD.length);
    426             }
    427             break;
    428         default:
    429             SL_LOGE("Invalid or unsupported data locator type %u for data source",
    430                     mp->mDataSource.mLocator.mLocatorType);
    431             result = XA_RESULT_PARAMETER_INVALID;
    432         }
    433         }
    434         break;
    435     case INVALID_TYPE: // intended fall-through
    436     default:
    437         SL_LOGE("Unable to realize MediaPlayer, invalid internal Android object type");
    438         result = XA_RESULT_PARAMETER_INVALID;
    439         break;
    440     }
    441 
    442     if (XA_RESULT_SUCCESS == result) {
    443 
    444         // if there is a video sink
    445         if (XA_DATALOCATOR_NATIVEDISPLAY ==
    446                 mp->mImageVideoSink.mLocator.mLocatorType) {
    447             ANativeWindow *nativeWindow = (ANativeWindow *)
    448                     mp->mImageVideoSink.mLocator.mNativeDisplay.hWindow;
    449             // we already verified earlier that hWindow is non-NULL
    450             assert(nativeWindow != NULL);
    451             result = android_Player_setNativeWindow(mp, nativeWindow);
    452         }
    453 
    454     }
    455 
    456     return result;
    457 }
    458 
    459 // Called with a lock on MediaPlayer, and blocks until safe to destroy
    460 XAresult android_Player_preDestroy(CMediaPlayer *mp) {
    461     SL_LOGV("android_Player_preDestroy(%p)", mp);
    462 
    463     // Not yet clear why this order is important, but it reduces detected deadlocks
    464     object_unlock_exclusive(&mp->mObject);
    465     if (mp->mCallbackProtector != 0) {
    466         mp->mCallbackProtector->requestCbExitAndWait();
    467     }
    468     object_lock_exclusive(&mp->mObject);
    469 
    470     if (mp->mAVPlayer != 0) {
    471         mp->mAVPlayer->preDestroy();
    472     }
    473     SL_LOGV("android_Player_preDestroy(%p) after mAVPlayer->preDestroy()", mp);
    474 
    475     return XA_RESULT_SUCCESS;
    476 }
    477 
    478 //-----------------------------------------------------------------------------
    479 XAresult android_Player_destroy(CMediaPlayer *mp) {
    480     SL_LOGV("android_Player_destroy(%p)", mp);
    481 
    482     mp->mAVPlayer.clear();
    483     mp->mCallbackProtector.clear();
    484 
    485     // explicit destructor
    486     mp->mAVPlayer.~sp();
    487     mp->mCallbackProtector.~sp();
    488 
    489     return XA_RESULT_SUCCESS;
    490 }
    491 
    492 
    493 void android_Player_usePlayEventMask(CMediaPlayer *mp) {
    494     if (mp->mAVPlayer != 0) {
    495         IPlay *pPlayItf = &mp->mPlay;
    496         mp->mAVPlayer->setPlayEvents((int32_t) pPlayItf->mEventFlags,
    497                 (int32_t) pPlayItf->mMarkerPosition, (int32_t) pPlayItf->mPositionUpdatePeriod);
    498     }
    499 }
    500 
    501 
    502 XAresult android_Player_getDuration(IPlay *pPlayItf, XAmillisecond *pDurMsec) {
    503     CMediaPlayer *avp = (CMediaPlayer *)pPlayItf->mThis;
    504 
    505     switch (avp->mAndroidObjType) {
    506 
    507     case AUDIOVIDEOPLAYER_FROM_URIFD: {
    508         int dur = ANDROID_UNKNOWN_TIME;
    509         if (avp->mAVPlayer != 0) {
    510             avp->mAVPlayer->getDurationMsec(&dur);
    511         }
    512         if (dur == ANDROID_UNKNOWN_TIME) {
    513             *pDurMsec = XA_TIME_UNKNOWN;
    514         } else {
    515             *pDurMsec = (XAmillisecond)dur;
    516         }
    517     } break;
    518 
    519     case AUDIOVIDEOPLAYER_FROM_TS_ANDROIDBUFFERQUEUE: // intended fall-through
    520     default:
    521         *pDurMsec = XA_TIME_UNKNOWN;
    522         break;
    523     }
    524 
    525     return XA_RESULT_SUCCESS;
    526 }
    527 
    528 
    529 XAresult android_Player_getPosition(IPlay *pPlayItf, XAmillisecond *pPosMsec) {
    530     SL_LOGD("android_Player_getPosition()");
    531     XAresult result = XA_RESULT_SUCCESS;
    532     CMediaPlayer *avp = (CMediaPlayer *)pPlayItf->mThis;
    533 
    534     switch (avp->mAndroidObjType) {
    535 
    536     case AUDIOVIDEOPLAYER_FROM_TS_ANDROIDBUFFERQUEUE: // intended fall-through
    537     case AUDIOVIDEOPLAYER_FROM_URIFD: {
    538         int pos = ANDROID_UNKNOWN_TIME;
    539         if (avp->mAVPlayer != 0) {
    540             avp->mAVPlayer->getPositionMsec(&pos);
    541         }
    542         if (pos == ANDROID_UNKNOWN_TIME) {
    543             *pPosMsec = 0;
    544         } else {
    545             *pPosMsec = (XAmillisecond)pos;
    546         }
    547     } break;
    548 
    549     default:
    550         // we shouldn't be here
    551         assert(false);
    552         break;
    553     }
    554 
    555     return result;
    556 }
    557 
    558 
    559 //-----------------------------------------------------------------------------
    560 /**
    561  * pre-condition: mp != NULL
    562  */
    563 void android_Player_volumeUpdate(CMediaPlayer* mp)
    564 {
    565     android::GenericPlayer* avp = mp->mAVPlayer.get();
    566     if (avp != NULL) {
    567         float volumes[2];
    568         // MediaPlayer does not currently support EffectSend or MuteSolo
    569         android_player_volumeUpdate(volumes, &mp->mVolume, mp->mNumChannels, 1.0f, NULL);
    570         float leftVol = volumes[0], rightVol = volumes[1];
    571         avp->setVolume(leftVol, rightVol);
    572     }
    573 }
    574 
    575 //-----------------------------------------------------------------------------
    576 /**
    577  * pre-condition: gp != 0
    578  */
    579 XAresult android_Player_setPlayState(const android::sp<android::GenericPlayer> &gp,
    580         SLuint32 playState,
    581         AndroidObjectState* pObjState)
    582 {
    583     XAresult result = XA_RESULT_SUCCESS;
    584     AndroidObjectState objState = *pObjState;
    585 
    586     switch (playState) {
    587      case SL_PLAYSTATE_STOPPED: {
    588          SL_LOGV("setting AVPlayer to SL_PLAYSTATE_STOPPED");
    589          gp->stop();
    590          }
    591          break;
    592      case SL_PLAYSTATE_PAUSED: {
    593          SL_LOGV("setting AVPlayer to SL_PLAYSTATE_PAUSED");
    594          switch(objState) {
    595          case ANDROID_UNINITIALIZED:
    596              *pObjState = ANDROID_PREPARING;
    597              gp->prepare();
    598              break;
    599          case ANDROID_PREPARING:
    600              break;
    601          case ANDROID_READY:
    602              gp->pause();
    603              break;
    604          default:
    605              SL_LOGE("Android object in invalid state");
    606              break;
    607          }
    608          }
    609          break;
    610      case SL_PLAYSTATE_PLAYING: {
    611          SL_LOGV("setting AVPlayer to SL_PLAYSTATE_PLAYING");
    612          switch(objState) {
    613          case ANDROID_UNINITIALIZED:
    614              *pObjState = ANDROID_PREPARING;
    615              gp->prepare();
    616              // intended fall through
    617          case ANDROID_PREPARING:
    618              // intended fall through
    619          case ANDROID_READY:
    620              gp->play();
    621              break;
    622          default:
    623              SL_LOGE("Android object in invalid state");
    624              break;
    625          }
    626          }
    627          break;
    628      default:
    629          // checked by caller, should not happen
    630          break;
    631      }
    632 
    633     return result;
    634 }
    635 
    636 
    637 /**
    638  * pre-condition: mp != NULL
    639  */
    640 XAresult android_Player_seek(CMediaPlayer *mp, SLmillisecond posMsec) {
    641     XAresult result = XA_RESULT_SUCCESS;
    642     switch (mp->mAndroidObjType) {
    643       case AUDIOVIDEOPLAYER_FROM_URIFD:
    644         if (mp->mAVPlayer !=0) {
    645             mp->mAVPlayer->seek(posMsec);
    646         }
    647         break;
    648       case AUDIOVIDEOPLAYER_FROM_TS_ANDROIDBUFFERQUEUE: // intended fall-through
    649       default: {
    650           result = XA_RESULT_FEATURE_UNSUPPORTED;
    651       }
    652     }
    653     return result;
    654 }
    655 
    656 
    657 /**
    658  * pre-condition: mp != NULL
    659  */
    660 XAresult android_Player_loop(CMediaPlayer *mp, SLboolean loopEnable) {
    661     XAresult result = XA_RESULT_SUCCESS;
    662     switch (mp->mAndroidObjType) {
    663       case AUDIOVIDEOPLAYER_FROM_URIFD:
    664         if (mp->mAVPlayer !=0) {
    665             mp->mAVPlayer->loop(loopEnable);
    666         }
    667         break;
    668       case AUDIOVIDEOPLAYER_FROM_TS_ANDROIDBUFFERQUEUE: // intended fall-through
    669       default: {
    670           result = XA_RESULT_FEATURE_UNSUPPORTED;
    671       }
    672     }
    673     return result;
    674 }
    675 
    676 
    677 //-----------------------------------------------------------------------------
    678 void android_Player_androidBufferQueue_clear_l(CMediaPlayer *mp) {
    679     if ((mp->mAndroidObjType == AUDIOVIDEOPLAYER_FROM_TS_ANDROIDBUFFERQUEUE)
    680             && (mp->mAVPlayer != 0)) {
    681         android::StreamPlayer* splr = static_cast<android::StreamPlayer*>(mp->mAVPlayer.get());
    682         splr->appClear_l();
    683     }
    684 }
    685 
    686 
    687 void android_Player_androidBufferQueue_onRefilled_l(CMediaPlayer *mp) {
    688     if ((mp->mAndroidObjType == AUDIOVIDEOPLAYER_FROM_TS_ANDROIDBUFFERQUEUE)
    689             && (mp->mAVPlayer != 0)) {
    690         android::StreamPlayer* splr = static_cast<android::StreamPlayer*>(mp->mAVPlayer.get());
    691         splr->queueRefilled();
    692     }
    693 }
    694 
    695 
    696 /*
    697  *  pre-conditions:
    698  *      mp != NULL
    699  *      mp->mAVPlayer != 0 (player is realized)
    700  *      nativeWindow can be NULL, but if NULL it is treated as an error
    701  */
    702 SLresult android_Player_setNativeWindow(CMediaPlayer *mp, ANativeWindow *nativeWindow)
    703 {
    704     assert(mp != NULL);
    705     assert(mp->mAVPlayer != 0);
    706     if (nativeWindow == NULL) {
    707         SL_LOGE("ANativeWindow is NULL");
    708         return SL_RESULT_PARAMETER_INVALID;
    709     }
    710     SLresult result;
    711     int err;
    712     int value;
    713     // this could crash if app passes in a bad parameter, but that's OK
    714     err = (*nativeWindow->query)(nativeWindow, NATIVE_WINDOW_CONCRETE_TYPE, &value);
    715     if (0 != err) {
    716         SL_LOGE("Query NATIVE_WINDOW_CONCRETE_TYPE on ANativeWindow * %p failed; "
    717                 "errno %d", nativeWindow, err);
    718         result = SL_RESULT_PARAMETER_INVALID;
    719     } else {
    720         switch (value) {
    721         case NATIVE_WINDOW_SURFACE: {                // Surface
    722             SL_LOGV("Displaying on ANativeWindow of type NATIVE_WINDOW_SURFACE");
    723             android::sp<android::Surface> nativeSurface(
    724                     static_cast<android::Surface *>(nativeWindow));
    725             mp->mAVPlayer->setVideoSurfaceTexture(
    726                     nativeSurface->getSurfaceTexture());
    727             result = SL_RESULT_SUCCESS;
    728             } break;
    729         case NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT: { // SurfaceTextureClient
    730             SL_LOGV("Displaying on ANativeWindow of type NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT");
    731             android::sp<android::SurfaceTextureClient> surfaceTextureClient(
    732                     static_cast<android::SurfaceTextureClient *>(nativeWindow));
    733             android::sp<android::ISurfaceTexture> nativeSurfaceTexture(
    734                     surfaceTextureClient->getISurfaceTexture());
    735             mp->mAVPlayer->setVideoSurfaceTexture(nativeSurfaceTexture);
    736             result = SL_RESULT_SUCCESS;
    737             } break;
    738         case NATIVE_WINDOW_FRAMEBUFFER:              // FramebufferNativeWindow
    739             // fall through
    740         default:
    741             SL_LOGE("ANativeWindow * %p has unknown or unsupported concrete type %d",
    742                     nativeWindow, value);
    743             result = SL_RESULT_PARAMETER_INVALID;
    744             break;
    745         }
    746     }
    747     return result;
    748 }
    749