xref: /aosp_15_r20/frameworks/wilhelm/src/itf/IPlay.cpp (revision bebae9c0e76121f8312ccb50385c080b3a0b023c)
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