1437f9ab9914ea61112aa496a047162a0d22194cdGlenn Kasten/*
2437f9ab9914ea61112aa496a047162a0d22194cdGlenn Kasten * Copyright (C) 2010 The Android Open Source Project
3437f9ab9914ea61112aa496a047162a0d22194cdGlenn Kasten *
4437f9ab9914ea61112aa496a047162a0d22194cdGlenn Kasten * Licensed under the Apache License, Version 2.0 (the "License");
5437f9ab9914ea61112aa496a047162a0d22194cdGlenn Kasten * you may not use this file except in compliance with the License.
6437f9ab9914ea61112aa496a047162a0d22194cdGlenn Kasten * You may obtain a copy of the License at
7437f9ab9914ea61112aa496a047162a0d22194cdGlenn Kasten *
8437f9ab9914ea61112aa496a047162a0d22194cdGlenn Kasten *      http://www.apache.org/licenses/LICENSE-2.0
9437f9ab9914ea61112aa496a047162a0d22194cdGlenn Kasten *
10437f9ab9914ea61112aa496a047162a0d22194cdGlenn Kasten * Unless required by applicable law or agreed to in writing, software
11437f9ab9914ea61112aa496a047162a0d22194cdGlenn Kasten * distributed under the License is distributed on an "AS IS" BASIS,
12437f9ab9914ea61112aa496a047162a0d22194cdGlenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13437f9ab9914ea61112aa496a047162a0d22194cdGlenn Kasten * See the License for the specific language governing permissions and
14437f9ab9914ea61112aa496a047162a0d22194cdGlenn Kasten * limitations under the License.
15437f9ab9914ea61112aa496a047162a0d22194cdGlenn Kasten */
16437f9ab9914ea61112aa496a047162a0d22194cdGlenn Kasten
1710ee2bc6119445f4339ecef998c40c9cc95057cdGlenn Kasten/** \file CEngine.c Engine class */
18437f9ab9914ea61112aa496a047162a0d22194cdGlenn Kasten
19437f9ab9914ea61112aa496a047162a0d22194cdGlenn Kasten#include "sles_allinclusive.h"
20437f9ab9914ea61112aa496a047162a0d22194cdGlenn Kasten
21437f9ab9914ea61112aa496a047162a0d22194cdGlenn Kasten
22b11def0293629d4d44ddbcd8a27c63504fd80ce1Glenn Kasten/* This implementation supports at most one engine, identical for both OpenSL ES and OpenMAX AL */
23a930d729ff2249eaa0b45a5e61c70bebad45f698Glenn Kasten
24a930d729ff2249eaa0b45a5e61c70bebad45f698Glenn KastenCEngine *theOneTrueEngine = NULL;
25a930d729ff2249eaa0b45a5e61c70bebad45f698Glenn Kastenpthread_mutex_t theOneTrueMutex = PTHREAD_MUTEX_INITIALIZER;
26b11def0293629d4d44ddbcd8a27c63504fd80ce1Glenn Kastenunsigned theOneTrueRefCount = 0;
27b11def0293629d4d44ddbcd8a27c63504fd80ce1Glenn Kasten// incremented by slCreateEngine or xaCreateEngine, decremented by Object::Destroy on engine
28a930d729ff2249eaa0b45a5e61c70bebad45f698Glenn Kasten
29a930d729ff2249eaa0b45a5e61c70bebad45f698Glenn Kasten
30a930d729ff2249eaa0b45a5e61c70bebad45f698Glenn Kasten/** \brief Called by dlopen when .so is loaded */
31a930d729ff2249eaa0b45a5e61c70bebad45f698Glenn Kasten
32a930d729ff2249eaa0b45a5e61c70bebad45f698Glenn Kasten__attribute__((constructor)) static void onDlOpen(void)
33a930d729ff2249eaa0b45a5e61c70bebad45f698Glenn Kasten{
34a930d729ff2249eaa0b45a5e61c70bebad45f698Glenn Kasten}
35a930d729ff2249eaa0b45a5e61c70bebad45f698Glenn Kasten
36a930d729ff2249eaa0b45a5e61c70bebad45f698Glenn Kasten
37a930d729ff2249eaa0b45a5e61c70bebad45f698Glenn Kasten/** \brief Called by dlclose when .so is unloaded */
38a930d729ff2249eaa0b45a5e61c70bebad45f698Glenn Kasten
39a930d729ff2249eaa0b45a5e61c70bebad45f698Glenn Kasten__attribute__((destructor)) static void onDlClose(void)
40a930d729ff2249eaa0b45a5e61c70bebad45f698Glenn Kasten{
4199fe0d68ddc198a532cb1fa71bea2c809fa94c59Glenn Kasten    // a memory barrier would be sufficient, but the mutex is easier
4299fe0d68ddc198a532cb1fa71bea2c809fa94c59Glenn Kasten    (void) pthread_mutex_lock(&theOneTrueMutex);
43b11def0293629d4d44ddbcd8a27c63504fd80ce1Glenn Kasten    if ((NULL != theOneTrueEngine) || (0 < theOneTrueRefCount)) {
44a930d729ff2249eaa0b45a5e61c70bebad45f698Glenn Kasten        SL_LOGE("Object::Destroy omitted for engine %p", theOneTrueEngine);
45a930d729ff2249eaa0b45a5e61c70bebad45f698Glenn Kasten    }
4699fe0d68ddc198a532cb1fa71bea2c809fa94c59Glenn Kasten    (void) pthread_mutex_unlock(&theOneTrueMutex);
47a930d729ff2249eaa0b45a5e61c70bebad45f698Glenn Kasten}
48a930d729ff2249eaa0b45a5e61c70bebad45f698Glenn Kasten
49a930d729ff2249eaa0b45a5e61c70bebad45f698Glenn Kasten
5010ee2bc6119445f4339ecef998c40c9cc95057cdGlenn Kasten/** \brief Hook called by Object::Realize when an engine is realized */
51158dbd1a71a890d29490198c8e5019081ac94ac3Glenn Kasten
52437f9ab9914ea61112aa496a047162a0d22194cdGlenn KastenSLresult CEngine_Realize(void *self, SLboolean async)
53437f9ab9914ea61112aa496a047162a0d22194cdGlenn Kasten{
5450bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    CEngine *thiz = (CEngine *) self;
55227b8b5fe36d5385bbb23d63198bc8e72bfda5d3Glenn Kasten    SLresult result;
56227b8b5fe36d5385bbb23d63198bc8e72bfda5d3Glenn Kasten#ifndef ANDROID
5751cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten    // create the sync thread
5850bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    int err = pthread_create(&thiz->mSyncThread, (const pthread_attr_t *) NULL, sync_start, thiz);
59227b8b5fe36d5385bbb23d63198bc8e72bfda5d3Glenn Kasten    result = err_to_result(err);
60437f9ab9914ea61112aa496a047162a0d22194cdGlenn Kasten    if (SL_RESULT_SUCCESS != result)
61437f9ab9914ea61112aa496a047162a0d22194cdGlenn Kasten        return result;
62227b8b5fe36d5385bbb23d63198bc8e72bfda5d3Glenn Kasten#endif
6351cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten    // initialize the thread pool for asynchronous operations
6450bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    result = ThreadPool_init(&thiz->mThreadPool, 0, 0);
65437f9ab9914ea61112aa496a047162a0d22194cdGlenn Kasten    if (SL_RESULT_SUCCESS != result) {
6650bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten        thiz->mEngine.mShutdown = SL_BOOLEAN_TRUE;
6750bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten        (void) pthread_join(thiz->mSyncThread, (void **) NULL);
68437f9ab9914ea61112aa496a047162a0d22194cdGlenn Kasten        return result;
69437f9ab9914ea61112aa496a047162a0d22194cdGlenn Kasten    }
70437f9ab9914ea61112aa496a047162a0d22194cdGlenn Kasten#ifdef USE_SDL
7150bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    SDL_open(&thiz->mEngine);
72437f9ab9914ea61112aa496a047162a0d22194cdGlenn Kasten#endif
73437f9ab9914ea61112aa496a047162a0d22194cdGlenn Kasten    return SL_RESULT_SUCCESS;
74437f9ab9914ea61112aa496a047162a0d22194cdGlenn Kasten}
75437f9ab9914ea61112aa496a047162a0d22194cdGlenn Kasten
76158dbd1a71a890d29490198c8e5019081ac94ac3Glenn Kasten
774f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten/** \brief Hook called by Object::Resume when an engine is resumed */
784f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten
794f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn KastenSLresult CEngine_Resume(void *self, SLboolean async)
804f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten{
814f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten    return SL_RESULT_SUCCESS;
824f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten}
834f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten
844f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten
8510ee2bc6119445f4339ecef998c40c9cc95057cdGlenn Kasten/** \brief Hook called by Object::Destroy when an engine is destroyed */
86158dbd1a71a890d29490198c8e5019081ac94ac3Glenn Kasten
87437f9ab9914ea61112aa496a047162a0d22194cdGlenn Kastenvoid CEngine_Destroy(void *self)
88437f9ab9914ea61112aa496a047162a0d22194cdGlenn Kasten{
8950bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    CEngine *thiz = (CEngine *) self;
90b0a0555e2fcad41d3ee0c45f0f75ed556dbee282Glenn Kasten
91b0a0555e2fcad41d3ee0c45f0f75ed556dbee282Glenn Kasten    // Verify that there are no extant objects
9250bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    unsigned instanceCount = thiz->mEngine.mInstanceCount;
9350bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    unsigned instanceMask = thiz->mEngine.mInstanceMask;
94b0a0555e2fcad41d3ee0c45f0f75ed556dbee282Glenn Kasten    if ((0 < instanceCount) || (0 != instanceMask)) {
9551cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten        SL_LOGE("Object::Destroy(%p) for engine ignored; %u total active objects",
9650bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten            thiz, instanceCount);
97b0a0555e2fcad41d3ee0c45f0f75ed556dbee282Glenn Kasten        while (0 != instanceMask) {
98b0a0555e2fcad41d3ee0c45f0f75ed556dbee282Glenn Kasten            unsigned i = ctz(instanceMask);
99b0a0555e2fcad41d3ee0c45f0f75ed556dbee282Glenn Kasten            assert(MAX_INSTANCE > i);
10051cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten            SL_LOGE("Object::Destroy(%p) for engine ignored; active object ID %u at %p",
10150bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten                thiz, i + 1, thiz->mEngine.mInstances[i]);
102b0a0555e2fcad41d3ee0c45f0f75ed556dbee282Glenn Kasten            instanceMask &= ~(1 << i);
103b0a0555e2fcad41d3ee0c45f0f75ed556dbee282Glenn Kasten        }
104b0a0555e2fcad41d3ee0c45f0f75ed556dbee282Glenn Kasten    }
105b0a0555e2fcad41d3ee0c45f0f75ed556dbee282Glenn Kasten
106cc484cd4b7ede364e95209eb0468df3bc51f50e5Glenn Kasten    // If engine was created but not realized, there will be no sync thread yet
107cc484cd4b7ede364e95209eb0468df3bc51f50e5Glenn Kasten    pthread_t zero;
108cc484cd4b7ede364e95209eb0468df3bc51f50e5Glenn Kasten    memset(&zero, 0, sizeof(pthread_t));
10950bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    if (0 != memcmp(&zero, &thiz->mSyncThread, sizeof(pthread_t))) {
110cc484cd4b7ede364e95209eb0468df3bc51f50e5Glenn Kasten
111cc484cd4b7ede364e95209eb0468df3bc51f50e5Glenn Kasten        // Announce to the sync thread that engine is shutting down; it polls so should see it soon
11250bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten        thiz->mEngine.mShutdown = SL_BOOLEAN_TRUE;
113cc484cd4b7ede364e95209eb0468df3bc51f50e5Glenn Kasten        // Wait for the sync thread to acknowledge the shutdown
11450bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten        while (!thiz->mEngine.mShutdownAck) {
11550bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten            object_cond_wait(&thiz->mObject);
116cc484cd4b7ede364e95209eb0468df3bc51f50e5Glenn Kasten        }
117cc484cd4b7ede364e95209eb0468df3bc51f50e5Glenn Kasten        // The sync thread should have exited by now, so collect it by joining
11850bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten        (void) pthread_join(thiz->mSyncThread, (void **) NULL);
119cc484cd4b7ede364e95209eb0468df3bc51f50e5Glenn Kasten
120b0a0555e2fcad41d3ee0c45f0f75ed556dbee282Glenn Kasten    }
121b0a0555e2fcad41d3ee0c45f0f75ed556dbee282Glenn Kasten
122b0a0555e2fcad41d3ee0c45f0f75ed556dbee282Glenn Kasten    // Shutdown the thread pool used for asynchronous operations (there should not be any)
12350bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    ThreadPool_deinit(&thiz->mThreadPool);
1243be625f40588941aa23e35fed5cb693ddc9718daGlenn Kasten
1250b718abd78bd3e4022008fe0492fb76b265d26d1Glenn Kasten#if defined(ANDROID)
1263be625f40588941aa23e35fed5cb693ddc9718daGlenn Kasten    // free equalizer preset names
12750bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    if (NULL != thiz->mEqPresetNames) {
12850bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten        for (unsigned i = 0; i < thiz->mEqNumPresets; ++i) {
12950bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten            if (NULL != thiz->mEqPresetNames[i]) {
13050bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten                delete[] thiz->mEqPresetNames[i];
13150bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten                thiz->mEqPresetNames[i] = NULL;
1323be625f40588941aa23e35fed5cb693ddc9718daGlenn Kasten            }
1333be625f40588941aa23e35fed5cb693ddc9718daGlenn Kasten        }
13450bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten        delete[] thiz->mEqPresetNames;
13550bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten        thiz->mEqPresetNames = NULL;
1363be625f40588941aa23e35fed5cb693ddc9718daGlenn Kasten    }
13750bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    thiz->mEqNumPresets = 0;
1383be625f40588941aa23e35fed5cb693ddc9718daGlenn Kasten#endif
139b0a0555e2fcad41d3ee0c45f0f75ed556dbee282Glenn Kasten
140b0a0555e2fcad41d3ee0c45f0f75ed556dbee282Glenn Kasten#ifdef USE_SDL
141b0a0555e2fcad41d3ee0c45f0f75ed556dbee282Glenn Kasten    SDL_close();
142b0a0555e2fcad41d3ee0c45f0f75ed556dbee282Glenn Kasten#endif
1431f5702ed2239c79b701aa8cc3c675798b34a9656Jean-Michel Trivi
144437f9ab9914ea61112aa496a047162a0d22194cdGlenn Kasten}
1454f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten
1464f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten
1474f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten/** \brief Hook called by Object::Destroy before an engine is about to be destroyed */
1484f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten
149b11def0293629d4d44ddbcd8a27c63504fd80ce1Glenn Kastenpredestroy_t CEngine_PreDestroy(void *self)
1504f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten{
151b11def0293629d4d44ddbcd8a27c63504fd80ce1Glenn Kasten    predestroy_t ret;
152b11def0293629d4d44ddbcd8a27c63504fd80ce1Glenn Kasten    (void) pthread_mutex_lock(&theOneTrueMutex);
153b11def0293629d4d44ddbcd8a27c63504fd80ce1Glenn Kasten    assert(self == theOneTrueEngine);
154b11def0293629d4d44ddbcd8a27c63504fd80ce1Glenn Kasten    switch (theOneTrueRefCount) {
155b11def0293629d4d44ddbcd8a27c63504fd80ce1Glenn Kasten    case 0:
156b11def0293629d4d44ddbcd8a27c63504fd80ce1Glenn Kasten        assert(false);
157b11def0293629d4d44ddbcd8a27c63504fd80ce1Glenn Kasten        ret = predestroy_error;
158b11def0293629d4d44ddbcd8a27c63504fd80ce1Glenn Kasten        break;
159b11def0293629d4d44ddbcd8a27c63504fd80ce1Glenn Kasten    case 1:
160b11def0293629d4d44ddbcd8a27c63504fd80ce1Glenn Kasten        ret = predestroy_ok;
161b11def0293629d4d44ddbcd8a27c63504fd80ce1Glenn Kasten        break;
162b11def0293629d4d44ddbcd8a27c63504fd80ce1Glenn Kasten    default:
163b11def0293629d4d44ddbcd8a27c63504fd80ce1Glenn Kasten        --theOneTrueRefCount;
164b11def0293629d4d44ddbcd8a27c63504fd80ce1Glenn Kasten        ret = predestroy_again;
165b11def0293629d4d44ddbcd8a27c63504fd80ce1Glenn Kasten        break;
166b11def0293629d4d44ddbcd8a27c63504fd80ce1Glenn Kasten    }
167b11def0293629d4d44ddbcd8a27c63504fd80ce1Glenn Kasten    (void) pthread_mutex_unlock(&theOneTrueMutex);
168b11def0293629d4d44ddbcd8a27c63504fd80ce1Glenn Kasten    return ret;
1694f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten}
170a930d729ff2249eaa0b45a5e61c70bebad45f698Glenn Kasten
171a930d729ff2249eaa0b45a5e61c70bebad45f698Glenn Kasten
172a930d729ff2249eaa0b45a5e61c70bebad45f698Glenn Kasten/** \brief Called by IObject::Destroy after engine is destroyed. The parameter refers to the
173a930d729ff2249eaa0b45a5e61c70bebad45f698Glenn Kasten *  previous engine, which is now undefined memory.
174a930d729ff2249eaa0b45a5e61c70bebad45f698Glenn Kasten */
175a930d729ff2249eaa0b45a5e61c70bebad45f698Glenn Kasten
176a930d729ff2249eaa0b45a5e61c70bebad45f698Glenn Kastenvoid CEngine_Destroyed(CEngine *self)
177a930d729ff2249eaa0b45a5e61c70bebad45f698Glenn Kasten{
178a930d729ff2249eaa0b45a5e61c70bebad45f698Glenn Kasten    int ok;
179a930d729ff2249eaa0b45a5e61c70bebad45f698Glenn Kasten    ok = pthread_mutex_lock(&theOneTrueMutex);
180a930d729ff2249eaa0b45a5e61c70bebad45f698Glenn Kasten    assert(0 == ok);
181a930d729ff2249eaa0b45a5e61c70bebad45f698Glenn Kasten    assert(self == theOneTrueEngine);
182a930d729ff2249eaa0b45a5e61c70bebad45f698Glenn Kasten    theOneTrueEngine = NULL;
183b11def0293629d4d44ddbcd8a27c63504fd80ce1Glenn Kasten    assert(1 == theOneTrueRefCount);
184b11def0293629d4d44ddbcd8a27c63504fd80ce1Glenn Kasten    theOneTrueRefCount = 0;
185a930d729ff2249eaa0b45a5e61c70bebad45f698Glenn Kasten    ok = pthread_mutex_unlock(&theOneTrueMutex);
186a930d729ff2249eaa0b45a5e61c70bebad45f698Glenn Kasten    assert(0 == ok);
187a930d729ff2249eaa0b45a5e61c70bebad45f698Glenn Kasten}
188