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