CEngine.c revision 262059f71a68edc5e510427c63f5f1623d3672a8
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
24CEngine *theOneTrueEngine = NULL;
25pthread_mutex_t theOneTrueMutex = PTHREAD_MUTEX_INITIALIZER;
26unsigned 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    if ((NULL != theOneTrueEngine) || (0 < theOneTrueRefCount)) {
42        SL_LOGE("Object::Destroy omitted for engine %p", theOneTrueEngine);
43    }
44}
45
46
47/** \brief Hook called by Object::Realize when an engine is realized */
48
49SLresult CEngine_Realize(void *self, SLboolean async)
50{
51    CEngine *this = (CEngine *) self;
52    SLresult result;
53#ifndef ANDROID
54    // create the sync thread
55    int err = pthread_create(&this->mSyncThread, (const pthread_attr_t *) NULL, sync_start, this);
56    result = err_to_result(err);
57    if (SL_RESULT_SUCCESS != result)
58        return result;
59#endif
60    // initialize the thread pool for asynchronous operations
61    result = ThreadPool_init(&this->mThreadPool, 0, 0);
62    if (SL_RESULT_SUCCESS != result) {
63        this->mEngine.mShutdown = SL_BOOLEAN_TRUE;
64        (void) pthread_join(this->mSyncThread, (void **) NULL);
65        return result;
66    }
67#ifdef USE_SDL
68    SDL_open(&this->mEngine);
69#endif
70    return SL_RESULT_SUCCESS;
71}
72
73
74/** \brief Hook called by Object::Resume when an engine is resumed */
75
76SLresult CEngine_Resume(void *self, SLboolean async)
77{
78    return SL_RESULT_SUCCESS;
79}
80
81
82/** \brief Hook called by Object::Destroy when an engine is destroyed */
83
84void CEngine_Destroy(void *self)
85{
86    CEngine *this = (CEngine *) self;
87
88    // Verify that there are no extant objects
89    unsigned instanceCount = this->mEngine.mInstanceCount;
90    unsigned instanceMask = this->mEngine.mInstanceMask;
91    if ((0 < instanceCount) || (0 != instanceMask)) {
92        SL_LOGE("Object::Destroy(%p) for engine ignored; %u total active objects",
93            this, instanceCount);
94        while (0 != instanceMask) {
95            unsigned i = ctz(instanceMask);
96            assert(MAX_INSTANCE > i);
97            SL_LOGE("Object::Destroy(%p) for engine ignored; active object ID %u at %p",
98                this, i + 1, this->mEngine.mInstances[i]);
99            instanceMask &= ~(1 << i);
100        }
101    }
102
103    // If engine was created but not realized, there will be no sync thread yet
104    pthread_t zero;
105    memset(&zero, 0, sizeof(pthread_t));
106    if (0 != memcmp(&zero, &this->mSyncThread, sizeof(pthread_t))) {
107
108        // Announce to the sync thread that engine is shutting down; it polls so should see it soon
109        this->mEngine.mShutdown = SL_BOOLEAN_TRUE;
110        // Wait for the sync thread to acknowledge the shutdown
111        while (!this->mEngine.mShutdownAck) {
112            object_cond_wait(&this->mObject);
113        }
114        // The sync thread should have exited by now, so collect it by joining
115        (void) pthread_join(this->mSyncThread, (void **) NULL);
116
117    }
118
119    // Shutdown the thread pool used for asynchronous operations (there should not be any)
120    ThreadPool_deinit(&this->mThreadPool);
121
122#if defined(ANDROID)
123    // free equalizer preset names
124    if (NULL != this->mEqPresetNames) {
125        for (unsigned i = 0; i < this->mEqNumPresets; ++i) {
126            if (NULL != this->mEqPresetNames[i]) {
127                delete[] this->mEqPresetNames[i];
128                this->mEqPresetNames[i] = NULL;
129            }
130        }
131        delete[] this->mEqPresetNames;
132        this->mEqPresetNames = NULL;
133    }
134    this->mEqNumPresets = 0;
135#endif
136
137#ifdef USE_SDL
138    SDL_close();
139#endif
140
141}
142
143
144/** \brief Hook called by Object::Destroy before an engine is about to be destroyed */
145
146predestroy_t CEngine_PreDestroy(void *self)
147{
148    predestroy_t ret;
149    (void) pthread_mutex_lock(&theOneTrueMutex);
150    assert(self == theOneTrueEngine);
151    switch (theOneTrueRefCount) {
152    case 0:
153        assert(false);
154        ret = predestroy_error;
155        break;
156    case 1:
157        ret = predestroy_ok;
158        break;
159    default:
160        --theOneTrueRefCount;
161        ret = predestroy_again;
162        break;
163    }
164    (void) pthread_mutex_unlock(&theOneTrueMutex);
165    return ret;
166}
167
168
169/** \brief Called by IObject::Destroy after engine is destroyed. The parameter refers to the
170 *  previous engine, which is now undefined memory.
171 */
172
173void CEngine_Destroyed(CEngine *self)
174{
175    int ok;
176    ok = pthread_mutex_lock(&theOneTrueMutex);
177    assert(0 == ok);
178    assert(self == theOneTrueEngine);
179    theOneTrueEngine = NULL;
180    assert(1 == theOneTrueRefCount);
181    theOneTrueRefCount = 0;
182    ok = pthread_mutex_unlock(&theOneTrueMutex);
183    assert(0 == ok);
184}
185