IPlay.c revision a8179ea15c4ff78db589d742b135649f0eda7ef2
1b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat/*
2b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat * Copyright (C) 2010 The Android Open Source Project
3b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat *
4b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat * Licensed under the Apache License, Version 2.0 (the "License");
5b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat * you may not use this file except in compliance with the License.
6b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat * You may obtain a copy of the License at
7b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat *
8b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat *      http://www.apache.org/licenses/LICENSE-2.0
9b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat *
10b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat * Unless required by applicable law or agreed to in writing, software
11b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat * distributed under the License is distributed on an "AS IS" BASIS,
12b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat * See the License for the specific language governing permissions and
14b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat * limitations under the License.
15b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat */
16b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat
17b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat/* Play implementation */
18b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat
19b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat#include "sles_allinclusive.h"
20b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat
21b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat
22b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehatstatic SLresult IPlay_SetPlayState(SLPlayItf self, SLuint32 state)
23b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat{
24b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    SL_ENTER_INTERFACE
25b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat
26b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    switch (state) {
27d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    case SL_PLAYSTATE_STOPPED:
28d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    case SL_PLAYSTATE_PAUSED:
29b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    case SL_PLAYSTATE_PLAYING:
30b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        {
31b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        IPlay *thiz = (IPlay *) self;
32b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        unsigned attr = ATTR_NONE;
33d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        result = SL_RESULT_SUCCESS;
34d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat#ifdef USE_OUTPUTMIXEXT
35b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        CAudioPlayer *audioPlayer = (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(thiz)) ?
36b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat            (CAudioPlayer *) thiz->mThis : NULL;
37d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat#endif
38d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        interface_lock_exclusive(thiz);
39d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat#ifdef USE_OUTPUTMIXEXT
40d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        for (;; interface_cond_wait(thiz)) {
41d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat
42d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat            // We are comparing the old state (left) vs. new state (right).
43d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat            // Note that the old state is 3 bits wide, but new state is only 2 bits wide.
44d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat            // That is why the old state is on the left and new state is on the right.
45d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat            switch ((thiz->mState << 2) | state) {
46d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat
47d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat            case (SL_PLAYSTATE_STOPPED  << 2) | SL_PLAYSTATE_STOPPED:
48d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat            case (SL_PLAYSTATE_PAUSED   << 2) | SL_PLAYSTATE_PAUSED:
49d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat            case (SL_PLAYSTATE_PLAYING  << 2) | SL_PLAYSTATE_PLAYING:
50d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat               // no-op
51d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                break;
52d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat
53d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat            case (SL_PLAYSTATE_STOPPED  << 2) | SL_PLAYSTATE_PLAYING:
54d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat            case (SL_PLAYSTATE_PAUSED   << 2) | SL_PLAYSTATE_PLAYING:
55d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                attr = ATTR_TRANSPORT;
56d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                // set enqueue attribute if queue is non-empty and state becomes PLAYING
57d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                if ((NULL != audioPlayer) && (audioPlayer->mBufferQueue.mFront !=
58d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                    audioPlayer->mBufferQueue.mRear)) {
59d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                    attr |= ATTR_BQ_ENQUEUE;
60d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                }
61d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                // fall through
62d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat
63d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat            case (SL_PLAYSTATE_STOPPED  << 2) | SL_PLAYSTATE_PAUSED:
64d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat            case (SL_PLAYSTATE_PLAYING  << 2) | SL_PLAYSTATE_PAUSED:
65d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                // easy
66d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                thiz->mState = state;
67d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                break;
68d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat
69d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat            case (SL_PLAYSTATE_STOPPING << 2) | SL_PLAYSTATE_STOPPED:
70d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                // either spurious wakeup, or someone else requested same transition
71d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                continue;
72d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat
73d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat            case (SL_PLAYSTATE_STOPPING << 2) | SL_PLAYSTATE_PAUSED:
74d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat            case (SL_PLAYSTATE_STOPPING << 2) | SL_PLAYSTATE_PLAYING:
75d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                // wait for other guy to finish his transition, then retry ours
76d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                continue;
77d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat
78d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat            case (SL_PLAYSTATE_PAUSED   << 2) | SL_PLAYSTATE_STOPPED:
79d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat            case (SL_PLAYSTATE_PLAYING  << 2) | SL_PLAYSTATE_STOPPED:
80d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                // tell mixer to stop, then wait for mixer to acknowledge the request to stop
81d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                thiz->mState = SL_PLAYSTATE_STOPPING;
82d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                continue;
83d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat
84d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat            default:
85d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                // unexpected state
86d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                assert(SL_BOOLEAN_FALSE);
87d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                result = SL_RESULT_INTERNAL_ERROR;
88d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                break;
89d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat
90d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat            }
91d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat
92d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat            break;
93d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        }
94d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat#else
95d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        // Here life looks easy for an Android, but there are other troubles in play land
96d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        thiz->mState = state;
97d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        attr = ATTR_TRANSPORT;
98d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat#endif
99d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        // SL_LOGD("set play state %d", state);
100d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        interface_unlock_exclusive_attributes(thiz, attr);
101d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        }
102d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        break;
103d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    default:
104d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        result = SL_RESULT_PARAMETER_INVALID;
105d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        break;
106d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    }
107d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat
108d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    SL_LEAVE_INTERFACE
109d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat}
110d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat
111d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat
112d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehatstatic SLresult IPlay_GetPlayState(SLPlayItf self, SLuint32 *pState)
113b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat{
114b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    SL_ENTER_INTERFACE
115b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat
116b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    if (NULL == pState) {
117b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        result = SL_RESULT_PARAMETER_INVALID;
118b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    } else {
119b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        IPlay *thiz = (IPlay *) self;
120b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        interface_lock_peek(thiz);
121b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        SLuint32 state = thiz->mState;
122d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        interface_unlock_peek(thiz);
123d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        result = SL_RESULT_SUCCESS;
124d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat#ifdef USE_OUTPUTMIXEXT
125b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        switch (state) {
126b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        case SL_PLAYSTATE_STOPPED:  // as is
127b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        case SL_PLAYSTATE_PAUSED:
128b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        case SL_PLAYSTATE_PLAYING:
129b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat            break;
130b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        case SL_PLAYSTATE_STOPPING: // these states require re-mapping
131b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat            state = SL_PLAYSTATE_STOPPED;
132b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat            break;
133b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        default:                    // impossible
134b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat            assert(SL_BOOLEAN_FALSE);
135b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat            state = SL_PLAYSTATE_STOPPED;
136b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat            result = SL_RESULT_INTERNAL_ERROR;
137b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat            break;
138b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        }
139b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat#endif
140b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        *pState = state;
141b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    }
142b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat
143b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    SL_LEAVE_INTERFACE
144b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat}
1458b8f71b1d760411279f3b07a5c97709f052c689eSan Mehat
1468b8f71b1d760411279f3b07a5c97709f052c689eSan Mehat
147b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehatstatic SLresult IPlay_GetDuration(SLPlayItf self, SLmillisecond *pMsec)
148b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat{
149b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    SL_ENTER_INTERFACE
150b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat
151b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    if (NULL == pMsec) {
152b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        result = SL_RESULT_PARAMETER_INVALID;
153b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    } else {
154b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        result = SL_RESULT_SUCCESS;
155b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        IPlay *thiz = (IPlay *) self;
156b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        // even though this is a getter, it can modify state due to caching
157b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        interface_lock_exclusive(thiz);
158b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        SLmillisecond duration = thiz->mDuration;
159b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat#ifdef ANDROID
1608b8f71b1d760411279f3b07a5c97709f052c689eSan Mehat        if ((SL_TIME_UNKNOWN == duration) &&
1618b8f71b1d760411279f3b07a5c97709f052c689eSan Mehat            (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(thiz))) {
162b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat            SLmillisecond temp;
163b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat            result = android_audioPlayer_getDuration(thiz, &temp);
164b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat            if (SL_RESULT_SUCCESS == result) {
165b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat                duration = temp;
166b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat                thiz->mDuration = duration;
167b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat            }
168b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        }
169b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat#else
170b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        // will be set by containing AudioPlayer or MidiPlayer object at Realize, if known,
171b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        // otherwise the duration will be updated each time a new maximum position is detected
172b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat#endif
173b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        interface_unlock_exclusive(thiz);
174b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        *pMsec = duration;
175b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    }
176b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat
177b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    SL_LEAVE_INTERFACE
178b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat}
179b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat
180b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat
181b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehatstatic SLresult IPlay_GetPosition(SLPlayItf self, SLmillisecond *pMsec)
182b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat{
183b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    SL_ENTER_INTERFACE
184b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat
185b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    if (NULL == pMsec) {
186b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        result = SL_RESULT_PARAMETER_INVALID;
187b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    } else {
188b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        IPlay *thiz = (IPlay *) self;
189b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        SLmillisecond position;
190b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        interface_lock_shared(thiz);
191b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat#ifdef ANDROID
192b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        // Android does not use the mPosition field for audio players
193b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        if (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(thiz)) {
194b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat            android_audioPlayer_getPosition(thiz, &position);
195b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat            // note that we do not cache the position
196b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        } else {
197b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat            position = thiz->mPosition;
198b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        }
199b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat#else
200b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        // on other platforms we depend on periodic updates to the current position
201b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        position = thiz->mPosition;
202b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        // if a seek is pending, then lie about current position so the seek appears synchronous
203b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        if (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(thiz)) {
204b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat            CAudioPlayer *audioPlayer = (CAudioPlayer *) thiz->mThis;
2058b8f71b1d760411279f3b07a5c97709f052c689eSan Mehat            SLmillisecond pos = audioPlayer->mSeek.mPos;
206b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat            if (SL_TIME_UNKNOWN != pos) {
207b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat                position = pos;
208b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat            }
209b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        }
210b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat#endif
211b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        interface_unlock_shared(thiz);
212b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        *pMsec = position;
213b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        result = SL_RESULT_SUCCESS;
214b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    }
215b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat
216b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    SL_LEAVE_INTERFACE
217b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat}
218b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat
219b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat
220b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehatstatic SLresult IPlay_RegisterCallback(SLPlayItf self, slPlayCallback callback, void *pContext)
221fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat{
222b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    SL_ENTER_INTERFACE
2238b8f71b1d760411279f3b07a5c97709f052c689eSan Mehat
224fcf24fe62f98c5d44431aa575555569c2c7a29b0San Mehat    IPlay *thiz = (IPlay *) self;
225b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    interface_lock_exclusive(thiz);
226b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    thiz->mCallback = callback;
227b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    thiz->mContext = pContext;
228b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    // omits _attributes b/c noone cares deeply enough about these fields to need quick notification
229b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    interface_unlock_exclusive(thiz);
230b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    result = SL_RESULT_SUCCESS;
231b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat
232b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    SL_LEAVE_INTERFACE
233b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat}
234b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat
235b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat
236b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehatstatic SLresult IPlay_SetCallbackEventsMask(SLPlayItf self, SLuint32 eventFlags)
237b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat{
238b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    SL_ENTER_INTERFACE
239b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat
240b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    if (eventFlags & ~(SL_PLAYEVENT_HEADATEND | SL_PLAYEVENT_HEADATMARKER |
241b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat            SL_PLAYEVENT_HEADATNEWPOS | SL_PLAYEVENT_HEADMOVING | SL_PLAYEVENT_HEADSTALLED)) {
242b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        result = SL_RESULT_PARAMETER_INVALID;
243b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    } else {
244b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        IPlay *thiz = (IPlay *) self;
245b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        interface_lock_exclusive(thiz);
246b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        if (thiz->mEventFlags != eventFlags) {
247b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat#ifdef USE_OUTPUTMIXEXT
248b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat            // enabling the "head at new position" play event will postpone the next update event
249b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat            if (!(thiz->mEventFlags & SL_PLAYEVENT_HEADATNEWPOS) &&
250b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat                    (eventFlags & SL_PLAYEVENT_HEADATNEWPOS)) {
251b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat                thiz->mFramesSincePositionUpdate = 0;
2528c940ef7dbd423cadc92982b44a65ed1014389e2San Mehat            }
253b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat#endif
254b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat            thiz->mEventFlags = eventFlags;
255b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat            interface_unlock_exclusive_attributes(thiz, ATTR_TRANSPORT);
256b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        } else
257b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat            interface_unlock_exclusive(thiz);
258b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        result = SL_RESULT_SUCCESS;
259b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    }
260b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat
261b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    SL_LEAVE_INTERFACE
262b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat}
263b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat
264b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat
265b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehatstatic SLresult IPlay_GetCallbackEventsMask(SLPlayItf self, SLuint32 *pEventFlags)
266b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat{
267b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    SL_ENTER_INTERFACE
268b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat
269b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    if (NULL == pEventFlags) {
270b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        result = SL_RESULT_PARAMETER_INVALID;
271b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    } else {
272b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        IPlay *thiz = (IPlay *) self;
273b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        interface_lock_peek(thiz);
274b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        SLuint32 eventFlags = thiz->mEventFlags;
275b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        interface_unlock_peek(thiz);
2760586d54053ee00e6d6523d4f125282ccb9a24aabSan Mehat        *pEventFlags = eventFlags;
2770586d54053ee00e6d6523d4f125282ccb9a24aabSan Mehat        result = SL_RESULT_SUCCESS;
2780586d54053ee00e6d6523d4f125282ccb9a24aabSan Mehat    }
279b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat
280b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    SL_LEAVE_INTERFACE
281b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat}
282b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat
283b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat
284b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehatstatic SLresult IPlay_SetMarkerPosition(SLPlayItf self, SLmillisecond mSec)
285b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat{
286b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    SL_ENTER_INTERFACE
287b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat
288b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    IPlay *thiz = (IPlay *) self;
289b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    interface_lock_exclusive(thiz);
290b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    if (thiz->mMarkerPosition != mSec) {
291b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        thiz->mMarkerPosition = mSec;
292b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        interface_unlock_exclusive_attributes(thiz, ATTR_TRANSPORT);
293b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    } else
294b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat        interface_unlock_exclusive(thiz);
295b78a32c1d5eeb243bdac0eaf18effb1897f1ee67San Mehat    result = SL_RESULT_SUCCESS;
296
297    SL_LEAVE_INTERFACE
298}
299
300
301static SLresult IPlay_ClearMarkerPosition(SLPlayItf self)
302{
303    SL_ENTER_INTERFACE
304
305    IPlay *thiz = (IPlay *) self;
306    interface_lock_exclusive(thiz);
307#ifdef ANDROID
308    if (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(thiz)) {
309        // clearing the marker position is equivalent to setting the marker at 0
310        thiz->mMarkerPosition = 0;
311    }
312#endif
313    interface_unlock_exclusive_attributes(thiz, ATTR_TRANSPORT);
314    result = SL_RESULT_SUCCESS;
315
316    SL_LEAVE_INTERFACE
317}
318
319
320static SLresult IPlay_GetMarkerPosition(SLPlayItf self, SLmillisecond *pMsec)
321{
322    SL_ENTER_INTERFACE
323
324    if (NULL == pMsec) {
325        result = SL_RESULT_PARAMETER_INVALID;
326    } else {
327        IPlay *thiz = (IPlay *) self;
328        interface_lock_peek(thiz);
329        SLmillisecond markerPosition = thiz->mMarkerPosition;
330        interface_unlock_peek(thiz);
331        *pMsec = markerPosition;
332        result = SL_RESULT_SUCCESS;
333    }
334
335    SL_LEAVE_INTERFACE
336}
337
338
339static SLresult IPlay_SetPositionUpdatePeriod(SLPlayItf self, SLmillisecond mSec)
340{
341    SL_ENTER_INTERFACE
342
343    if (0 == mSec) {
344        result = SL_RESULT_PARAMETER_INVALID;
345    } else {
346        IPlay *thiz = (IPlay *) self;
347        interface_lock_exclusive(thiz);
348        if (thiz->mPositionUpdatePeriod != mSec) {
349            thiz->mPositionUpdatePeriod = mSec;
350#ifdef ANDROID
351            if (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(thiz)) {
352                // result = android_audioPlayer_useEventMask(thiz, thiz->mEventFlags);
353            }
354#endif
355#ifdef USE_OUTPUTMIXEXT
356            if (SL_OBJECTID_AUDIOPLAYER == InterfaceToObjectID(thiz)) {
357                CAudioPlayer *audioPlayer = (CAudioPlayer *) thiz->mThis;
358                SLuint32 frameUpdatePeriod = ((long long) mSec *
359                    (long long) audioPlayer->mSampleRateMilliHz) / 1000000LL;
360                if (0 == frameUpdatePeriod)
361                    frameUpdatePeriod = ~0;
362                thiz->mFrameUpdatePeriod = frameUpdatePeriod;
363                // setting a new update period postpones the next callback
364                thiz->mFramesSincePositionUpdate = 0;
365            }
366#endif
367            interface_unlock_exclusive_attributes(thiz, ATTR_TRANSPORT);
368        } else
369            interface_unlock_exclusive(thiz);
370        result = SL_RESULT_SUCCESS;
371    }
372
373    SL_LEAVE_INTERFACE
374}
375
376
377static SLresult IPlay_GetPositionUpdatePeriod(SLPlayItf self, SLmillisecond *pMsec)
378{
379    SL_ENTER_INTERFACE
380
381    if (NULL == pMsec) {
382        result = SL_RESULT_PARAMETER_INVALID;
383    } else {
384        IPlay *thiz = (IPlay *) self;
385        interface_lock_peek(thiz);
386        SLmillisecond positionUpdatePeriod = thiz->mPositionUpdatePeriod;
387        interface_unlock_peek(thiz);
388        *pMsec = positionUpdatePeriod;
389        result = SL_RESULT_SUCCESS;
390    }
391
392    SL_LEAVE_INTERFACE
393}
394
395
396static const struct SLPlayItf_ IPlay_Itf = {
397    IPlay_SetPlayState,
398    IPlay_GetPlayState,
399    IPlay_GetDuration,
400    IPlay_GetPosition,
401    IPlay_RegisterCallback,
402    IPlay_SetCallbackEventsMask,
403    IPlay_GetCallbackEventsMask,
404    IPlay_SetMarkerPosition,
405    IPlay_ClearMarkerPosition,
406    IPlay_GetMarkerPosition,
407    IPlay_SetPositionUpdatePeriod,
408    IPlay_GetPositionUpdatePeriod
409};
410
411void IPlay_init(void *self)
412{
413    IPlay *thiz = (IPlay *) self;
414    thiz->mItf = &IPlay_Itf;
415    thiz->mState = SL_PLAYSTATE_STOPPED;
416    thiz->mDuration = SL_TIME_UNKNOWN;  // will be set by containing player object
417    thiz->mPosition = (SLmillisecond) 0;
418    thiz->mCallback = NULL;
419    thiz->mContext = NULL;
420    thiz->mEventFlags = 0;
421    thiz->mMarkerPosition = 0;
422    thiz->mPositionUpdatePeriod = 1000;
423#ifdef USE_OUTPUTMIXEXT
424    thiz->mFrameUpdatePeriod = 0;   // because we don't know the sample rate yet
425    thiz->mLastSeekPosition = 0;
426    thiz->mFramesSinceLastSeek = 0;
427    thiz->mFramesSincePositionUpdate = 0;
428#endif
429}
430