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