IPlay.c revision bcc5c7225e3b7a1dbf2e9e830987f69167acf06f
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);
394b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten#ifdef USE_OUTPUTMIXEXT
40bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        for (;; interface_cond_wait(thiz)) {
414b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
424b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            // We are comparing the old state (left) vs. new state (right).
434b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            // Note that the old state is 3 bits wide, but new state is only 2 bits wide.
444b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            // That is why the old state is on the left and new state is on the right.
45bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            switch ((thiz->mState << 2) | state) {
464b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
474b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            case (SL_PLAYSTATE_STOPPED  << 2) | SL_PLAYSTATE_STOPPED:
484b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            case (SL_PLAYSTATE_PAUSED   << 2) | SL_PLAYSTATE_PAUSED:
494b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            case (SL_PLAYSTATE_PLAYING  << 2) | SL_PLAYSTATE_PLAYING:
504b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten               // no-op
514b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                break;
524b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
534b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            case (SL_PLAYSTATE_STOPPED  << 2) | SL_PLAYSTATE_PLAYING:
544b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            case (SL_PLAYSTATE_PAUSED   << 2) | SL_PLAYSTATE_PLAYING:
554b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                attr = ATTR_TRANSPORT;
564b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                // set enqueue attribute if queue is non-empty and state becomes PLAYING
574b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                if ((NULL != audioPlayer) && (audioPlayer->mBufferQueue.mFront !=
584b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    audioPlayer->mBufferQueue.mRear)) {
594b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    attr |= ATTR_ENQUEUE;
604b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                }
614b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                // fall through
624b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
634b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            case (SL_PLAYSTATE_STOPPED  << 2) | SL_PLAYSTATE_PAUSED:
644b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            case (SL_PLAYSTATE_PLAYING  << 2) | SL_PLAYSTATE_PAUSED:
654b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                // easy
66bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                thiz->mState = state;
674b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                break;
684b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
694b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            case (SL_PLAYSTATE_STOPPING << 2) | SL_PLAYSTATE_STOPPED:
704b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                // either spurious wakeup, or someone else requested same transition
714b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                continue;
724b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
734b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            case (SL_PLAYSTATE_STOPPING << 2) | SL_PLAYSTATE_PAUSED:
744b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            case (SL_PLAYSTATE_STOPPING << 2) | SL_PLAYSTATE_PLAYING:
754b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                // wait for other guy to finish his transition, then retry ours
764b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                continue;
774b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
784b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            case (SL_PLAYSTATE_PAUSED   << 2) | SL_PLAYSTATE_STOPPED:
794b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            case (SL_PLAYSTATE_PLAYING  << 2) | SL_PLAYSTATE_STOPPED:
804b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                // tell mixer to stop, then wait for mixer to acknowledge the request to stop
81bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                thiz->mState = SL_PLAYSTATE_STOPPING;
824b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                continue;
834b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
844b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            default:
854b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                // unexpected state
864b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                assert(SL_BOOLEAN_FALSE);
874b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                result = SL_RESULT_INTERNAL_ERROR;
884b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                break;
894b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
904b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            }
914b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
924b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            break;
934b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        }
944b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten#else
954b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        // Here life looks easy for an Android, but there are other troubles in play land
96bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        thiz->mState = state;
974b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        attr = ATTR_TRANSPORT;
984b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten#endif
991d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten        // SL_LOGD("set play state %ld", state);
100bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        interface_unlock_exclusive_attributes(thiz, attr);
101ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        }
1020b167267bda99b68346045ccab14e810121d5de4Glenn Kasten        break;
1030b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    default:
104ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_PARAMETER_INVALID;
1054b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        break;
1060b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    }
107ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
108ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
1090b167267bda99b68346045ccab14e810121d5de4Glenn Kasten}
1100b167267bda99b68346045ccab14e810121d5de4Glenn Kasten
111ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
1120b167267bda99b68346045ccab14e810121d5de4Glenn Kastenstatic SLresult IPlay_GetPlayState(SLPlayItf self, SLuint32 *pState)
1130b167267bda99b68346045ccab14e810121d5de4Glenn Kasten{
114ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
115ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
116ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    if (NULL == pState) {
117ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_PARAMETER_INVALID;
118ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    } else {
119bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        IPlay *thiz = (IPlay *) self;
120bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        interface_lock_peek(thiz);
121bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        SLuint32 state = thiz->mState;
122bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        interface_unlock_peek(thiz);
123ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_SUCCESS;
1244b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten#ifdef USE_OUTPUTMIXEXT
1254b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        switch (state) {
1264b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        case SL_PLAYSTATE_STOPPED:  // as is
1274b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        case SL_PLAYSTATE_PAUSED:
1284b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        case SL_PLAYSTATE_PLAYING:
1294b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            break;
1304b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        case SL_PLAYSTATE_STOPPING: // these states require re-mapping
1314b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            state = SL_PLAYSTATE_STOPPED;
1324b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            break;
1334b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        default:                    // impossible
1344b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            assert(SL_BOOLEAN_FALSE);
1354b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            state = SL_PLAYSTATE_STOPPED;
1364b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            result = SL_RESULT_INTERNAL_ERROR;
1374b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            break;
1384b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        }
1394b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten#endif
1404b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        *pState = state;
141ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    }
142ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
143ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
1440b167267bda99b68346045ccab14e810121d5de4Glenn Kasten}
1450b167267bda99b68346045ccab14e810121d5de4Glenn Kasten
146ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
1470b167267bda99b68346045ccab14e810121d5de4Glenn Kastenstatic SLresult IPlay_GetDuration(SLPlayItf self, SLmillisecond *pMsec)
1480b167267bda99b68346045ccab14e810121d5de4Glenn Kasten{
149ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
150ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
151ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    if (NULL == pMsec) {
152ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_PARAMETER_INVALID;
153ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    } else {
154ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_SUCCESS;
155bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        IPlay *thiz = (IPlay *) self;
156ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        // even though this is a getter, it can modify state due to caching
157bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        interface_lock_exclusive(thiz);
158bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        SLmillisecond duration = thiz->mDuration;
159ef8931ae547cd703e69df9ad350d69825da0f546Jean-Michel Trivi#ifdef ANDROID
160ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        if ((SL_TIME_UNKNOWN == duration) &&
161bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(thiz))) {
162ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            SLmillisecond temp;
163bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            result = android_audioPlayer_getDuration(thiz, &temp);
164ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            if (SL_RESULT_SUCCESS == result) {
165ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                duration = temp;
166bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                thiz->mDuration = duration;
167ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            }
168e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten        }
169e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten#else
1708c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        // will be set by containing AudioPlayer or MidiPlayer object at Realize, if known,
1718c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        // otherwise the duration will be updated each time a new maximum position is detected
172dc181a4a041fe4be7c91b92646b236b6d652f4a3Jean-Michel Trivi#endif
173bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        interface_unlock_exclusive(thiz);
174ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        *pMsec = duration;
175ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    }
176ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
177ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
1780b167267bda99b68346045ccab14e810121d5de4Glenn Kasten}
1790b167267bda99b68346045ccab14e810121d5de4Glenn Kasten
180ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
1810b167267bda99b68346045ccab14e810121d5de4Glenn Kastenstatic SLresult IPlay_GetPosition(SLPlayItf self, SLmillisecond *pMsec)
1820b167267bda99b68346045ccab14e810121d5de4Glenn Kasten{
183ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
184ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
185ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    if (NULL == pMsec) {
186ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_PARAMETER_INVALID;
187ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    } else {
188bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        IPlay *thiz = (IPlay *) self;
189ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        SLmillisecond position;
190bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        interface_lock_shared(thiz);
191ef8931ae547cd703e69df9ad350d69825da0f546Jean-Michel Trivi#ifdef ANDROID
192ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        // Android does not use the mPosition field for audio players
193bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        if (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(thiz)) {
194bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            android_audioPlayer_getPosition(thiz, &position);
195ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            // note that we do not cache the position
1968c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        } else {
197bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            position = thiz->mPosition;
1988c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        }
199e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten#else
200ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        // on other platforms we depend on periodic updates to the current position
201bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        position = thiz->mPosition;
2028c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        // if a seek is pending, then lie about current position so the seek appears synchronous
203bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        if (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(thiz)) {
204bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            CAudioPlayer *audioPlayer = (CAudioPlayer *) thiz->mThis;
2058c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            SLmillisecond pos = audioPlayer->mSeek.mPos;
2068c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            if (SL_TIME_UNKNOWN != pos) {
2078c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten                position = pos;
2088c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            }
2098c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        }
2106a7bf7733e955d4d89204627c34fb357d542a9ecJean-Michel Trivi#endif
211bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        interface_unlock_shared(thiz);
212ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        *pMsec = position;
213ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_SUCCESS;
214ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    }
215ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
216ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
2170b167267bda99b68346045ccab14e810121d5de4Glenn Kasten}
2180b167267bda99b68346045ccab14e810121d5de4Glenn Kasten
219ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
220d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kastenstatic SLresult IPlay_RegisterCallback(SLPlayItf self, slPlayCallback callback, void *pContext)
2210b167267bda99b68346045ccab14e810121d5de4Glenn Kasten{
222ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
223ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
224bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    IPlay *thiz = (IPlay *) self;
225bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    interface_lock_exclusive(thiz);
226bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mCallback = callback;
227bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mContext = pContext;
228e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    // omits _attributes b/c noone cares deeply enough about these fields to need quick notification
229bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    interface_unlock_exclusive(thiz);
230ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    result = SL_RESULT_SUCCESS;
231ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
232ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
2330b167267bda99b68346045ccab14e810121d5de4Glenn Kasten}
2340b167267bda99b68346045ccab14e810121d5de4Glenn Kasten
235ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
2360b167267bda99b68346045ccab14e810121d5de4Glenn Kastenstatic SLresult IPlay_SetCallbackEventsMask(SLPlayItf self, SLuint32 eventFlags)
2370b167267bda99b68346045ccab14e810121d5de4Glenn Kasten{
238ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
239ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
2408c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    if (eventFlags & ~(SL_PLAYEVENT_HEADATEND | SL_PLAYEVENT_HEADATMARKER |
2418c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            SL_PLAYEVENT_HEADATNEWPOS | SL_PLAYEVENT_HEADMOVING | SL_PLAYEVENT_HEADSTALLED)) {
2428c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        result = SL_RESULT_PARAMETER_INVALID;
2438c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    } else {
244bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        IPlay *thiz = (IPlay *) self;
245bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        interface_lock_exclusive(thiz);
246bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        if (thiz->mEventFlags != eventFlags) {
2478c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten#ifdef USE_OUTPUTMIXEXT
2488c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            // enabling the "head at new position" play event will postpone the next update event
249bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            if (!(thiz->mEventFlags & SL_PLAYEVENT_HEADATNEWPOS) &&
2508c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten                    (eventFlags & SL_PLAYEVENT_HEADATNEWPOS)) {
251bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                thiz->mFramesSincePositionUpdate = 0;
2528c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            }
2538c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten#endif
254bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            thiz->mEventFlags = eventFlags;
255bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            interface_unlock_exclusive_attributes(thiz, ATTR_TRANSPORT);
2568c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        } else
257bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            interface_unlock_exclusive(thiz);
2588c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        result = SL_RESULT_SUCCESS;
2598c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    }
260ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
261ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
2620b167267bda99b68346045ccab14e810121d5de4Glenn Kasten}
2630b167267bda99b68346045ccab14e810121d5de4Glenn Kasten
264ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
265d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kastenstatic SLresult IPlay_GetCallbackEventsMask(SLPlayItf self, SLuint32 *pEventFlags)
2660b167267bda99b68346045ccab14e810121d5de4Glenn Kasten{
267ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
268ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
269ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    if (NULL == pEventFlags) {
270ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_PARAMETER_INVALID;
271ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    } else {
272bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        IPlay *thiz = (IPlay *) self;
273bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        interface_lock_peek(thiz);
274bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        SLuint32 eventFlags = thiz->mEventFlags;
275bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        interface_unlock_peek(thiz);
276ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        *pEventFlags = eventFlags;
277ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_SUCCESS;
278ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    }
279ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
280ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
2810b167267bda99b68346045ccab14e810121d5de4Glenn Kasten}
2820b167267bda99b68346045ccab14e810121d5de4Glenn Kasten
283ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
2840b167267bda99b68346045ccab14e810121d5de4Glenn Kastenstatic SLresult IPlay_SetMarkerPosition(SLPlayItf self, SLmillisecond mSec)
2850b167267bda99b68346045ccab14e810121d5de4Glenn Kasten{
286ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
287ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
288bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    IPlay *thiz = (IPlay *) self;
289bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    interface_lock_exclusive(thiz);
290bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    if (thiz->mMarkerPosition != mSec) {
291bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        thiz->mMarkerPosition = mSec;
292bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        interface_unlock_exclusive_attributes(thiz, ATTR_TRANSPORT);
293e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    } else
294bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        interface_unlock_exclusive(thiz);
295ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    result = SL_RESULT_SUCCESS;
296ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
297ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
2980b167267bda99b68346045ccab14e810121d5de4Glenn Kasten}
2990b167267bda99b68346045ccab14e810121d5de4Glenn Kasten
300ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
3010b167267bda99b68346045ccab14e810121d5de4Glenn Kastenstatic SLresult IPlay_ClearMarkerPosition(SLPlayItf self)
3020b167267bda99b68346045ccab14e810121d5de4Glenn Kasten{
303ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
304ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
305bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    IPlay *thiz = (IPlay *) self;
306bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    interface_lock_exclusive(thiz);
307ef8931ae547cd703e69df9ad350d69825da0f546Jean-Michel Trivi#ifdef ANDROID
308bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    if (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(thiz)) {
3093b142e50f4ae068f50f8e3d277e0f19910c67001Jean-Michel Trivi        // clearing the marker position is equivalent to setting the marker at 0
310bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        thiz->mMarkerPosition = 0;
3116a7bf7733e955d4d89204627c34fb357d542a9ecJean-Michel Trivi    }
3126a7bf7733e955d4d89204627c34fb357d542a9ecJean-Michel Trivi#endif
313bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    interface_unlock_exclusive_attributes(thiz, ATTR_TRANSPORT);
314ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    result = SL_RESULT_SUCCESS;
315ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
316ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
3170b167267bda99b68346045ccab14e810121d5de4Glenn Kasten}
3180b167267bda99b68346045ccab14e810121d5de4Glenn Kasten
319ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
3200b167267bda99b68346045ccab14e810121d5de4Glenn Kastenstatic SLresult IPlay_GetMarkerPosition(SLPlayItf self, SLmillisecond *pMsec)
3210b167267bda99b68346045ccab14e810121d5de4Glenn Kasten{
322ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
323ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
324ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    if (NULL == pMsec) {
325ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_PARAMETER_INVALID;
326ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    } else {
327bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        IPlay *thiz = (IPlay *) self;
328bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        interface_lock_peek(thiz);
329bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        SLmillisecond markerPosition = thiz->mMarkerPosition;
330bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        interface_unlock_peek(thiz);
331ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        *pMsec = markerPosition;
332ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_SUCCESS;
333ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    }
334ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
335ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
3360b167267bda99b68346045ccab14e810121d5de4Glenn Kasten}
3370b167267bda99b68346045ccab14e810121d5de4Glenn Kasten
338ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
3390b167267bda99b68346045ccab14e810121d5de4Glenn Kastenstatic SLresult IPlay_SetPositionUpdatePeriod(SLPlayItf self, SLmillisecond mSec)
3400b167267bda99b68346045ccab14e810121d5de4Glenn Kasten{
341ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
342ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
343ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    if (0 == mSec) {
344ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_PARAMETER_INVALID;
345ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    } else {
346bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        IPlay *thiz = (IPlay *) self;
347bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        interface_lock_exclusive(thiz);
348bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        if (thiz->mPositionUpdatePeriod != mSec) {
349bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            thiz->mPositionUpdatePeriod = mSec;
350ef8931ae547cd703e69df9ad350d69825da0f546Jean-Michel Trivi#ifdef ANDROID
351bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            if (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(thiz)) {
352bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                // result = android_audioPlayer_useEventMask(thiz, thiz->mEventFlags);
353ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            }
3546a7bf7733e955d4d89204627c34fb357d542a9ecJean-Michel Trivi#endif
3558c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten#ifdef USE_OUTPUTMIXEXT
356bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            if (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(thiz)) {
357bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                CAudioPlayer *audioPlayer = (CAudioPlayer *) thiz->mThis;
3588c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten                SLuint32 frameUpdatePeriod = ((long long) mSec *
3598c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten                    (long long) audioPlayer->mSampleRateMilliHz) / 1000000LL;
3608c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten                if (0 == frameUpdatePeriod)
3618c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten                    frameUpdatePeriod = ~0;
362bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                thiz->mFrameUpdatePeriod = frameUpdatePeriod;
3638c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten                // setting a new update period postpones the next callback
364bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                thiz->mFramesSincePositionUpdate = 0;
3658c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            }
3668c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten#endif
367bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            interface_unlock_exclusive_attributes(thiz, ATTR_TRANSPORT);
368ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        } else
369bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            interface_unlock_exclusive(thiz);
370ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_SUCCESS;
371ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    }
372ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
373ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
3740b167267bda99b68346045ccab14e810121d5de4Glenn Kasten}
3750b167267bda99b68346045ccab14e810121d5de4Glenn Kasten
376ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
377d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kastenstatic SLresult IPlay_GetPositionUpdatePeriod(SLPlayItf self, SLmillisecond *pMsec)
3780b167267bda99b68346045ccab14e810121d5de4Glenn Kasten{
379ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
380ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
381ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    if (NULL == pMsec) {
382ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_PARAMETER_INVALID;
383ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    } else {
384bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        IPlay *thiz = (IPlay *) self;
385bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        interface_lock_peek(thiz);
386bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        SLmillisecond positionUpdatePeriod = thiz->mPositionUpdatePeriod;
387bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        interface_unlock_peek(thiz);
388ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        *pMsec = positionUpdatePeriod;
389ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_SUCCESS;
390ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    }
391ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
392ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
3930b167267bda99b68346045ccab14e810121d5de4Glenn Kasten}
3940b167267bda99b68346045ccab14e810121d5de4Glenn Kasten
395ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
3960b167267bda99b68346045ccab14e810121d5de4Glenn Kastenstatic const struct SLPlayItf_ IPlay_Itf = {
3970b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IPlay_SetPlayState,
3980b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IPlay_GetPlayState,
3990b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IPlay_GetDuration,
4000b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IPlay_GetPosition,
4010b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IPlay_RegisterCallback,
4020b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IPlay_SetCallbackEventsMask,
4030b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IPlay_GetCallbackEventsMask,
4040b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IPlay_SetMarkerPosition,
4050b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IPlay_ClearMarkerPosition,
4060b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IPlay_GetMarkerPosition,
4070b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IPlay_SetPositionUpdatePeriod,
4080b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    IPlay_GetPositionUpdatePeriod
4090b167267bda99b68346045ccab14e810121d5de4Glenn Kasten};
4100b167267bda99b68346045ccab14e810121d5de4Glenn Kasten
4110b167267bda99b68346045ccab14e810121d5de4Glenn Kastenvoid IPlay_init(void *self)
4120b167267bda99b68346045ccab14e810121d5de4Glenn Kasten{
413bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    IPlay *thiz = (IPlay *) self;
414bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mItf = &IPlay_Itf;
415bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mState = SL_PLAYSTATE_STOPPED;
416bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mDuration = SL_TIME_UNKNOWN;  // will be set by containing player object
417bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mPosition = (SLmillisecond) 0;
418bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mCallback = NULL;
419bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mContext = NULL;
420bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mEventFlags = 0;
421bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mMarkerPosition = 0;
422bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mPositionUpdatePeriod = 1000;
4238c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten#ifdef USE_OUTPUTMIXEXT
424bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mFrameUpdatePeriod = 0;   // because we don't know the sample rate yet
425bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mLastSeekPosition = 0;
426bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mFramesSinceLastSeek = 0;
427bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mFramesSincePositionUpdate = 0;
4288c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten#endif
4290b167267bda99b68346045ccab14e810121d5de4Glenn Kasten}
430