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/** \file CEngine.c Engine class */
18
19#include "sles_allinclusive.h"
20
21
22/* This implementation supports at most one engine, identical for both OpenSL ES and OpenMAX AL */
23
24CEngine *theOneTrueEngine = NULL;
25pthread_mutex_t theOneTrueMutex = PTHREAD_MUTEX_INITIALIZER;
26unsigned theOneTrueRefCount = 0;
27// incremented by slCreateEngine or xaCreateEngine, decremented by Object::Destroy on engine
28
29
30/** \brief Called by dlopen when .so is loaded */
31
32__attribute__((constructor)) static void onDlOpen(void)
33{
34}
35
36
37/** \brief Called by dlclose when .so is unloaded */
38
39__attribute__((destructor)) static void onDlClose(void)
40{
41    // a memory barrier would be sufficient, but the mutex is easier
42    (void) pthread_mutex_lock(&theOneTrueMutex);
43    if ((NULL != theOneTrueEngine) || (0 < theOneTrueRefCount)) {
44        SL_LOGE("Object::Destroy omitted for engine %p", theOneTrueEngine);
45    }
46    (void) pthread_mutex_unlock(&theOneTrueMutex);
47}
48
49
50/** \brief Hook called by Object::Realize when an engine is realized */
51
52SLresult CEngine_Realize(void *self, SLboolean async)
53{
54    CEngine *thiz = (CEngine *) self;
55    SLresult result;
56#ifndef ANDROID
57    // create the sync thread
58    int err = pthread_create(&thiz->mSyncThread, (const pthread_attr_t *) NULL, sync_start, thiz);
59    result = err_to_result(err);
60    if (SL_RESULT_SUCCESS != result)
61        return result;
62#endif
63    // initialize the thread pool for asynchronous operations
64    result = ThreadPool_init(&thiz->mThreadPool, 0, 0);
65    if (SL_RESULT_SUCCESS != result) {
66        thiz->mEngine.mShutdown = SL_BOOLEAN_TRUE;
67        (void) pthread_join(thiz->mSyncThread, (void **) NULL);
68        return result;
69    }
70#ifdef USE_SDL
71    SDL_open(&thiz->mEngine);
72#endif
73    return SL_RESULT_SUCCESS;
74}
75
76
77/** \brief Hook called by Object::Resume when an engine is resumed */
78
79SLresult CEngine_Resume(void *self, SLboolean async)
80{
81    return SL_RESULT_SUCCESS;
82}
83
84
85/** \brief Hook called by Object::Destroy when an engine is destroyed */
86
87void CEngine_Destroy(void *self)
88{
89    CEngine *thiz = (CEngine *) self;
90
91    // Verify that there are no extant objects
92    unsigned instanceCount = thiz->mEngine.mInstanceCount;
93    unsigned instanceMask = thiz->mEngine.mInstanceMask;
94    if ((0 < instanceCount) || (0 != instanceMask)) {
95        SL_LOGE("Object::Destroy(%p) for engine ignored; %u total active objects",
96            thiz, instanceCount);
97        while (0 != instanceMask) {
98            unsigned i = ctz(instanceMask);
99            assert(MAX_INSTANCE > i);
100            SL_LOGE("Object::Destroy(%p) for engine ignored; active object ID %u at %p",
101                thiz, i + 1, thiz->mEngine.mInstances[i]);
102            instanceMask &= ~(1 << i);
103        }
104    }
105
106    // If engine was created but not realized, there will be no sync thread yet
107    pthread_t zero;
108    memset(&zero, 0, sizeof(pthread_t));
109    if (0 != memcmp(&zero, &thiz->mSyncThread, sizeof(pthread_t))) {
110
111        // Announce to the sync thread that engine is shutting down; it polls so should see it soon
112        thiz->mEngine.mShutdown = SL_BOOLEAN_TRUE;
113        // Wait for the sync thread to acknowledge the shutdown
114        while (!thiz->mEngine.mShutdownAck) {
115            object_cond_wait(&thiz->mObject);
116        }
117        // The sync thread should have exited by now, so collect it by joining
118        (void) pthread_join(thiz->mSyncThread, (void **) NULL);
119
120    }
121
122    // Shutdown the thread pool used for asynchronous operations (there should not be any)
123    ThreadPool_deinit(&thiz->mThreadPool);
124
125#if defined(ANDROID)
126    // free equalizer preset names
127    if (NULL != thiz->mEqPresetNames) {
128        for (unsigned i = 0; i < thiz->mEqNumPresets; ++i) {
129            if (NULL != thiz->mEqPresetNames[i]) {
130                delete[] thiz->mEqPresetNames[i];
131                thiz->mEqPresetNames[i] = NULL;
132            }
133        }
134        delete[] thiz->mEqPresetNames;
135        thiz->mEqPresetNames = NULL;
136    }
137    thiz->mEqNumPresets = 0;
138#endif
139
140#ifdef USE_SDL
141    SDL_close();
142#endif
143
144}
145
146
147/** \brief Hook called by Object::Destroy before an engine is about to be destroyed */
148
149predestroy_t CEngine_PreDestroy(void *self)
150{
151    predestroy_t ret;
152    (void) pthread_mutex_lock(&theOneTrueMutex);
153    assert(self == theOneTrueEngine);
154    switch (theOneTrueRefCount) {
155    case 0:
156        assert(false);
157        ret = predestroy_error;
158        break;
159    case 1:
160        ret = predestroy_ok;
161        break;
162    default:
163        --theOneTrueRefCount;
164        ret = predestroy_again;
165        break;
166    }
167    (void) pthread_mutex_unlock(&theOneTrueMutex);
168    return ret;
169}
170
171
172/** \brief Called by IObject::Destroy after engine is destroyed. The parameter refers to the
173 *  previous engine, which is now undefined memory.
174 */
175
176void CEngine_Destroyed(CEngine *self)
177{
178    int ok;
179    ok = pthread_mutex_lock(&theOneTrueMutex);
180    assert(0 == ok);
181    assert(self == theOneTrueEngine);
182    theOneTrueEngine = NULL;
183    assert(1 == theOneTrueRefCount);
184    theOneTrueRefCount = 0;
185    ok = pthread_mutex_unlock(&theOneTrueMutex);
186    assert(0 == ok);
187}
188