CEngine.cpp revision c8a305bcafc009615270a30186b711fc33f85b91
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
29CEngine *theOneTrueEngine = NULL;
30pthread_mutex_t theOneTrueMutex = PTHREAD_MUTEX_INITIALIZER;
31unsigned 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
57SLresult 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
94SLresult 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
102void 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
168predestroy_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
195void 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