locks.c revision fcc996296bdbf6c3949ad4312991fdde4ae2e157
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        case XA_OBJECTID_MEDIAPLAYER: {
143#ifdef ANDROID
144            attributes &= ~ATTR_GAIN;   // no need to process asynchronously also
145            CMediaPlayer *mp = (CMediaPlayer *) thiz;
146            android::GenericPlayer* avp = mp->mAVPlayer.get();
147            if (avp != NULL) {
148                android_Player_volumeUpdate(avp, &mp->mVolume);
149            }
150#endif
151            break;
152        }
153        default:
154            break;
155        }
156    }
157
158    if (attributes & ATTR_POSITION) {
159        switch (objectID) {
160        case SL_OBJECTID_AUDIOPLAYER:
161#ifdef ANDROID
162            ap = (CAudioPlayer *) thiz;
163            attributes &= ~ATTR_POSITION;   // no need to process asynchronously also
164            android_audioPlayer_seek(ap, ap->mSeek.mPos);
165#else
166            //audioPlayerTransportUpdate(ap);
167#endif
168            break;
169        case SL_OBJECTID_MIDIPLAYER:
170            // MIDI
171            SL_LOGD("[ FIXME: position update on an SL_OBJECTID_MIDIPLAYER to be implemented ]");
172            break;
173        default:
174            break;
175        }
176    }
177
178    if (attributes & ATTR_TRANSPORT) {
179        switch (objectID) {
180        case SL_OBJECTID_AUDIOPLAYER:
181#ifdef ANDROID
182            attributes &= ~ATTR_TRANSPORT;   // no need to process asynchronously also
183            ap = (CAudioPlayer *) thiz;
184            // FIXME should only call when state changes
185            android_audioPlayer_setPlayState(ap, false /*lockAP*/);
186            // FIXME ditto, but for either eventflags or marker position
187            android_audioPlayer_useEventMask(ap);
188#else
189            //audioPlayerTransportUpdate(ap);
190#endif
191            break;
192        case SL_OBJECTID_AUDIORECORDER:
193#ifdef ANDROID
194            {
195            attributes &= ~ATTR_TRANSPORT;   // no need to process asynchronously also
196            CAudioRecorder* ar = (CAudioRecorder *) thiz;
197            android_audioRecorder_useEventMask(ar);
198            }
199#endif
200            break;
201        case XA_OBJECTID_MEDIAPLAYER:
202#ifdef ANDROID
203            {
204            attributes &= ~ATTR_TRANSPORT;   // no need to process asynchronously also
205            CMediaPlayer *mp = (CMediaPlayer *) thiz;
206            android::GenericPlayer* avp = mp->mAVPlayer.get();
207            if (avp != NULL) {
208                android_Player_setPlayState(avp, mp->mPlay.mState, &(mp->mAndroidObjState));
209            }
210            }
211#endif
212            break;
213        default:
214            break;
215        }
216    }
217
218    if (attributes & ATTR_BQ_ENQUEUE) {
219        // ( buffer queue count is non-empty and play state == PLAYING ) became true
220        if (SL_OBJECTID_AUDIOPLAYER == objectID) {
221            attributes &= ~ATTR_BQ_ENQUEUE;
222            ap = (CAudioPlayer *) thiz;
223            if (SL_PLAYSTATE_PLAYING == ap->mPlay.mState) {
224#ifdef ANDROID
225                android_audioPlayer_bufferQueue_onRefilled_l(ap);
226#endif
227            }
228        }
229#ifndef ANDROID
230    }
231#else
232    } else if (attributes & ATTR_ABQ_ENQUEUE) {
233        // (Android buffer queue count is non-empty and play state == PLAYING ) became true
234        if (SL_OBJECTID_AUDIOPLAYER == objectID) {
235            attributes &= ~ATTR_ABQ_ENQUEUE;
236            ap = (CAudioPlayer *) thiz;
237            if (SL_PLAYSTATE_PLAYING == ap->mPlay.mState) {
238                android_audioPlayer_androidBufferQueue_onRefilled_l(ap);
239            }
240        } else if (XA_OBJECTID_MEDIAPLAYER == objectID) {
241            attributes &= ~ATTR_ABQ_ENQUEUE;
242            CMediaPlayer* mp = (CMediaPlayer *)thiz;
243            if (SL_PLAYSTATE_PLAYING == mp->mPlay.mState) {
244                android_Player_androidBufferQueue_onRefilled_l(mp);
245            }
246        }
247    }
248#endif
249
250    if (attributes) {
251        unsigned oldAttributesMask = thiz->mAttributesMask;
252        thiz->mAttributesMask = oldAttributesMask | attributes;
253        if (oldAttributesMask)
254            attributes = ATTR_NONE;
255    }
256#ifdef USE_DEBUG
257    memset(&thiz->mOwner, 0, sizeof(pthread_t));
258    thiz->mFile = file;
259    thiz->mLine = line;
260#endif
261    ok = pthread_mutex_unlock(&thiz->mMutex);
262    assert(0 == ok);
263    // first update to this interface since previous sync
264    if (attributes) {
265        unsigned id = thiz->mInstanceID;
266        if (0 != id) {
267            --id;
268            assert(MAX_INSTANCE > id);
269            IEngine *thisEngine = &thiz->mEngine->mEngine;
270            interface_lock_exclusive(thisEngine);
271            thisEngine->mChangedMask |= 1 << id;
272            interface_unlock_exclusive(thisEngine);
273        }
274    }
275}
276
277
278/** \brief Wait on the condition variable associated with the object; see pthread_cond_wait */
279
280#ifdef USE_DEBUG
281void object_cond_wait_(IObject *thiz, const char *file, int line)
282{
283    // note that this will unlock the mutex, so we have to clear the owner
284    assert(pthread_equal(pthread_self(), thiz->mOwner));
285    assert(NULL != thiz->mFile);
286    assert(0 != thiz->mLine);
287    memset(&thiz->mOwner, 0, sizeof(pthread_t));
288    thiz->mFile = file;
289    thiz->mLine = line;
290    // alas we don't know the new owner's identity
291    int ok;
292    ok = pthread_cond_wait(&thiz->mCond, &thiz->mMutex);
293    assert(0 == ok);
294    // restore my ownership
295    thiz->mOwner = pthread_self();
296    thiz->mFile = file;
297    thiz->mLine = line;
298}
299#else
300void object_cond_wait(IObject *thiz)
301{
302    int ok;
303    ok = pthread_cond_wait(&thiz->mCond, &thiz->mMutex);
304    assert(0 == ok);
305}
306#endif
307
308
309/** \brief Signal the condition variable associated with the object; see pthread_cond_signal */
310
311void object_cond_signal(IObject *thiz)
312{
313    int ok;
314    ok = pthread_cond_signal(&thiz->mCond);
315    assert(0 == ok);
316}
317
318
319/** \brief Broadcast the condition variable associated with the object;
320 *  see pthread_cond_broadcast
321 */
322
323void object_cond_broadcast(IObject *thiz)
324{
325    int ok;
326    ok = pthread_cond_broadcast(&thiz->mCond);
327    assert(0 == ok);
328}
329