• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
onDlOpen(void)37 __attribute__((constructor)) static void onDlOpen(void)
38 {
39 }
40 
41 
42 /** \brief Called by dlclose when .so is unloaded */
43 
onDlClose(void)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 
CEngine_Realize(void * self,SLboolean async)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 
CEngine_Resume(void * self,SLboolean async)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 
CEngine_Destroy(void * self)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 
CEngine_PreDestroy(void * self)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 
CEngine_Destroyed(CEngine * self)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