1d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten/*
2d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten * Copyright (C) 2010 The Android Open Source Project
3d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten *
4d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten * Licensed under the Apache License, Version 2.0 (the "License");
5d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten * you may not use this file except in compliance with the License.
6d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten * You may obtain a copy of the License at
7d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten *
8d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten *      http://www.apache.org/licenses/LICENSE-2.0
9d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten *
10d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten * Unless required by applicable law or agreed to in writing, software
11d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten * distributed under the License is distributed on an "AS IS" BASIS,
12d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten * See the License for the specific language governing permissions and
14d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten * limitations under the License.
15d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten */
16d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten
17369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kasten/** \file CEngine.c Engine class */
18d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten
19d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten#include "sles_allinclusive.h"
20d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten
21d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten
221d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten/* This implementation supports at most one engine, identical for both OpenSL ES and OpenMAX AL */
238db0b106cdce5f5216b1535492de7930ad738aedGlenn Kasten
248db0b106cdce5f5216b1535492de7930ad738aedGlenn KastenCEngine *theOneTrueEngine = NULL;
258db0b106cdce5f5216b1535492de7930ad738aedGlenn Kastenpthread_mutex_t theOneTrueMutex = PTHREAD_MUTEX_INITIALIZER;
261d081e49a10543018e1ae33792bd3d30504719baGlenn Kastenunsigned theOneTrueRefCount = 0;
271d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten// incremented by slCreateEngine or xaCreateEngine, decremented by Object::Destroy on engine
288db0b106cdce5f5216b1535492de7930ad738aedGlenn Kasten
298db0b106cdce5f5216b1535492de7930ad738aedGlenn Kasten
308db0b106cdce5f5216b1535492de7930ad738aedGlenn Kasten/** \brief Called by dlopen when .so is loaded */
318db0b106cdce5f5216b1535492de7930ad738aedGlenn Kasten
328db0b106cdce5f5216b1535492de7930ad738aedGlenn Kasten__attribute__((constructor)) static void onDlOpen(void)
338db0b106cdce5f5216b1535492de7930ad738aedGlenn Kasten{
348db0b106cdce5f5216b1535492de7930ad738aedGlenn Kasten}
358db0b106cdce5f5216b1535492de7930ad738aedGlenn Kasten
368db0b106cdce5f5216b1535492de7930ad738aedGlenn Kasten
378db0b106cdce5f5216b1535492de7930ad738aedGlenn Kasten/** \brief Called by dlclose when .so is unloaded */
388db0b106cdce5f5216b1535492de7930ad738aedGlenn Kasten
398db0b106cdce5f5216b1535492de7930ad738aedGlenn Kasten__attribute__((destructor)) static void onDlClose(void)
408db0b106cdce5f5216b1535492de7930ad738aedGlenn Kasten{
415c8bd83295b2752bb7ac34f83dfb19dcdb1be5e5Glenn Kasten    // a memory barrier would be sufficient, but the mutex is easier
425c8bd83295b2752bb7ac34f83dfb19dcdb1be5e5Glenn Kasten    (void) pthread_mutex_lock(&theOneTrueMutex);
431d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten    if ((NULL != theOneTrueEngine) || (0 < theOneTrueRefCount)) {
448db0b106cdce5f5216b1535492de7930ad738aedGlenn Kasten        SL_LOGE("Object::Destroy omitted for engine %p", theOneTrueEngine);
458db0b106cdce5f5216b1535492de7930ad738aedGlenn Kasten    }
465c8bd83295b2752bb7ac34f83dfb19dcdb1be5e5Glenn Kasten    (void) pthread_mutex_unlock(&theOneTrueMutex);
478db0b106cdce5f5216b1535492de7930ad738aedGlenn Kasten}
488db0b106cdce5f5216b1535492de7930ad738aedGlenn Kasten
498db0b106cdce5f5216b1535492de7930ad738aedGlenn Kasten
50369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kasten/** \brief Hook called by Object::Realize when an engine is realized */
510b595cc18d82e41dfab0c686e9e63c30a86e8c80Glenn Kasten
52d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn KastenSLresult CEngine_Realize(void *self, SLboolean async)
53d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten{
54bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    CEngine *thiz = (CEngine *) self;
55b52bc98b576a9b56e82eca435849bd55e54b6bc1Glenn Kasten    SLresult result;
56b52bc98b576a9b56e82eca435849bd55e54b6bc1Glenn Kasten#ifndef ANDROID
57a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten    // create the sync thread
58bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    int err = pthread_create(&thiz->mSyncThread, (const pthread_attr_t *) NULL, sync_start, thiz);
59b52bc98b576a9b56e82eca435849bd55e54b6bc1Glenn Kasten    result = err_to_result(err);
60d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    if (SL_RESULT_SUCCESS != result)
61d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        return result;
62b52bc98b576a9b56e82eca435849bd55e54b6bc1Glenn Kasten#endif
63a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten    // initialize the thread pool for asynchronous operations
64bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    result = ThreadPool_init(&thiz->mThreadPool, 0, 0);
65d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    if (SL_RESULT_SUCCESS != result) {
66bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        thiz->mEngine.mShutdown = SL_BOOLEAN_TRUE;
67bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        (void) pthread_join(thiz->mSyncThread, (void **) NULL);
68d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        return result;
69d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    }
70d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten#ifdef USE_SDL
71bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    SDL_open(&thiz->mEngine);
72d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten#endif
73d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    return SL_RESULT_SUCCESS;
74d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten}
75d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten
760b595cc18d82e41dfab0c686e9e63c30a86e8c80Glenn Kasten
77928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten/** \brief Hook called by Object::Resume when an engine is resumed */
78928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten
79928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn KastenSLresult CEngine_Resume(void *self, SLboolean async)
80928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten{
81928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    return SL_RESULT_SUCCESS;
82928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten}
83928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten
84928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten
85369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kasten/** \brief Hook called by Object::Destroy when an engine is destroyed */
860b595cc18d82e41dfab0c686e9e63c30a86e8c80Glenn Kasten
87d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kastenvoid CEngine_Destroy(void *self)
88d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten{
89bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    CEngine *thiz = (CEngine *) self;
90d48ff338b8338c1e3e54e0f9dcd03567a0aa9de4Glenn Kasten
91d48ff338b8338c1e3e54e0f9dcd03567a0aa9de4Glenn Kasten    // Verify that there are no extant objects
92bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    unsigned instanceCount = thiz->mEngine.mInstanceCount;
93bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    unsigned instanceMask = thiz->mEngine.mInstanceMask;
94d48ff338b8338c1e3e54e0f9dcd03567a0aa9de4Glenn Kasten    if ((0 < instanceCount) || (0 != instanceMask)) {
95a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten        SL_LOGE("Object::Destroy(%p) for engine ignored; %u total active objects",
96bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            thiz, instanceCount);
97d48ff338b8338c1e3e54e0f9dcd03567a0aa9de4Glenn Kasten        while (0 != instanceMask) {
98d48ff338b8338c1e3e54e0f9dcd03567a0aa9de4Glenn Kasten            unsigned i = ctz(instanceMask);
99d48ff338b8338c1e3e54e0f9dcd03567a0aa9de4Glenn Kasten            assert(MAX_INSTANCE > i);
100a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            SL_LOGE("Object::Destroy(%p) for engine ignored; active object ID %u at %p",
101bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                thiz, i + 1, thiz->mEngine.mInstances[i]);
102d48ff338b8338c1e3e54e0f9dcd03567a0aa9de4Glenn Kasten            instanceMask &= ~(1 << i);
103d48ff338b8338c1e3e54e0f9dcd03567a0aa9de4Glenn Kasten        }
104d48ff338b8338c1e3e54e0f9dcd03567a0aa9de4Glenn Kasten    }
105d48ff338b8338c1e3e54e0f9dcd03567a0aa9de4Glenn Kasten
106fff44558a7fdbe741607b25fbd4344fe9ab94c17Glenn Kasten    // If engine was created but not realized, there will be no sync thread yet
107fff44558a7fdbe741607b25fbd4344fe9ab94c17Glenn Kasten    pthread_t zero;
108fff44558a7fdbe741607b25fbd4344fe9ab94c17Glenn Kasten    memset(&zero, 0, sizeof(pthread_t));
109bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    if (0 != memcmp(&zero, &thiz->mSyncThread, sizeof(pthread_t))) {
110fff44558a7fdbe741607b25fbd4344fe9ab94c17Glenn Kasten
111fff44558a7fdbe741607b25fbd4344fe9ab94c17Glenn Kasten        // Announce to the sync thread that engine is shutting down; it polls so should see it soon
112bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        thiz->mEngine.mShutdown = SL_BOOLEAN_TRUE;
113fff44558a7fdbe741607b25fbd4344fe9ab94c17Glenn Kasten        // Wait for the sync thread to acknowledge the shutdown
114bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        while (!thiz->mEngine.mShutdownAck) {
115bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            object_cond_wait(&thiz->mObject);
116fff44558a7fdbe741607b25fbd4344fe9ab94c17Glenn Kasten        }
117fff44558a7fdbe741607b25fbd4344fe9ab94c17Glenn Kasten        // The sync thread should have exited by now, so collect it by joining
118bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        (void) pthread_join(thiz->mSyncThread, (void **) NULL);
119fff44558a7fdbe741607b25fbd4344fe9ab94c17Glenn Kasten
120d48ff338b8338c1e3e54e0f9dcd03567a0aa9de4Glenn Kasten    }
121d48ff338b8338c1e3e54e0f9dcd03567a0aa9de4Glenn Kasten
122d48ff338b8338c1e3e54e0f9dcd03567a0aa9de4Glenn Kasten    // Shutdown the thread pool used for asynchronous operations (there should not be any)
123bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    ThreadPool_deinit(&thiz->mThreadPool);
124b0ab2dee391dd2cb257faeaba252ee6ecccc5f03Glenn Kasten
125faf90312d2156acbf27c62e114fd180708aa7654Glenn Kasten#if defined(ANDROID)
126b0ab2dee391dd2cb257faeaba252ee6ecccc5f03Glenn Kasten    // free equalizer preset names
127bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    if (NULL != thiz->mEqPresetNames) {
128bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        for (unsigned i = 0; i < thiz->mEqNumPresets; ++i) {
129bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            if (NULL != thiz->mEqPresetNames[i]) {
130bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                delete[] thiz->mEqPresetNames[i];
131bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                thiz->mEqPresetNames[i] = NULL;
132b0ab2dee391dd2cb257faeaba252ee6ecccc5f03Glenn Kasten            }
133b0ab2dee391dd2cb257faeaba252ee6ecccc5f03Glenn Kasten        }
134bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        delete[] thiz->mEqPresetNames;
135bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        thiz->mEqPresetNames = NULL;
136b0ab2dee391dd2cb257faeaba252ee6ecccc5f03Glenn Kasten    }
137bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mEqNumPresets = 0;
138b0ab2dee391dd2cb257faeaba252ee6ecccc5f03Glenn Kasten#endif
139d48ff338b8338c1e3e54e0f9dcd03567a0aa9de4Glenn Kasten
140d48ff338b8338c1e3e54e0f9dcd03567a0aa9de4Glenn Kasten#ifdef USE_SDL
141d48ff338b8338c1e3e54e0f9dcd03567a0aa9de4Glenn Kasten    SDL_close();
142d48ff338b8338c1e3e54e0f9dcd03567a0aa9de4Glenn Kasten#endif
1434be7fe875758b42939719a1082ae9e6dbf37a1d7Jean-Michel Trivi
144d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten}
145928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten
146928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten
147928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten/** \brief Hook called by Object::Destroy before an engine is about to be destroyed */
148928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten
1491d081e49a10543018e1ae33792bd3d30504719baGlenn Kastenpredestroy_t CEngine_PreDestroy(void *self)
150928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten{
1511d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten    predestroy_t ret;
1521d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten    (void) pthread_mutex_lock(&theOneTrueMutex);
1531d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten    assert(self == theOneTrueEngine);
1541d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten    switch (theOneTrueRefCount) {
1551d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten    case 0:
1561d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten        assert(false);
1571d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten        ret = predestroy_error;
1581d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten        break;
1591d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten    case 1:
1601d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten        ret = predestroy_ok;
1611d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten        break;
1621d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten    default:
1631d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten        --theOneTrueRefCount;
1641d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten        ret = predestroy_again;
1651d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten        break;
1661d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten    }
1671d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten    (void) pthread_mutex_unlock(&theOneTrueMutex);
1681d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten    return ret;
169928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten}
1708db0b106cdce5f5216b1535492de7930ad738aedGlenn Kasten
1718db0b106cdce5f5216b1535492de7930ad738aedGlenn Kasten
1728db0b106cdce5f5216b1535492de7930ad738aedGlenn Kasten/** \brief Called by IObject::Destroy after engine is destroyed. The parameter refers to the
1738db0b106cdce5f5216b1535492de7930ad738aedGlenn Kasten *  previous engine, which is now undefined memory.
1748db0b106cdce5f5216b1535492de7930ad738aedGlenn Kasten */
1758db0b106cdce5f5216b1535492de7930ad738aedGlenn Kasten
1768db0b106cdce5f5216b1535492de7930ad738aedGlenn Kastenvoid CEngine_Destroyed(CEngine *self)
1778db0b106cdce5f5216b1535492de7930ad738aedGlenn Kasten{
1788db0b106cdce5f5216b1535492de7930ad738aedGlenn Kasten    int ok;
1798db0b106cdce5f5216b1535492de7930ad738aedGlenn Kasten    ok = pthread_mutex_lock(&theOneTrueMutex);
1808db0b106cdce5f5216b1535492de7930ad738aedGlenn Kasten    assert(0 == ok);
1818db0b106cdce5f5216b1535492de7930ad738aedGlenn Kasten    assert(self == theOneTrueEngine);
1828db0b106cdce5f5216b1535492de7930ad738aedGlenn Kasten    theOneTrueEngine = NULL;
1831d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten    assert(1 == theOneTrueRefCount);
1841d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten    theOneTrueRefCount = 0;
1858db0b106cdce5f5216b1535492de7930ad738aedGlenn Kasten    ok = pthread_mutex_unlock(&theOneTrueMutex);
1868db0b106cdce5f5216b1535492de7930ad738aedGlenn Kasten    assert(0 == ok);
1878db0b106cdce5f5216b1535492de7930ad738aedGlenn Kasten}
188