bool COutputMix_PreDestroy(void *self) { // Ignore destroy requests if there are any players attached to this output mix COutputMix *outputMix = (COutputMix *) self; // See design document for explanation if (0 == outputMix->mObject.mStrongRefCount) { #ifdef USE_OUTPUTMIXEXT // We only support a single active output mix per engine, so check if this is the active mix IEngine *thisEngine = outputMix->mObject.mEngine; interface_lock_exclusive(thisEngine); bool thisIsTheActiveOutputMix = false; if (outputMix == thisEngine->mOutputMix) { thisIsTheActiveOutputMix = true; } interface_unlock_exclusive(thisEngine); if (thisIsTheActiveOutputMix) { // Tell the asynchronous mixer callback that we want to destroy the output mix outputMix->mOutputMixExt.mDestroyRequested = true; while (outputMix->mOutputMixExt.mDestroyRequested) { object_cond_wait(&outputMix->mObject); } #ifdef USE_SDL // Mixer callback has acknowledged our request and unlinked output mix from engine. // Disable SDL_callback from being called periodically by SDL's internal thread. SDL_PauseAudio(1); #endif } #endif return true; } SL_LOGE("Object::Destroy(%p) for OutputMix ignored; %u players attached", outputMix, outputMix->mObject.mStrongRefCount); return false; }
void CEngine_Destroy(void *self) { CEngine *thiz = (CEngine *) self; // Verify that there are no extant objects unsigned instanceCount = thiz->mEngine.mInstanceCount; unsigned instanceMask = thiz->mEngine.mInstanceMask; if ((0 < instanceCount) || (0 != instanceMask)) { SL_LOGE("Object::Destroy(%p) for engine ignored; %u total active objects", thiz, instanceCount); while (0 != instanceMask) { unsigned i = ctz(instanceMask); assert(MAX_INSTANCE > i); SL_LOGE("Object::Destroy(%p) for engine ignored; active object ID %u at %p", thiz, i + 1, thiz->mEngine.mInstances[i]); instanceMask &= ~(1 << i); } } // If engine was created but not realized, there will be no sync thread yet pthread_t zero; memset(&zero, 0, sizeof(pthread_t)); if (0 != memcmp(&zero, &thiz->mSyncThread, sizeof(pthread_t))) { // Announce to the sync thread that engine is shutting down; it polls so should see it soon thiz->mEngine.mShutdown = SL_BOOLEAN_TRUE; // Wait for the sync thread to acknowledge the shutdown while (!thiz->mEngine.mShutdownAck) { object_cond_wait(&thiz->mObject); } // The sync thread should have exited by now, so collect it by joining (void) pthread_join(thiz->mSyncThread, (void **) NULL); } // Shutdown the thread pool used for asynchronous operations (there should not be any) ThreadPool_deinit(&thiz->mThreadPool); #if defined(ANDROID) // free equalizer preset names if (NULL != thiz->mEqPresetNames) { for (unsigned i = 0; i < thiz->mEqNumPresets; ++i) { if (NULL != thiz->mEqPresetNames[i]) { delete[] thiz->mEqPresetNames[i]; thiz->mEqPresetNames[i] = NULL; } } delete[] thiz->mEqPresetNames; thiz->mEqPresetNames = NULL; } thiz->mEqNumPresets = 0; #endif #ifdef USE_SDL SDL_close(); #endif }