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 
24 CEngine *theOneTrueEngine = NULL;
25 pthread_mutex_t theOneTrueMutex = PTHREAD_MUTEX_INITIALIZER;
26 unsigned 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 
onDlOpen(void)32 __attribute__((constructor)) static void onDlOpen(void)
33 {
34 }
35 
36 
37 /** \brief Called by dlclose when .so is unloaded */
38 
onDlClose(void)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 
CEngine_Realize(void * self,SLboolean async)52 SLresult 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 
CEngine_Resume(void * self,SLboolean async)79 SLresult 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 
CEngine_Destroy(void * self)87 void 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 
CEngine_PreDestroy(void * self)149 predestroy_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 
CEngine_Destroyed(CEngine * self)176 void 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