Home | History | Annotate | Download | only in objects
      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