10b167267bda99b68346045ccab14e810121d5de4Glenn Kasten/*
20b167267bda99b68346045ccab14e810121d5de4Glenn Kasten * Copyright (C) 2010 The Android Open Source Project
30b167267bda99b68346045ccab14e810121d5de4Glenn Kasten *
40b167267bda99b68346045ccab14e810121d5de4Glenn Kasten * Licensed under the Apache License, Version 2.0 (the "License");
50b167267bda99b68346045ccab14e810121d5de4Glenn Kasten * you may not use this file except in compliance with the License.
60b167267bda99b68346045ccab14e810121d5de4Glenn Kasten * You may obtain a copy of the License at
70b167267bda99b68346045ccab14e810121d5de4Glenn Kasten *
80b167267bda99b68346045ccab14e810121d5de4Glenn Kasten *      http://www.apache.org/licenses/LICENSE-2.0
90b167267bda99b68346045ccab14e810121d5de4Glenn Kasten *
100b167267bda99b68346045ccab14e810121d5de4Glenn Kasten * Unless required by applicable law or agreed to in writing, software
110b167267bda99b68346045ccab14e810121d5de4Glenn Kasten * distributed under the License is distributed on an "AS IS" BASIS,
120b167267bda99b68346045ccab14e810121d5de4Glenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130b167267bda99b68346045ccab14e810121d5de4Glenn Kasten * See the License for the specific language governing permissions and
140b167267bda99b68346045ccab14e810121d5de4Glenn Kasten * limitations under the License.
150b167267bda99b68346045ccab14e810121d5de4Glenn Kasten */
160b167267bda99b68346045ccab14e810121d5de4Glenn Kasten
170b167267bda99b68346045ccab14e810121d5de4Glenn Kasten/* Play implementation */
180b167267bda99b68346045ccab14e810121d5de4Glenn Kasten
19979a3f8743646af9999a89dff9e13b972b7efd87Glenn Kasten#include "sles_allinclusive.h"
20979a3f8743646af9999a89dff9e13b972b7efd87Glenn Kasten
21ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
220b167267bda99b68346045ccab14e810121d5de4Glenn Kastenstatic SLresult IPlay_SetPlayState(SLPlayItf self, SLuint32 state)
230b167267bda99b68346045ccab14e810121d5de4Glenn Kasten{
24ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
25ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
260b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    switch (state) {
270b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    case SL_PLAYSTATE_STOPPED:
280b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    case SL_PLAYSTATE_PAUSED:
290b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    case SL_PLAYSTATE_PLAYING:
30ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        {
31bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        IPlay *thiz = (IPlay *) self;
324b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        unsigned attr = ATTR_NONE;
33ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_SUCCESS;
3494a37e8117fb72790882dfb815f99e2365754c74Glenn Kasten#ifdef USE_OUTPUTMIXEXT
35bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        CAudioPlayer *audioPlayer = (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(thiz)) ?
36bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            (CAudioPlayer *) thiz->mThis : NULL;
3794a37e8117fb72790882dfb815f99e2365754c74Glenn Kasten#endif
38bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        interface_lock_exclusive(thiz);
39f4647bf85968ab30eb07f9a80b99177d91068f94Glenn Kasten        SLuint32 oldState = thiz->mState;
40f4647bf85968ab30eb07f9a80b99177d91068f94Glenn Kasten        if (state != oldState) {
414b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten#ifdef USE_OUTPUTMIXEXT
42f4647bf85968ab30eb07f9a80b99177d91068f94Glenn Kasten          for (;; interface_cond_wait(thiz)) {
434b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
444b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            // We are comparing the old state (left) vs. new state (right).
454b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            // Note that the old state is 3 bits wide, but new state is only 2 bits wide.
464b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            // That is why the old state is on the left and new state is on the right.
47f4647bf85968ab30eb07f9a80b99177d91068f94Glenn Kasten            switch ((oldState << 2) | state) {
484b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
494b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            case (SL_PLAYSTATE_STOPPED  << 2) | SL_PLAYSTATE_STOPPED:
504b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            case (SL_PLAYSTATE_PAUSED   << 2) | SL_PLAYSTATE_PAUSED:
514b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            case (SL_PLAYSTATE_PLAYING  << 2) | SL_PLAYSTATE_PLAYING:
52f4647bf85968ab30eb07f9a80b99177d91068f94Glenn Kasten               // no-op, and unreachable due to earlier "if (state != oldState)"
534b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                break;
544b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
554b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            case (SL_PLAYSTATE_STOPPED  << 2) | SL_PLAYSTATE_PLAYING:
564b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            case (SL_PLAYSTATE_PAUSED   << 2) | SL_PLAYSTATE_PLAYING:
57f4647bf85968ab30eb07f9a80b99177d91068f94Glenn Kasten                attr = ATTR_PLAY_STATE;
584b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                // set enqueue attribute if queue is non-empty and state becomes PLAYING
594b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                if ((NULL != audioPlayer) && (audioPlayer->mBufferQueue.mFront !=
604b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    audioPlayer->mBufferQueue.mRear)) {
61f4647bf85968ab30eb07f9a80b99177d91068f94Glenn Kasten                    // note that USE_OUTPUTMIXEXT does not support ATTR_ABQ_ENQUEUE
62d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi                    attr |= ATTR_BQ_ENQUEUE;
634b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                }
644b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                // fall through
654b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
664b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            case (SL_PLAYSTATE_STOPPED  << 2) | SL_PLAYSTATE_PAUSED:
674b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            case (SL_PLAYSTATE_PLAYING  << 2) | SL_PLAYSTATE_PAUSED:
684b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                // easy
69bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                thiz->mState = state;
704b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                break;
714b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
724b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            case (SL_PLAYSTATE_STOPPING << 2) | SL_PLAYSTATE_STOPPED:
734b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                // either spurious wakeup, or someone else requested same transition
744b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                continue;
754b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
764b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            case (SL_PLAYSTATE_STOPPING << 2) | SL_PLAYSTATE_PAUSED:
774b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            case (SL_PLAYSTATE_STOPPING << 2) | SL_PLAYSTATE_PLAYING:
784b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                // wait for other guy to finish his transition, then retry ours
794b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                continue;
804b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
814b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            case (SL_PLAYSTATE_PAUSED   << 2) | SL_PLAYSTATE_STOPPED:
824b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            case (SL_PLAYSTATE_PLAYING  << 2) | SL_PLAYSTATE_STOPPED:
834b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                // tell mixer to stop, then wait for mixer to acknowledge the request to stop
84bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                thiz->mState = SL_PLAYSTATE_STOPPING;
854b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                continue;
864b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
874b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            default:
884b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                // unexpected state
894b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                assert(SL_BOOLEAN_FALSE);
904b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                result = SL_RESULT_INTERNAL_ERROR;
914b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                break;
924b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
934b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            }
944b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
954b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            break;
96f4647bf85968ab30eb07f9a80b99177d91068f94Glenn Kasten          }
974b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten#else
98f4647bf85968ab30eb07f9a80b99177d91068f94Glenn Kasten          // Here life looks easy for an Android, but there are other troubles in play land
99f4647bf85968ab30eb07f9a80b99177d91068f94Glenn Kasten          thiz->mState = state;
100f4647bf85968ab30eb07f9a80b99177d91068f94Glenn Kasten          attr = ATTR_PLAY_STATE;
101f4647bf85968ab30eb07f9a80b99177d91068f94Glenn Kasten          // no need to set ATTR_BQ_ENQUEUE or ATTR_ABQ_ENQUEUE
1024b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten#endif
103f4647bf85968ab30eb07f9a80b99177d91068f94Glenn Kasten        }
104a8179ea15c4ff78db589d742b135649f0eda7ef2Glenn Kasten        // SL_LOGD("set play state %d", state);
105bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        interface_unlock_exclusive_attributes(thiz, attr);
106ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        }
1070b167267bda99b68346045ccab14e810121d5de4Glenn Kasten        break;
1080b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    default:
109ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_PARAMETER_INVALID;
1104b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        break;
1110b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    }
112ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
113ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
1140b167267bda99b68346045ccab14e810121d5de4Glenn Kasten}
1150b167267bda99b68346045ccab14e810121d5de4Glenn Kasten
116ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
1170b167267bda99b68346045ccab14e810121d5de4Glenn Kastenstatic SLresult IPlay_GetPlayState(SLPlayItf self, SLuint32 *pState)
1180b167267bda99b68346045ccab14e810121d5de4Glenn Kasten{
119ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
120ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
121ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    if (NULL == pState) {
122ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_PARAMETER_INVALID;
123ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    } else {
124bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        IPlay *thiz = (IPlay *) self;
1255933f3d5e532aaac31ce0e6551c59f0197c0ae3cGlenn Kasten        interface_lock_shared(thiz);
126bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        SLuint32 state = thiz->mState;
1275933f3d5e532aaac31ce0e6551c59f0197c0ae3cGlenn Kasten        interface_unlock_shared(thiz);
128ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_SUCCESS;
1294b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten#ifdef USE_OUTPUTMIXEXT
1304b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        switch (state) {
1314b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        case SL_PLAYSTATE_STOPPED:  // as is
1324b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        case SL_PLAYSTATE_PAUSED:
1334b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        case SL_PLAYSTATE_PLAYING:
1344b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            break;
1354b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        case SL_PLAYSTATE_STOPPING: // these states require re-mapping
1364b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            state = SL_PLAYSTATE_STOPPED;
1374b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            break;
1384b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        default:                    // impossible
1394b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            assert(SL_BOOLEAN_FALSE);
1404b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            state = SL_PLAYSTATE_STOPPED;
1414b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            result = SL_RESULT_INTERNAL_ERROR;
1424b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            break;
1434b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        }
1444b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten#endif
1454b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        *pState = state;
146ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    }
147ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
148ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
1490b167267bda99b68346045ccab14e810121d5de4Glenn Kasten}
1500b167267bda99b68346045ccab14e810121d5de4Glenn Kasten
151ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
1520b167267bda99b68346045ccab14e810121d5de4Glenn Kastenstatic SLresult IPlay_GetDuration(SLPlayItf self, SLmillisecond *pMsec)
1530b167267bda99b68346045ccab14e810121d5de4Glenn Kasten{
154ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
155ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
156ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    if (NULL == pMsec) {
157ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_PARAMETER_INVALID;
158ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    } else {
159ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_SUCCESS;
160bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        IPlay *thiz = (IPlay *) self;
161ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        // even though this is a getter, it can modify state due to caching
162bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        interface_lock_exclusive(thiz);
163bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        SLmillisecond duration = thiz->mDuration;
164ef8931ae547cd703e69df9ad350d69825da0f546Jean-Michel Trivi#ifdef ANDROID
1653d332ff421e7179c36fb652771cc8ded53383729Glenn Kasten        if (SL_TIME_UNKNOWN == duration) {
166ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            SLmillisecond temp;
1673d332ff421e7179c36fb652771cc8ded53383729Glenn Kasten            switch (InterfaceToObjectID(thiz)) {
1683d332ff421e7179c36fb652771cc8ded53383729Glenn Kasten            case SL_OBJECTID_AUDIOPLAYER:
1693d332ff421e7179c36fb652771cc8ded53383729Glenn Kasten                result = android_audioPlayer_getDuration(thiz, &temp);
1703d332ff421e7179c36fb652771cc8ded53383729Glenn Kasten                break;
1713d332ff421e7179c36fb652771cc8ded53383729Glenn Kasten            case XA_OBJECTID_MEDIAPLAYER:
1723d332ff421e7179c36fb652771cc8ded53383729Glenn Kasten                result = android_Player_getDuration(thiz, &temp);
1733d332ff421e7179c36fb652771cc8ded53383729Glenn Kasten                break;
1743d332ff421e7179c36fb652771cc8ded53383729Glenn Kasten            default:
1753d332ff421e7179c36fb652771cc8ded53383729Glenn Kasten                result = SL_RESULT_FEATURE_UNSUPPORTED;
1763d332ff421e7179c36fb652771cc8ded53383729Glenn Kasten                break;
1773d332ff421e7179c36fb652771cc8ded53383729Glenn Kasten            }
178ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            if (SL_RESULT_SUCCESS == result) {
179ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                duration = temp;
180bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                thiz->mDuration = duration;
181ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            }
182e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten        }
183e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten#else
1848c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        // will be set by containing AudioPlayer or MidiPlayer object at Realize, if known,
1858c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        // otherwise the duration will be updated each time a new maximum position is detected
186dc181a4a041fe4be7c91b92646b236b6d652f4a3Jean-Michel Trivi#endif
187bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        interface_unlock_exclusive(thiz);
188ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        *pMsec = duration;
189ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    }
190ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
191ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
1920b167267bda99b68346045ccab14e810121d5de4Glenn Kasten}
1930b167267bda99b68346045ccab14e810121d5de4Glenn Kasten
194ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
1950b167267bda99b68346045ccab14e810121d5de4Glenn Kastenstatic SLresult IPlay_GetPosition(SLPlayItf self, SLmillisecond *pMsec)
1960b167267bda99b68346045ccab14e810121d5de4Glenn Kasten{
197ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
198ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
199ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    if (NULL == pMsec) {
200ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_PARAMETER_INVALID;
201ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    } else {
202bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        IPlay *thiz = (IPlay *) self;
203ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        SLmillisecond position;
204bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        interface_lock_shared(thiz);
205ef8931ae547cd703e69df9ad350d69825da0f546Jean-Michel Trivi#ifdef ANDROID
20635a5a30fdad179ccf38d8d756590411326159a89Jean-Michel Trivi        // Android does not use the mPosition field for audio and media players
20735a5a30fdad179ccf38d8d756590411326159a89Jean-Michel Trivi        //  and doesn't cache the position
20835a5a30fdad179ccf38d8d756590411326159a89Jean-Michel Trivi        switch (IObjectToObjectID((thiz)->mThis)) {
20935a5a30fdad179ccf38d8d756590411326159a89Jean-Michel Trivi          case SL_OBJECTID_AUDIOPLAYER:
210bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            android_audioPlayer_getPosition(thiz, &position);
21135a5a30fdad179ccf38d8d756590411326159a89Jean-Michel Trivi            break;
21235a5a30fdad179ccf38d8d756590411326159a89Jean-Michel Trivi          case XA_OBJECTID_MEDIAPLAYER:
21335a5a30fdad179ccf38d8d756590411326159a89Jean-Michel Trivi            android_Player_getPosition(thiz, &position);
21435a5a30fdad179ccf38d8d756590411326159a89Jean-Michel Trivi            break;
21535a5a30fdad179ccf38d8d756590411326159a89Jean-Michel Trivi          default:
21635a5a30fdad179ccf38d8d756590411326159a89Jean-Michel Trivi            // we shouldn'be here
21735a5a30fdad179ccf38d8d756590411326159a89Jean-Michel Trivi            assert(SL_BOOLEAN_FALSE);
2188c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        }
219e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten#else
220ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        // on other platforms we depend on periodic updates to the current position
221bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        position = thiz->mPosition;
2228c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        // if a seek is pending, then lie about current position so the seek appears synchronous
223bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        if (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(thiz)) {
224bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            CAudioPlayer *audioPlayer = (CAudioPlayer *) thiz->mThis;
2258c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            SLmillisecond pos = audioPlayer->mSeek.mPos;
2268c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            if (SL_TIME_UNKNOWN != pos) {
2278c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten                position = pos;
2288c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            }
2298c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        }
2306a7bf7733e955d4d89204627c34fb357d542a9ecJean-Michel Trivi#endif
231bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        interface_unlock_shared(thiz);
232ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        *pMsec = position;
233ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_SUCCESS;
234ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    }
235ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
236ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
2370b167267bda99b68346045ccab14e810121d5de4Glenn Kasten}
2380b167267bda99b68346045ccab14e810121d5de4Glenn Kasten
239ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
240d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kastenstatic SLresult IPlay_RegisterCallback(SLPlayItf self, slPlayCallback callback, void *pContext)
2410b167267bda99b68346045ccab14e810121d5de4Glenn Kasten{
242ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
243ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
244bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    IPlay *thiz = (IPlay *) self;
245bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    interface_lock_exclusive(thiz);
246bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mCallback = callback;
247bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mContext = pContext;
248e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    // omits _attributes b/c noone cares deeply enough about these fields to need quick notification
249bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    interface_unlock_exclusive(thiz);
250ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    result = SL_RESULT_SUCCESS;
251ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
252ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
2530b167267bda99b68346045ccab14e810121d5de4Glenn Kasten}
2540b167267bda99b68346045ccab14e810121d5de4Glenn Kasten
255ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
2560b167267bda99b68346045ccab14e810121d5de4Glenn Kastenstatic SLresult IPlay_SetCallbackEventsMask(SLPlayItf self, SLuint32 eventFlags)
2570b167267bda99b68346045ccab14e810121d5de4Glenn Kasten{
258ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
259ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
2608c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    if (eventFlags & ~(SL_PLAYEVENT_HEADATEND | SL_PLAYEVENT_HEADATMARKER |
2618c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            SL_PLAYEVENT_HEADATNEWPOS | SL_PLAYEVENT_HEADMOVING | SL_PLAYEVENT_HEADSTALLED)) {
2628c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        result = SL_RESULT_PARAMETER_INVALID;
2638c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    } else {
264bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        IPlay *thiz = (IPlay *) self;
265bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        interface_lock_exclusive(thiz);
266bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        if (thiz->mEventFlags != eventFlags) {
2678c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten#ifdef USE_OUTPUTMIXEXT
2688c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            // enabling the "head at new position" play event will postpone the next update event
269bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            if (!(thiz->mEventFlags & SL_PLAYEVENT_HEADATNEWPOS) &&
2708c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten                    (eventFlags & SL_PLAYEVENT_HEADATNEWPOS)) {
271bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                thiz->mFramesSincePositionUpdate = 0;
2728c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            }
2738c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten#endif
274bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            thiz->mEventFlags = eventFlags;
275bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            interface_unlock_exclusive_attributes(thiz, ATTR_TRANSPORT);
27645b349f3c585a0750417722f72224a35baaab734Glenn Kasten        } else {
277bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            interface_unlock_exclusive(thiz);
27845b349f3c585a0750417722f72224a35baaab734Glenn Kasten        }
2798c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        result = SL_RESULT_SUCCESS;
2808c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    }
281ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
282ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
2830b167267bda99b68346045ccab14e810121d5de4Glenn Kasten}
2840b167267bda99b68346045ccab14e810121d5de4Glenn Kasten
285ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
286d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kastenstatic SLresult IPlay_GetCallbackEventsMask(SLPlayItf self, SLuint32 *pEventFlags)
2870b167267bda99b68346045ccab14e810121d5de4Glenn Kasten{
288ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
289ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
290ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    if (NULL == pEventFlags) {
291ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_PARAMETER_INVALID;
292ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    } else {
293bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        IPlay *thiz = (IPlay *) self;
2945933f3d5e532aaac31ce0e6551c59f0197c0ae3cGlenn Kasten        interface_lock_shared(thiz);
295bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        SLuint32 eventFlags = thiz->mEventFlags;
2965933f3d5e532aaac31ce0e6551c59f0197c0ae3cGlenn Kasten        interface_unlock_shared(thiz);
297ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        *pEventFlags = eventFlags;
298ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_SUCCESS;
299ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    }
300ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
301ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
3020b167267bda99b68346045ccab14e810121d5de4Glenn Kasten}
3030b167267bda99b68346045ccab14e810121d5de4Glenn Kasten
304ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
3050b167267bda99b68346045ccab14e810121d5de4Glenn Kastenstatic SLresult IPlay_SetMarkerPosition(SLPlayItf self, SLmillisecond mSec)
3060b167267bda99b68346045ccab14e810121d5de4Glenn Kasten{
307ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
308ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
30945b349f3c585a0750417722f72224a35baaab734Glenn Kasten    if (SL_TIME_UNKNOWN == mSec) {
31045b349f3c585a0750417722f72224a35baaab734Glenn Kasten        result = SL_RESULT_PARAMETER_INVALID;
31145b349f3c585a0750417722f72224a35baaab734Glenn Kasten    } else {
31245b349f3c585a0750417722f72224a35baaab734Glenn Kasten        IPlay *thiz = (IPlay *) self;
31345b349f3c585a0750417722f72224a35baaab734Glenn Kasten        bool significant = false;
31445b349f3c585a0750417722f72224a35baaab734Glenn Kasten        interface_lock_exclusive(thiz);
31545b349f3c585a0750417722f72224a35baaab734Glenn Kasten        if (thiz->mMarkerPosition != mSec) {
31645b349f3c585a0750417722f72224a35baaab734Glenn Kasten            thiz->mMarkerPosition = mSec;
31745b349f3c585a0750417722f72224a35baaab734Glenn Kasten            if (thiz->mEventFlags & SL_PLAYEVENT_HEADATMARKER) {
31845b349f3c585a0750417722f72224a35baaab734Glenn Kasten                significant = true;
31945b349f3c585a0750417722f72224a35baaab734Glenn Kasten            }
3205933f3d5e532aaac31ce0e6551c59f0197c0ae3cGlenn Kasten        }
32145b349f3c585a0750417722f72224a35baaab734Glenn Kasten        if (significant) {
32245b349f3c585a0750417722f72224a35baaab734Glenn Kasten            interface_unlock_exclusive_attributes(thiz, ATTR_TRANSPORT);
32345b349f3c585a0750417722f72224a35baaab734Glenn Kasten        } else {
32445b349f3c585a0750417722f72224a35baaab734Glenn Kasten            interface_unlock_exclusive(thiz);
32545b349f3c585a0750417722f72224a35baaab734Glenn Kasten        }
32645b349f3c585a0750417722f72224a35baaab734Glenn Kasten        result = SL_RESULT_SUCCESS;
3275933f3d5e532aaac31ce0e6551c59f0197c0ae3cGlenn Kasten    }
328ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
329ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
3300b167267bda99b68346045ccab14e810121d5de4Glenn Kasten}
3310b167267bda99b68346045ccab14e810121d5de4Glenn Kasten
332ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
3330b167267bda99b68346045ccab14e810121d5de4Glenn Kastenstatic SLresult IPlay_ClearMarkerPosition(SLPlayItf self)
3340b167267bda99b68346045ccab14e810121d5de4Glenn Kasten{
335ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
336ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
337bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    IPlay *thiz = (IPlay *) self;
3385933f3d5e532aaac31ce0e6551c59f0197c0ae3cGlenn Kasten    bool significant = false;
339bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    interface_lock_exclusive(thiz);
3405933f3d5e532aaac31ce0e6551c59f0197c0ae3cGlenn Kasten    // clearing the marker position is equivalent to setting the marker to SL_TIME_UNKNOWN
3415933f3d5e532aaac31ce0e6551c59f0197c0ae3cGlenn Kasten    if (thiz->mMarkerPosition != SL_TIME_UNKNOWN) {
3425933f3d5e532aaac31ce0e6551c59f0197c0ae3cGlenn Kasten        thiz->mMarkerPosition = SL_TIME_UNKNOWN;
3435933f3d5e532aaac31ce0e6551c59f0197c0ae3cGlenn Kasten        if (thiz->mEventFlags & SL_PLAYEVENT_HEADATMARKER) {
3445933f3d5e532aaac31ce0e6551c59f0197c0ae3cGlenn Kasten            significant = true;
3455933f3d5e532aaac31ce0e6551c59f0197c0ae3cGlenn Kasten        }
3465933f3d5e532aaac31ce0e6551c59f0197c0ae3cGlenn Kasten    }
3475933f3d5e532aaac31ce0e6551c59f0197c0ae3cGlenn Kasten    if (significant) {
3485933f3d5e532aaac31ce0e6551c59f0197c0ae3cGlenn Kasten        interface_unlock_exclusive_attributes(thiz, ATTR_TRANSPORT);
3495933f3d5e532aaac31ce0e6551c59f0197c0ae3cGlenn Kasten    } else {
3505933f3d5e532aaac31ce0e6551c59f0197c0ae3cGlenn Kasten        interface_unlock_exclusive(thiz);
3516a7bf7733e955d4d89204627c34fb357d542a9ecJean-Michel Trivi    }
352ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    result = SL_RESULT_SUCCESS;
353ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
354ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
3550b167267bda99b68346045ccab14e810121d5de4Glenn Kasten}
3560b167267bda99b68346045ccab14e810121d5de4Glenn Kasten
357ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
3580b167267bda99b68346045ccab14e810121d5de4Glenn Kastenstatic SLresult IPlay_GetMarkerPosition(SLPlayItf self, SLmillisecond *pMsec)
3590b167267bda99b68346045ccab14e810121d5de4Glenn Kasten{
360ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
361ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
362ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    if (NULL == pMsec) {
363ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_PARAMETER_INVALID;
364ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    } else {
365bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        IPlay *thiz = (IPlay *) self;
3665933f3d5e532aaac31ce0e6551c59f0197c0ae3cGlenn Kasten        interface_lock_shared(thiz);
367bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        SLmillisecond markerPosition = thiz->mMarkerPosition;
3685933f3d5e532aaac31ce0e6551c59f0197c0ae3cGlenn Kasten        interface_unlock_shared(thiz);
369ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        *pMsec = markerPosition;
37045b349f3c585a0750417722f72224a35baaab734Glenn Kasten        if (SL_TIME_UNKNOWN == markerPosition) {
37145b349f3c585a0750417722f72224a35baaab734Glenn Kasten            result = SL_RESULT_PRECONDITIONS_VIOLATED;
37245b349f3c585a0750417722f72224a35baaab734Glenn Kasten        } else {
37345b349f3c585a0750417722f72224a35baaab734Glenn Kasten            result = SL_RESULT_SUCCESS;
37445b349f3c585a0750417722f72224a35baaab734Glenn Kasten        }
375ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    }
376ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
377ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
3780b167267bda99b68346045ccab14e810121d5de4Glenn Kasten}
3790b167267bda99b68346045ccab14e810121d5de4Glenn Kasten
380ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
3810b167267bda99b68346045ccab14e810121d5de4Glenn Kastenstatic SLresult IPlay_SetPositionUpdatePeriod(SLPlayItf self, SLmillisecond mSec)
3820b167267bda99b68346045ccab14e810121d5de4Glenn Kasten{
383ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
384ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
385ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    if (0 == mSec) {
386ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_PARAMETER_INVALID;
387ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    } else {
388bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        IPlay *thiz = (IPlay *) self;
3895933f3d5e532aaac31ce0e6551c59f0197c0ae3cGlenn Kasten        bool significant = false;
390bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        interface_lock_exclusive(thiz);
391bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        if (thiz->mPositionUpdatePeriod != mSec) {
392bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            thiz->mPositionUpdatePeriod = mSec;
3938c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten#ifdef USE_OUTPUTMIXEXT
394bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            if (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(thiz)) {
395bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                CAudioPlayer *audioPlayer = (CAudioPlayer *) thiz->mThis;
3968c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten                SLuint32 frameUpdatePeriod = ((long long) mSec *
3978c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten                    (long long) audioPlayer->mSampleRateMilliHz) / 1000000LL;
398ab7724988c1ff39ad3fc95a7ae0e638357708f7cGlenn Kasten                if (0 == frameUpdatePeriod) {
3998c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten                    frameUpdatePeriod = ~0;
400ab7724988c1ff39ad3fc95a7ae0e638357708f7cGlenn Kasten                }
401bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                thiz->mFrameUpdatePeriod = frameUpdatePeriod;
4028c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten                // setting a new update period postpones the next callback
403bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                thiz->mFramesSincePositionUpdate = 0;
4048c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            }
4058c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten#endif
4065933f3d5e532aaac31ce0e6551c59f0197c0ae3cGlenn Kasten            if (thiz->mEventFlags & SL_PLAYEVENT_HEADATNEWPOS) {
4075933f3d5e532aaac31ce0e6551c59f0197c0ae3cGlenn Kasten                significant = true;
4085933f3d5e532aaac31ce0e6551c59f0197c0ae3cGlenn Kasten            }
4095933f3d5e532aaac31ce0e6551c59f0197c0ae3cGlenn Kasten        }
4105933f3d5e532aaac31ce0e6551c59f0197c0ae3cGlenn Kasten        if (significant) {
411bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            interface_unlock_exclusive_attributes(thiz, ATTR_TRANSPORT);
41245b349f3c585a0750417722f72224a35baaab734Glenn Kasten        } else {
413bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            interface_unlock_exclusive(thiz);
41445b349f3c585a0750417722f72224a35baaab734Glenn Kasten        }
415ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_SUCCESS;
416ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    }
417ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
418ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
4190b167267bda99b68346045ccab14e810121d5de4Glenn Kasten}
4200b167267bda99b68346045ccab14e810121d5de4Glenn Kasten
421ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
422d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kastenstatic SLresult IPlay_GetPositionUpdatePeriod(SLPlayItf self, SLmillisecond *pMsec)
4230b167267bda99b68346045ccab14e810121d5de4Glenn Kasten{
424ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
425ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
426ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    if (NULL == pMsec) {
427ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_PARAMETER_INVALID;
428ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    } else {
429bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        IPlay *thiz = (IPlay *) self;
4305933f3d5e532aaac31ce0e6551c59f0197c0ae3cGlenn Kasten        interface_lock_shared(thiz);
431bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        SLmillisecond positionUpdatePeriod = thiz->mPositionUpdatePeriod;
4325933f3d5e532aaac31ce0e6551c59f0197c0ae3cGlenn Kasten        interface_unlock_shared(thiz);
433ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        *pMsec = positionUpdatePeriod;
434ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_SUCCESS;
435ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    }
436ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
437ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
4380b167267bda99b68346045ccab14e810121d5de4Glenn Kasten}
4390b167267bda99b68346045ccab14e810121d5de4Glenn Kasten
440ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
4410b167267bda99b68346045ccab14e810121d5de4Glenn Kastenstatic const struct SLPlayItf_ IPlay_Itf = {
4420b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IPlay_SetPlayState,
4430b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IPlay_GetPlayState,
4440b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IPlay_GetDuration,
4450b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IPlay_GetPosition,
4460b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IPlay_RegisterCallback,
4470b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IPlay_SetCallbackEventsMask,
4480b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IPlay_GetCallbackEventsMask,
4490b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IPlay_SetMarkerPosition,
4500b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IPlay_ClearMarkerPosition,
4510b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IPlay_GetMarkerPosition,
4520b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IPlay_SetPositionUpdatePeriod,
4530b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IPlay_GetPositionUpdatePeriod
4540b167267bda99b68346045ccab14e810121d5de4Glenn Kasten};
4550b167267bda99b68346045ccab14e810121d5de4Glenn Kasten
4560b167267bda99b68346045ccab14e810121d5de4Glenn Kastenvoid IPlay_init(void *self)
4570b167267bda99b68346045ccab14e810121d5de4Glenn Kasten{
458bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    IPlay *thiz = (IPlay *) self;
459bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mItf = &IPlay_Itf;
460bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mState = SL_PLAYSTATE_STOPPED;
461bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mDuration = SL_TIME_UNKNOWN;  // will be set by containing player object
462bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mPosition = (SLmillisecond) 0;
463bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mCallback = NULL;
464bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mContext = NULL;
465bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mEventFlags = 0;
4665933f3d5e532aaac31ce0e6551c59f0197c0ae3cGlenn Kasten    thiz->mMarkerPosition = SL_TIME_UNKNOWN;
4675933f3d5e532aaac31ce0e6551c59f0197c0ae3cGlenn Kasten    thiz->mPositionUpdatePeriod = 1000; // per spec
4688c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten#ifdef USE_OUTPUTMIXEXT
469bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mFrameUpdatePeriod = 0;   // because we don't know the sample rate yet
470bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mLastSeekPosition = 0;
471bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mFramesSinceLastSeek = 0;
472bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mFramesSincePositionUpdate = 0;
4738c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten#endif
4740b167267bda99b68346045ccab14e810121d5de4Glenn Kasten}
475