locks.c revision 70c49ae2867094072a4365423417ea452bf82231
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "sles_allinclusive.h"
18
19
20/** \brief Exclusively lock an object */
21
22#ifdef USE_DEBUG
23void object_lock_exclusive_(IObject *thiz, const char *file, int line)
24{
25    int ok;
26    ok = pthread_mutex_trylock(&thiz->mMutex);
27    if (0 != ok) {
28        // pthread_mutex_timedlock_np is not available, but wait up to 100 ms
29        static const useconds_t backoffs[] = {1, 10000, 20000, 30000, 40000};
30        unsigned i = 0;
31        for (;;) {
32            usleep(backoffs[i]);
33            ok = pthread_mutex_trylock(&thiz->mMutex);
34            if (0 == ok)
35                break;
36            if (++i >= (sizeof(backoffs) / sizeof(backoffs[0]))) {
37                SL_LOGW("%s:%d: object %p was locked by %p at %s:%d\n",
38                    file, line, thiz, *(void **)&thiz->mOwner, thiz->mFile, thiz->mLine);
39                // attempt one more time; maybe this time we will be successful
40                ok = pthread_mutex_lock(&thiz->mMutex);
41                assert(0 == ok);
42                break;
43            }
44        }
45    }
46    pthread_t zero;
47    memset(&zero, 0, sizeof(pthread_t));
48    if (0 != memcmp(&zero, &thiz->mOwner, sizeof(pthread_t))) {
49        if (pthread_equal(pthread_self(), thiz->mOwner)) {
50            SL_LOGE("%s:%d: object %p was recursively locked by %p at %s:%d\n",
51                file, line, thiz, *(void **)&thiz->mOwner, thiz->mFile, thiz->mLine);
52        } else {
53            SL_LOGE("%s:%d: object %p was left unlocked in unexpected state by %p at %s:%d\n",
54                file, line, thiz, *(void **)&thiz->mOwner, thiz->mFile, thiz->mLine);
55        }
56        assert(false);
57    }
58    thiz->mOwner = pthread_self();
59    thiz->mFile = file;
60    thiz->mLine = line;
61}
62#else
63void object_lock_exclusive(IObject *thiz)
64{
65    int ok;
66    ok = pthread_mutex_lock(&thiz->mMutex);
67    assert(0 == ok);
68}
69#endif
70
71
72/** \brief Exclusively unlock an object and do not report any updates */
73
74#ifdef USE_DEBUG
75void object_unlock_exclusive_(IObject *thiz, const char *file, int line)
76{
77    assert(pthread_equal(pthread_self(), thiz->mOwner));
78    assert(NULL != thiz->mFile);
79    assert(0 != thiz->mLine);
80    memset(&thiz->mOwner, 0, sizeof(pthread_t));
81    thiz->mFile = file;
82    thiz->mLine = line;
83    int ok;
84    ok = pthread_mutex_unlock(&thiz->mMutex);
85    assert(0 == ok);
86}
87#else
88void object_unlock_exclusive(IObject *thiz)
89{
90    int ok;
91    ok = pthread_mutex_unlock(&thiz->mMutex);
92    assert(0 == ok);
93}
94#endif
95
96
97/** \brief Exclusively unlock an object and report updates to the specified bit-mask of
98 *  attributes
99 */
100
101#ifdef USE_DEBUG
102void object_unlock_exclusive_attributes_(IObject *thiz, unsigned attributes,
103    const char *file, int line)
104#else
105void object_unlock_exclusive_attributes(IObject *thiz, unsigned attributes)
106#endif
107{
108
109#ifdef USE_DEBUG
110    assert(pthread_equal(pthread_self(), thiz->mOwner));
111    assert(NULL != thiz->mFile);
112    assert(0 != thiz->mLine);
113#endif
114
115    int ok;
116    SLuint32 objectID = IObjectToObjectID(thiz);
117    CAudioPlayer *ap;
118
119    // FIXME The endless if statements are getting ugly, should use bit search
120
121    // Android likes to see certain updates synchronously
122
123    if (attributes & ATTR_GAIN) {
124        switch (objectID) {
125        case SL_OBJECTID_AUDIOPLAYER:
126            attributes &= ~ATTR_GAIN;   // no need to process asynchronously also
127            ap = (CAudioPlayer *) thiz;
128#ifdef ANDROID
129            android_audioPlayer_volumeUpdate(ap);
130#else
131            audioPlayerGainUpdate(ap);
132#endif
133            break;
134        case SL_OBJECTID_OUTPUTMIX:
135            // FIXME update gains on all players attached to this outputmix
136            SL_LOGD("[ FIXME: gain update on an SL_OBJECTID_OUTPUTMIX to be implemented ]");
137            break;
138        case SL_OBJECTID_MIDIPLAYER:
139            // MIDI
140            SL_LOGD("[ FIXME: gain update on an SL_OBJECTID_MIDIPLAYER to be implemented ]");
141            break;
142        default:
143            break;
144        }
145    }
146
147    if (attributes & ATTR_POSITION) {
148        switch (objectID) {
149        case SL_OBJECTID_AUDIOPLAYER:
150#ifdef ANDROID
151            ap = (CAudioPlayer *) thiz;
152            attributes &= ~ATTR_POSITION;   // no need to process asynchronously also
153            android_audioPlayer_seek(ap, ap->mSeek.mPos);
154#else
155            //audioPlayerTransportUpdate(ap);
156#endif
157            break;
158        case SL_OBJECTID_MIDIPLAYER:
159            // MIDI
160            SL_LOGD("[ FIXME: position update on an SL_OBJECTID_MIDIPLAYER to be implemented ]");
161            break;
162        default:
163            break;
164        }
165    }
166
167    if (attributes & ATTR_TRANSPORT) {
168        switch (objectID) {
169        case SL_OBJECTID_AUDIOPLAYER:
170#ifdef ANDROID
171            attributes &= ~ATTR_TRANSPORT;   // no need to process asynchronously also
172            ap = (CAudioPlayer *) thiz;
173            // FIXME should only call when state changes
174            android_audioPlayer_setPlayState(ap, false /*lockAP*/);
175            // FIXME ditto, but for either eventflags or marker position
176            android_audioPlayer_useEventMask(ap);
177#else
178            //audioPlayerTransportUpdate(ap);
179#endif
180            break;
181        case SL_OBJECTID_AUDIORECORDER:
182#ifdef ANDROID
183            {
184            attributes &= ~ATTR_TRANSPORT;   // no need to process asynchronously also
185            CAudioRecorder* ar = (CAudioRecorder *) thiz;
186            android_audioRecorder_useEventMask(ar);
187            }
188#endif
189            break;
190        case XA_OBJECTID_MEDIAPLAYER:
191#ifdef ANDROID
192            {
193            attributes &= ~ATTR_TRANSPORT;   // no need to process asynchronously also
194            CMediaPlayer *mp = (CMediaPlayer *) thiz;
195            android::GenericPlayer* avp = mp->mAVPlayer.get();
196            if (avp != NULL) {
197                android_Player_setPlayState(avp, mp->mPlay.mState, &(mp->mAndroidObjState));
198            }
199            }
200#endif
201            break;
202        default:
203            break;
204        }
205    }
206
207    if (attributes & ATTR_BQ_ENQUEUE) {
208        // ( buffer queue count is non-empty and play state == PLAYING ) became true
209        if (SL_OBJECTID_AUDIOPLAYER == objectID) {
210            attributes &= ~ATTR_BQ_ENQUEUE;
211            ap = (CAudioPlayer *) thiz;
212            if (SL_PLAYSTATE_PLAYING == ap->mPlay.mState) {
213#ifdef ANDROID
214                android_audioPlayer_bufferQueue_onRefilled_l(ap);
215#endif
216            }
217        }
218#ifndef ANDROID
219    }
220#else
221    } else if (attributes & ATTR_ABQ_ENQUEUE) {
222        // (Android buffer queue count is non-empty and play state == PLAYING ) became true
223        if (SL_OBJECTID_AUDIOPLAYER == objectID) {
224            attributes &= ~ATTR_ABQ_ENQUEUE;
225            ap = (CAudioPlayer *) thiz;
226            if (SL_PLAYSTATE_PLAYING == ap->mPlay.mState) {
227                android_audioPlayer_androidBufferQueue_onRefilled_l(ap);
228            }
229        } else if (XA_OBJECTID_MEDIAPLAYER == objectID) {
230            attributes &= ~ATTR_ABQ_ENQUEUE;
231            CMediaPlayer* mp = (CMediaPlayer *)thiz;
232            if (SL_PLAYSTATE_PLAYING == mp->mPlay.mState) {
233                android_Player_androidBufferQueue_onRefilled_l(mp);
234            }
235        }
236    }
237#endif
238
239    if (attributes) {
240        unsigned oldAttributesMask = thiz->mAttributesMask;
241        thiz->mAttributesMask = oldAttributesMask | attributes;
242        if (oldAttributesMask)
243            attributes = ATTR_NONE;
244    }
245#ifdef USE_DEBUG
246    memset(&thiz->mOwner, 0, sizeof(pthread_t));
247    thiz->mFile = file;
248    thiz->mLine = line;
249#endif
250    ok = pthread_mutex_unlock(&thiz->mMutex);
251    assert(0 == ok);
252    // first update to this interface since previous sync
253    if (attributes) {
254        unsigned id = thiz->mInstanceID;
255        if (0 != id) {
256            --id;
257            assert(MAX_INSTANCE > id);
258            IEngine *thisEngine = &thiz->mEngine->mEngine;
259            interface_lock_exclusive(thisEngine);
260            thisEngine->mChangedMask |= 1 << id;
261            interface_unlock_exclusive(thisEngine);
262        }
263    }
264}
265
266
267/** \brief Wait on the condition variable associated with the object; see pthread_cond_wait */
268
269#ifdef USE_DEBUG
270void object_cond_wait_(IObject *thiz, const char *file, int line)
271{
272    // note that this will unlock the mutex, so we have to clear the owner
273    assert(pthread_equal(pthread_self(), thiz->mOwner));
274    assert(NULL != thiz->mFile);
275    assert(0 != thiz->mLine);
276    memset(&thiz->mOwner, 0, sizeof(pthread_t));
277    thiz->mFile = file;
278    thiz->mLine = line;
279    // alas we don't know the new owner's identity
280    int ok;
281    ok = pthread_cond_wait(&thiz->mCond, &thiz->mMutex);
282    assert(0 == ok);
283    // restore my ownership
284    thiz->mOwner = pthread_self();
285    thiz->mFile = file;
286    thiz->mLine = line;
287}
288#else
289void object_cond_wait(IObject *thiz)
290{
291    int ok;
292    ok = pthread_cond_wait(&thiz->mCond, &thiz->mMutex);
293    assert(0 == ok);
294}
295#endif
296
297
298/** \brief Signal the condition variable associated with the object; see pthread_cond_signal */
299
300void object_cond_signal(IObject *thiz)
301{
302    int ok;
303    ok = pthread_cond_signal(&thiz->mCond);
304    assert(0 == ok);
305}
306
307
308/** \brief Broadcast the condition variable associated with the object;
309 *  see pthread_cond_broadcast
310 */
311
312void object_cond_broadcast(IObject *thiz)
313{
314    int ok;
315    ok = pthread_cond_broadcast(&thiz->mCond);
316    assert(0 == ok);
317}
318