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 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 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 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 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 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 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