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