Home | History | Annotate | Download | only in itf
      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 /* Play implementation */
     18 
     19 #include "sles_allinclusive.h"
     20 
     21 
     22 static SLresult IPlay_SetPlayState(SLPlayItf self, SLuint32 state)
     23 {
     24     SL_ENTER_INTERFACE
     25 
     26     switch (state) {
     27     case SL_PLAYSTATE_STOPPED:
     28     case SL_PLAYSTATE_PAUSED:
     29     case SL_PLAYSTATE_PLAYING:
     30         {
     31         IPlay *thiz = (IPlay *) self;
     32         unsigned attr = ATTR_NONE;
     33         result = SL_RESULT_SUCCESS;
     34 #ifdef USE_OUTPUTMIXEXT
     35         CAudioPlayer *audioPlayer = (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(thiz)) ?
     36             (CAudioPlayer *) thiz->mThis : NULL;
     37 #endif
     38         interface_lock_exclusive(thiz);
     39         SLuint32 oldState = thiz->mState;
     40         if (state != oldState) {
     41 #ifdef USE_OUTPUTMIXEXT
     42           for (;; interface_cond_wait(thiz)) {
     43 
     44             // We are comparing the old state (left) vs. new state (right).
     45             // Note that the old state is 3 bits wide, but new state is only 2 bits wide.
     46             // That is why the old state is on the left and new state is on the right.
     47             switch ((oldState << 2) | state) {
     48 
     49             case (SL_PLAYSTATE_STOPPED  << 2) | SL_PLAYSTATE_STOPPED:
     50             case (SL_PLAYSTATE_PAUSED   << 2) | SL_PLAYSTATE_PAUSED:
     51             case (SL_PLAYSTATE_PLAYING  << 2) | SL_PLAYSTATE_PLAYING:
     52                // no-op, and unreachable due to earlier "if (state != oldState)"
     53                 break;
     54 
     55             case (SL_PLAYSTATE_STOPPED  << 2) | SL_PLAYSTATE_PLAYING:
     56             case (SL_PLAYSTATE_PAUSED   << 2) | SL_PLAYSTATE_PLAYING:
     57                 attr = ATTR_PLAY_STATE;
     58                 // set enqueue attribute if queue is non-empty and state becomes PLAYING
     59                 if ((NULL != audioPlayer) && (audioPlayer->mBufferQueue.mFront !=
     60                     audioPlayer->mBufferQueue.mRear)) {
     61                     // note that USE_OUTPUTMIXEXT does not support ATTR_ABQ_ENQUEUE
     62                     attr |= ATTR_BQ_ENQUEUE;
     63                 }
     64                 // fall through
     65 
     66             case (SL_PLAYSTATE_STOPPED  << 2) | SL_PLAYSTATE_PAUSED:
     67             case (SL_PLAYSTATE_PLAYING  << 2) | SL_PLAYSTATE_PAUSED:
     68                 // easy
     69                 thiz->mState = state;
     70                 break;
     71 
     72             case (SL_PLAYSTATE_STOPPING << 2) | SL_PLAYSTATE_STOPPED:
     73                 // either spurious wakeup, or someone else requested same transition
     74                 continue;
     75 
     76             case (SL_PLAYSTATE_STOPPING << 2) | SL_PLAYSTATE_PAUSED:
     77             case (SL_PLAYSTATE_STOPPING << 2) | SL_PLAYSTATE_PLAYING:
     78                 // wait for other guy to finish his transition, then retry ours
     79                 continue;
     80 
     81             case (SL_PLAYSTATE_PAUSED   << 2) | SL_PLAYSTATE_STOPPED:
     82             case (SL_PLAYSTATE_PLAYING  << 2) | SL_PLAYSTATE_STOPPED:
     83                 // tell mixer to stop, then wait for mixer to acknowledge the request to stop
     84                 thiz->mState = SL_PLAYSTATE_STOPPING;
     85                 continue;
     86 
     87             default:
     88                 // unexpected state
     89                 assert(SL_BOOLEAN_FALSE);
     90                 result = SL_RESULT_INTERNAL_ERROR;
     91                 break;
     92 
     93             }
     94 
     95             break;
     96           }
     97 #else
     98           // Here life looks easy for an Android, but there are other troubles in play land
     99           thiz->mState = state;
    100           attr = ATTR_PLAY_STATE;
    101           // no need to set ATTR_BQ_ENQUEUE or ATTR_ABQ_ENQUEUE
    102 #endif
    103         }
    104         // SL_LOGD("set play state %d", state);
    105         interface_unlock_exclusive_attributes(thiz, attr);
    106         }
    107         break;
    108     default:
    109         result = SL_RESULT_PARAMETER_INVALID;
    110         break;
    111     }
    112 
    113     SL_LEAVE_INTERFACE
    114 }
    115 
    116 
    117 static SLresult IPlay_GetPlayState(SLPlayItf self, SLuint32 *pState)
    118 {
    119     SL_ENTER_INTERFACE
    120 
    121     if (NULL == pState) {
    122         result = SL_RESULT_PARAMETER_INVALID;
    123     } else {
    124         IPlay *thiz = (IPlay *) self;
    125         interface_lock_shared(thiz);
    126         SLuint32 state = thiz->mState;
    127         interface_unlock_shared(thiz);
    128         result = SL_RESULT_SUCCESS;
    129 #ifdef USE_OUTPUTMIXEXT
    130         switch (state) {
    131         case SL_PLAYSTATE_STOPPED:  // as is
    132         case SL_PLAYSTATE_PAUSED:
    133         case SL_PLAYSTATE_PLAYING:
    134             break;
    135         case SL_PLAYSTATE_STOPPING: // these states require re-mapping
    136             state = SL_PLAYSTATE_STOPPED;
    137             break;
    138         default:                    // impossible
    139             assert(SL_BOOLEAN_FALSE);
    140             state = SL_PLAYSTATE_STOPPED;
    141             result = SL_RESULT_INTERNAL_ERROR;
    142             break;
    143         }
    144 #endif
    145         *pState = state;
    146     }
    147 
    148     SL_LEAVE_INTERFACE
    149 }
    150 
    151 
    152 static SLresult IPlay_GetDuration(SLPlayItf self, SLmillisecond *pMsec)
    153 {
    154     SL_ENTER_INTERFACE
    155 
    156     if (NULL == pMsec) {
    157         result = SL_RESULT_PARAMETER_INVALID;
    158     } else {
    159         result = SL_RESULT_SUCCESS;
    160         IPlay *thiz = (IPlay *) self;
    161         // even though this is a getter, it can modify state due to caching
    162         interface_lock_exclusive(thiz);
    163         SLmillisecond duration = thiz->mDuration;
    164 #ifdef ANDROID
    165         if (SL_TIME_UNKNOWN == duration) {
    166             SLmillisecond temp;
    167             switch (InterfaceToObjectID(thiz)) {
    168             case SL_OBJECTID_AUDIOPLAYER:
    169                 result = android_audioPlayer_getDuration(thiz, &temp);
    170                 break;
    171             case XA_OBJECTID_MEDIAPLAYER:
    172                 result = android_Player_getDuration(thiz, &temp);
    173                 break;
    174             default:
    175                 result = SL_RESULT_FEATURE_UNSUPPORTED;
    176                 break;
    177             }
    178             if (SL_RESULT_SUCCESS == result) {
    179                 duration = temp;
    180                 thiz->mDuration = duration;
    181             }
    182         }
    183 #else
    184         // will be set by containing AudioPlayer or MidiPlayer object at Realize, if known,
    185         // otherwise the duration will be updated each time a new maximum position is detected
    186 #endif
    187         interface_unlock_exclusive(thiz);
    188         *pMsec = duration;
    189     }
    190 
    191     SL_LEAVE_INTERFACE
    192 }
    193 
    194 
    195 static SLresult IPlay_GetPosition(SLPlayItf self, SLmillisecond *pMsec)
    196 {
    197     SL_ENTER_INTERFACE
    198 
    199     if (NULL == pMsec) {
    200         result = SL_RESULT_PARAMETER_INVALID;
    201     } else {
    202         IPlay *thiz = (IPlay *) self;
    203         SLmillisecond position;
    204         interface_lock_shared(thiz);
    205 #ifdef ANDROID
    206         // Android does not use the mPosition field for audio and media players
    207         //  and doesn't cache the position
    208         switch (IObjectToObjectID((thiz)->mThis)) {
    209           case SL_OBJECTID_AUDIOPLAYER:
    210             android_audioPlayer_getPosition(thiz, &position);
    211             break;
    212           case XA_OBJECTID_MEDIAPLAYER:
    213             android_Player_getPosition(thiz, &position);
    214             break;
    215           default:
    216             // we shouldn'be here
    217             assert(SL_BOOLEAN_FALSE);
    218         }
    219 #else
    220         // on other platforms we depend on periodic updates to the current position
    221         position = thiz->mPosition;
    222         // if a seek is pending, then lie about current position so the seek appears synchronous
    223         if (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(thiz)) {
    224             CAudioPlayer *audioPlayer = (CAudioPlayer *) thiz->mThis;
    225             SLmillisecond pos = audioPlayer->mSeek.mPos;
    226             if (SL_TIME_UNKNOWN != pos) {
    227                 position = pos;
    228             }
    229         }
    230 #endif
    231         interface_unlock_shared(thiz);
    232         *pMsec = position;
    233         result = SL_RESULT_SUCCESS;
    234     }
    235 
    236     SL_LEAVE_INTERFACE
    237 }
    238 
    239 
    240 static SLresult IPlay_RegisterCallback(SLPlayItf self, slPlayCallback callback, void *pContext)
    241 {
    242     SL_ENTER_INTERFACE
    243 
    244     IPlay *thiz = (IPlay *) self;
    245     interface_lock_exclusive(thiz);
    246     thiz->mCallback = callback;
    247     thiz->mContext = pContext;
    248     // omits _attributes b/c noone cares deeply enough about these fields to need quick notification
    249     interface_unlock_exclusive(thiz);
    250     result = SL_RESULT_SUCCESS;
    251 
    252     SL_LEAVE_INTERFACE
    253 }
    254 
    255 
    256 static SLresult IPlay_SetCallbackEventsMask(SLPlayItf self, SLuint32 eventFlags)
    257 {
    258     SL_ENTER_INTERFACE
    259 
    260     if (eventFlags & ~(SL_PLAYEVENT_HEADATEND | SL_PLAYEVENT_HEADATMARKER |
    261             SL_PLAYEVENT_HEADATNEWPOS | SL_PLAYEVENT_HEADMOVING | SL_PLAYEVENT_HEADSTALLED)) {
    262         result = SL_RESULT_PARAMETER_INVALID;
    263     } else {
    264         IPlay *thiz = (IPlay *) self;
    265         interface_lock_exclusive(thiz);
    266         if (thiz->mEventFlags != eventFlags) {
    267 #ifdef USE_OUTPUTMIXEXT
    268             // enabling the "head at new position" play event will postpone the next update event
    269             if (!(thiz->mEventFlags & SL_PLAYEVENT_HEADATNEWPOS) &&
    270                     (eventFlags & SL_PLAYEVENT_HEADATNEWPOS)) {
    271                 thiz->mFramesSincePositionUpdate = 0;
    272             }
    273 #endif
    274             thiz->mEventFlags = eventFlags;
    275             interface_unlock_exclusive_attributes(thiz, ATTR_TRANSPORT);
    276         } else {
    277             interface_unlock_exclusive(thiz);
    278         }
    279         result = SL_RESULT_SUCCESS;
    280     }
    281 
    282     SL_LEAVE_INTERFACE
    283 }
    284 
    285 
    286 static SLresult IPlay_GetCallbackEventsMask(SLPlayItf self, SLuint32 *pEventFlags)
    287 {
    288     SL_ENTER_INTERFACE
    289 
    290     if (NULL == pEventFlags) {
    291         result = SL_RESULT_PARAMETER_INVALID;
    292     } else {
    293         IPlay *thiz = (IPlay *) self;
    294         interface_lock_shared(thiz);
    295         SLuint32 eventFlags = thiz->mEventFlags;
    296         interface_unlock_shared(thiz);
    297         *pEventFlags = eventFlags;
    298         result = SL_RESULT_SUCCESS;
    299     }
    300 
    301     SL_LEAVE_INTERFACE
    302 }
    303 
    304 
    305 static SLresult IPlay_SetMarkerPosition(SLPlayItf self, SLmillisecond mSec)
    306 {
    307     SL_ENTER_INTERFACE
    308 
    309     if (SL_TIME_UNKNOWN == mSec) {
    310         result = SL_RESULT_PARAMETER_INVALID;
    311     } else {
    312         IPlay *thiz = (IPlay *) self;
    313         bool significant = false;
    314         interface_lock_exclusive(thiz);
    315         if (thiz->mMarkerPosition != mSec) {
    316             thiz->mMarkerPosition = mSec;
    317             if (thiz->mEventFlags & SL_PLAYEVENT_HEADATMARKER) {
    318                 significant = true;
    319             }
    320         }
    321         if (significant) {
    322             interface_unlock_exclusive_attributes(thiz, ATTR_TRANSPORT);
    323         } else {
    324             interface_unlock_exclusive(thiz);
    325         }
    326         result = SL_RESULT_SUCCESS;
    327     }
    328 
    329     SL_LEAVE_INTERFACE
    330 }
    331 
    332 
    333 static SLresult IPlay_ClearMarkerPosition(SLPlayItf self)
    334 {
    335     SL_ENTER_INTERFACE
    336 
    337     IPlay *thiz = (IPlay *) self;
    338     bool significant = false;
    339     interface_lock_exclusive(thiz);
    340     // clearing the marker position is equivalent to setting the marker to SL_TIME_UNKNOWN
    341     if (thiz->mMarkerPosition != SL_TIME_UNKNOWN) {
    342         thiz->mMarkerPosition = SL_TIME_UNKNOWN;
    343         if (thiz->mEventFlags & SL_PLAYEVENT_HEADATMARKER) {
    344             significant = true;
    345         }
    346     }
    347     if (significant) {
    348         interface_unlock_exclusive_attributes(thiz, ATTR_TRANSPORT);
    349     } else {
    350         interface_unlock_exclusive(thiz);
    351     }
    352     result = SL_RESULT_SUCCESS;
    353 
    354     SL_LEAVE_INTERFACE
    355 }
    356 
    357 
    358 static SLresult IPlay_GetMarkerPosition(SLPlayItf self, SLmillisecond *pMsec)
    359 {
    360     SL_ENTER_INTERFACE
    361 
    362     if (NULL == pMsec) {
    363         result = SL_RESULT_PARAMETER_INVALID;
    364     } else {
    365         IPlay *thiz = (IPlay *) self;
    366         interface_lock_shared(thiz);
    367         SLmillisecond markerPosition = thiz->mMarkerPosition;
    368         interface_unlock_shared(thiz);
    369         *pMsec = markerPosition;
    370         if (SL_TIME_UNKNOWN == markerPosition) {
    371             result = SL_RESULT_PRECONDITIONS_VIOLATED;
    372         } else {
    373             result = SL_RESULT_SUCCESS;
    374         }
    375     }
    376 
    377     SL_LEAVE_INTERFACE
    378 }
    379 
    380 
    381 static SLresult IPlay_SetPositionUpdatePeriod(SLPlayItf self, SLmillisecond mSec)
    382 {
    383     SL_ENTER_INTERFACE
    384 
    385     if (0 == mSec) {
    386         result = SL_RESULT_PARAMETER_INVALID;
    387     } else {
    388         IPlay *thiz = (IPlay *) self;
    389         bool significant = false;
    390         interface_lock_exclusive(thiz);
    391         if (thiz->mPositionUpdatePeriod != mSec) {
    392             thiz->mPositionUpdatePeriod = mSec;
    393 #ifdef USE_OUTPUTMIXEXT
    394             if (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(thiz)) {
    395                 CAudioPlayer *audioPlayer = (CAudioPlayer *) thiz->mThis;
    396                 SLuint32 frameUpdatePeriod = ((long long) mSec *
    397                     (long long) audioPlayer->mSampleRateMilliHz) / 1000000LL;
    398                 if (0 == frameUpdatePeriod) {
    399                     frameUpdatePeriod = ~0;
    400                 }
    401                 thiz->mFrameUpdatePeriod = frameUpdatePeriod;
    402                 // setting a new update period postpones the next callback
    403                 thiz->mFramesSincePositionUpdate = 0;
    404             }
    405 #endif
    406             if (thiz->mEventFlags & SL_PLAYEVENT_HEADATNEWPOS) {
    407                 significant = true;
    408             }
    409         }
    410         if (significant) {
    411             interface_unlock_exclusive_attributes(thiz, ATTR_TRANSPORT);
    412         } else {
    413             interface_unlock_exclusive(thiz);
    414         }
    415         result = SL_RESULT_SUCCESS;
    416     }
    417 
    418     SL_LEAVE_INTERFACE
    419 }
    420 
    421 
    422 static SLresult IPlay_GetPositionUpdatePeriod(SLPlayItf self, SLmillisecond *pMsec)
    423 {
    424     SL_ENTER_INTERFACE
    425 
    426     if (NULL == pMsec) {
    427         result = SL_RESULT_PARAMETER_INVALID;
    428     } else {
    429         IPlay *thiz = (IPlay *) self;
    430         interface_lock_shared(thiz);
    431         SLmillisecond positionUpdatePeriod = thiz->mPositionUpdatePeriod;
    432         interface_unlock_shared(thiz);
    433         *pMsec = positionUpdatePeriod;
    434         result = SL_RESULT_SUCCESS;
    435     }
    436 
    437     SL_LEAVE_INTERFACE
    438 }
    439 
    440 
    441 static const struct SLPlayItf_ IPlay_Itf = {
    442     IPlay_SetPlayState,
    443     IPlay_GetPlayState,
    444     IPlay_GetDuration,
    445     IPlay_GetPosition,
    446     IPlay_RegisterCallback,
    447     IPlay_SetCallbackEventsMask,
    448     IPlay_GetCallbackEventsMask,
    449     IPlay_SetMarkerPosition,
    450     IPlay_ClearMarkerPosition,
    451     IPlay_GetMarkerPosition,
    452     IPlay_SetPositionUpdatePeriod,
    453     IPlay_GetPositionUpdatePeriod
    454 };
    455 
    456 void IPlay_init(void *self)
    457 {
    458     IPlay *thiz = (IPlay *) self;
    459     thiz->mItf = &IPlay_Itf;
    460     thiz->mState = SL_PLAYSTATE_STOPPED;
    461     thiz->mDuration = SL_TIME_UNKNOWN;  // will be set by containing player object
    462     thiz->mPosition = (SLmillisecond) 0;
    463     thiz->mCallback = NULL;
    464     thiz->mContext = NULL;
    465     thiz->mEventFlags = 0;
    466     thiz->mMarkerPosition = SL_TIME_UNKNOWN;
    467     thiz->mPositionUpdatePeriod = 1000; // per spec
    468 #ifdef USE_OUTPUTMIXEXT
    469     thiz->mFrameUpdatePeriod = 0;   // because we don't know the sample rate yet
    470     thiz->mLastSeekPosition = 0;
    471     thiz->mFramesSinceLastSeek = 0;
    472     thiz->mFramesSincePositionUpdate = 0;
    473 #endif
    474 }
    475