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