From 2a25d97e40dbd5dd9195195a3a269095a4932097 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Tue, 5 Oct 2010 07:46:26 -0700 Subject: [PATCH] Object an interface initialization/destroy cleanup Prior to this, object and interface fields were being initialized and deinitialized in random places. This resulted in some real and potential leaks, especially in the case of partial object construction. There were even some places where fields were not being initialized at all. Details: Move destructor for AndroidEffectCapabilities from CEngine::Destroy to IAndroidEffectCapabilities deinit hook. Move destructor for equalizer preset names from CEngine::Destroy to IEngine deinit hook. In Object::Destroy, call deinitializer for each initialized interface, regardless whether it was ever exposed. Remove double initialization of mStepSize in IPlaybackRate constructor. Remove obsolete logs. Add expose hooks that are called when interface is requested in Engine::Create... or by DynamicInterface::AddInterface. Always initialize all interfaces, even if not exposed Fix typos in same-line comments on INTERFACE_ constants. Add new interface state INITIALIZED: uninitialized -> initialized -> exposed. DynamicInterface::Remove sets interface state to initialized (but not exposed), instead of uninitialized. Add explicit constructor calls to initialize fields in C structs (e.g. smart pointers), using placement new. See also build warning which was turned off with -Wno-invalid-offsetof. Add comments about per-instance fields not associated with an interface. Add default initializations for all per-instance fields that are not associated with an interface, in case the object is only partially constructed and then needs to be destroyed due to an error. Add placement new comments. Update comments on private per-instance fields not associated with an interface. Move effect clears from the containing object destructor (CAudioPlayer_Destroy and COutputMix_Destroy) to the interface destructor. In this process this caught a bug that environmental reverb and preset reverb were not being destroyed properly for an audio player. Add comments on interface hooks. Add entries for interface destructors. Add placement new (explicit constructor) and explicit destructor calls for C++ fields in C struct. Fix template instantiation error. Move explicit calls to IBufferQueue_Destroy (now renamed to IBufferQueue_deinit) from CAudioPlayer_Destroy and CAudioRecorder_Destroy to be implicit via the BufferQueue interface deinit hook. ThreadSync interface destructor now logs a warning if ThreadSync::EnterCriticalSection was active at Engine::Destroy Add some comments. Clean up gMonitorFp close code. Fix typo in log message. Fix DynamicInterface to handle distinction between UNINITIALIZED and INITIALIZED states for an interface, and to call the optional expose hook. Do not use memset per interface, because the size of the last interface is unknown. Set the v-table pointer while lock is held. Add curlies to if statements. Log errors if interfaces active during Object::Destroy, instead of asserting. Log a warning if interface requests an interface but it is not available, and is optional. Add log with the class name and address of each new object. Mark only interfaces with init hooks as INITIALIZED; others are UNINITIALIZED. Change-Id: Ibb9c1b5f21e6195af6b20b2f7a5c7157905b735b --- opensles/libopensles/CAudioPlayer.c | 1 - opensles/libopensles/CAudioRecorder.c | 1 - opensles/libopensles/CEngine.c | 17 -- opensles/libopensles/IAndroidEffect.c | 18 ++- opensles/libopensles/IAndroidEffectCapabilities.c | 42 +++-- opensles/libopensles/IBassBoost.c | 20 +++ opensles/libopensles/IBufferQueue.c | 10 +- opensles/libopensles/IDeviceVolume.c | 7 +- opensles/libopensles/IDynamicInterfaceManagement.c | 80 +++++----- opensles/libopensles/IDynamicSource.c | 3 +- opensles/libopensles/IEngine.c | 67 +++++++- opensles/libopensles/IEnvironmentalReverb.c | 21 ++- opensles/libopensles/IEqualizer.c | 23 ++- opensles/libopensles/IMetadataExtraction.c | 1 + opensles/libopensles/IObject.c | 24 +-- opensles/libopensles/IPlaybackRate.c | 2 - opensles/libopensles/IPresetReverb.c | 20 +++ opensles/libopensles/IRecord.c | 2 - opensles/libopensles/IThreadSync.c | 8 + opensles/libopensles/IVirtualizer.c | 20 +++ opensles/libopensles/android_AudioPlayer.cpp | 31 ++-- opensles/libopensles/android_AudioRecorder.cpp | 6 +- opensles/libopensles/android_OutputMix.cpp | 30 +--- opensles/libopensles/sles.c | 175 +++++++++++++-------- opensles/libopensles/sles_allinclusive.h | 61 ++++--- 25 files changed, 444 insertions(+), 246 deletions(-) diff --git a/opensles/libopensles/CAudioPlayer.c b/opensles/libopensles/CAudioPlayer.c index 8bee03c3..3bcb7b12 100644 --- a/opensles/libopensles/CAudioPlayer.c +++ b/opensles/libopensles/CAudioPlayer.c @@ -57,7 +57,6 @@ void CAudioPlayer_Destroy(void *self) CAudioPlayer *this = (CAudioPlayer *) self; freeDataLocatorFormat(&this->mDataSource); freeDataLocatorFormat(&this->mDataSink); - IBufferQueue_Destroy(&this->mBufferQueue); #ifdef USE_SNDFILE SndFile_Destroy(this); #endif diff --git a/opensles/libopensles/CAudioRecorder.c b/opensles/libopensles/CAudioRecorder.c index f1c7ccf4..4171e5fe 100644 --- a/opensles/libopensles/CAudioRecorder.c +++ b/opensles/libopensles/CAudioRecorder.c @@ -50,7 +50,6 @@ void CAudioRecorder_Destroy(void *self) freeDataLocatorFormat(&this->mDataSource); freeDataLocatorFormat(&this->mDataSink); #ifdef ANDROID - IBufferQueue_Destroy(&this->mBufferQueue); android_audioRecorder_destroy(this); #endif } diff --git a/opensles/libopensles/CEngine.c b/opensles/libopensles/CEngine.c index 0811e0e1..dba7c29e 100644 --- a/opensles/libopensles/CEngine.c +++ b/opensles/libopensles/CEngine.c @@ -91,23 +91,6 @@ void CEngine_Destroy(void *self) // Shutdown the thread pool used for asynchronous operations (there should not be any) ThreadPool_deinit(&this->mEngine.mThreadPool); -#if defined(ANDROID) && !defined(USE_BACKPORT) - // free effect data - // free EQ data - if ((0 < this->mEngine.mEqNumPresets) && (NULL != this->mEngine.mEqPresetNames)) { - for(uint32_t i = 0 ; i < this->mEngine.mEqNumPresets ; i++) { - if (NULL != this->mEngine.mEqPresetNames[i]) { - delete [] this->mEngine.mEqPresetNames[i]; - } - } - delete [] this->mEngine.mEqPresetNames; - } - // free effect library data - if (NULL != this->mAndroidEffectCapabilities.mFxDescriptors) { - delete [] this->mAndroidEffectCapabilities.mFxDescriptors; - } -#endif - #ifdef USE_SDL SDL_close(); #endif diff --git a/opensles/libopensles/IAndroidEffect.c b/opensles/libopensles/IAndroidEffect.c index c1900f4c..6e24eb5e 100644 --- a/opensles/libopensles/IAndroidEffect.c +++ b/opensles/libopensles/IAndroidEffect.c @@ -107,8 +107,20 @@ void IAndroidEffect_init(void *self) { IAndroidEffect *this = (IAndroidEffect *) self; this->mItf = &IAndroidEffect_Itf; + this->mEffects = new android::KeyedVector(); +} - // mEffects lifecycle is handled by the object on which SLAndroidEffect is exposed. This is a - // safety initialization just in case the object is partially constructed and then destroyed. - this->mEffects = NULL; +void IAndroidEffect_deinit(void *self) +{ + IAndroidEffect *this = (IAndroidEffect *) self; + if (NULL != this->mEffects) { + if (!this->mEffects->isEmpty()) { + for (size_t i = 0 ; i < this->mEffects->size() ; i++) { + delete this->mEffects->valueAt(i); + } + this->mEffects->clear(); + } + delete this->mEffects; + this->mEffects = NULL; + } } diff --git a/opensles/libopensles/IAndroidEffectCapabilities.c b/opensles/libopensles/IAndroidEffectCapabilities.c index 85fdd004..2a539de4 100644 --- a/opensles/libopensles/IAndroidEffectCapabilities.c +++ b/opensles/libopensles/IAndroidEffectCapabilities.c @@ -81,20 +81,33 @@ void IAndroidEffectCapabilities_init(void *self) IAndroidEffectCapabilities *this = (IAndroidEffectCapabilities *) self; this->mItf = &IAndroidEffectCapabilities_Itf; + // This is the default initialization; fields will be updated when interface is exposed this->mNumFx = 0; - SLuint32 numEffects; - if (SL_RESULT_SUCCESS == android_genericFx_queryNumEffects(&numEffects)) { - this->mNumFx = numEffects; + this->mFxDescriptors = NULL; +} + +bool IAndroidEffectCapabilities_Expose(void *self) +{ + IAndroidEffectCapabilities *this = (IAndroidEffectCapabilities *) self; + SLuint32 numEffects = 0; + SLresult result = android_genericFx_queryNumEffects(&numEffects); + if (SL_RESULT_SUCCESS != result) { + SL_LOGE("android_genericFx_queryNumEffects %lu", result); + return false; } + this->mNumFx = numEffects; SL_LOGV("Effect Capabilities has %ld effects", this->mNumFx); - if (this->mNumFx > 0) { - SLresult result = SL_RESULT_SUCCESS; this->mFxDescriptors = (effect_descriptor_t*) new effect_descriptor_t[this->mNumFx]; for (SLuint32 i = 0 ; i < this->mNumFx ; i++) { - result = android_genericFx_queryEffect(i, &this->mFxDescriptors[i]); - if (SL_RESULT_SUCCESS != result) { - SL_LOGE("Error (SLresult is %ld) querying effect %ld", result, i); + SLresult result2; + result2 = android_genericFx_queryEffect(i, &this->mFxDescriptors[i]); + if (SL_RESULT_SUCCESS != result2) { + SL_LOGE("Error (SLresult is %ld) querying effect %ld", result2, i); + // Remember the first failing result code, but keep going + if (SL_RESULT_SUCCESS == result) { + result = result2; + } } else { SL_LOGV("effect %ld: type=%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x name=%s", i, @@ -111,9 +124,16 @@ void IAndroidEffectCapabilities_init(void *self) this->mFxDescriptors[i].name); } } - } else { - // for safety - this->mFxDescriptors = NULL; } + return SL_RESULT_SUCCESS == result; +} +void IAndroidEffectCapabilities_deinit(void *self) +{ + IAndroidEffectCapabilities *this = (IAndroidEffectCapabilities *) self; + // free effect library data + if (NULL != this->mFxDescriptors) { + delete[] this->mFxDescriptors; + this->mFxDescriptors = NULL; + } } diff --git a/opensles/libopensles/IBassBoost.c b/opensles/libopensles/IBassBoost.c index c473da78..3e001b3d 100644 --- a/opensles/libopensles/IBassBoost.c +++ b/opensles/libopensles/IBassBoost.c @@ -185,11 +185,31 @@ void IBassBoost_init(void *self) this->mItf = &IBassBoost_Itf; this->mEnabled = SL_BOOLEAN_FALSE; this->mStrength = 0; +#if defined(ANDROID) && !defined(USE_BACKPORT) + memset(&this->mBassBoostDescriptor, 0, sizeof(effect_descriptor_t)); + // placement new (explicit constructor) + (void) new (&this->mBassBoostEffect) android::sp(); +#endif +} +void IBassBoost_deinit(void *self) +{ #if defined(ANDROID) && !defined(USE_BACKPORT) + IBassBoost *this = (IBassBoost *) self; + // explicit destructor + this->mBassBoostEffect.~sp(); +#endif +} + +bool IBassBoost_Expose(void *self) +{ +#if defined(ANDROID) && !defined(USE_BACKPORT) + IBassBoost *this = (IBassBoost *) self; if (!android_fx_initEffectDescriptor(SL_IID_BASSBOOST, &this->mBassBoostDescriptor)) { // BassBoost init failed SL_LOGE("BassBoost initialization failed."); + return false; } #endif + return true; } diff --git a/opensles/libopensles/IBufferQueue.c b/opensles/libopensles/IBufferQueue.c index d55a6b2a..a93888c0 100644 --- a/opensles/libopensles/IBufferQueue.c +++ b/opensles/libopensles/IBufferQueue.c @@ -172,7 +172,6 @@ static const struct SLBufferQueueItf_ IBufferQueue_Itf = { void IBufferQueue_init(void *self) { - //SL_LOGV("IBufferQueue_init(%p) entering", self); IBufferQueue *this = (IBufferQueue *) self; this->mItf = &IBufferQueue_Itf; this->mState.count = 0; @@ -196,12 +195,13 @@ void IBufferQueue_init(void *self) } -/** \brief Free the buffer queue, if it was larger than typical. - * Called by CAudioPlayer_Destroy and CAudioRecorder_Destroy. - */ +/** \brief Interface deinitialization hook called by IObject::Destroy. + * Free the buffer queue, if it was larger than typical. + */ -void IBufferQueue_Destroy(IBufferQueue *this) +void IBufferQueue_deinit(void *self) { + IBufferQueue *this = (IBufferQueue *) self; if ((NULL != this->mArray) && (this->mArray != this->mTypical)) { free(this->mArray); this->mArray = NULL; diff --git a/opensles/libopensles/IDeviceVolume.c b/opensles/libopensles/IDeviceVolume.c index 82650c07..346e5d83 100644 --- a/opensles/libopensles/IDeviceVolume.c +++ b/opensles/libopensles/IDeviceVolume.c @@ -119,7 +119,8 @@ void IDeviceVolume_init(void *self) { IDeviceVolume *this = (IDeviceVolume *) self; this->mItf = &IDeviceVolume_Itf; - // hard-coded array size for default in/out - this->mVolume[0] = 10; - this->mVolume[1] = 10; + unsigned i; + for (i = 0; i < MAX_DEVICE; ++i) { + this->mVolume[i] = 10; + } } diff --git a/opensles/libopensles/IDynamicInterfaceManagement.c b/opensles/libopensles/IDynamicInterfaceManagement.c index 8a30f7ad..26d6c99c 100644 --- a/opensles/libopensles/IDynamicInterfaceManagement.c +++ b/opensles/libopensles/IDynamicInterfaceManagement.c @@ -53,29 +53,29 @@ static void HandleAdd(void *self, int MPH) const struct iid_vtable *x = &class__->mInterfaces[index]; size_t offset = x->mOffset; void *thisItf = (char *) thisObject + offset; - size_t size = ((SLuint32) (index + 1) == class__->mInterfaceCount ? - class__->mSize : x[1].mOffset) - offset; - memset(thisItf, 0, size); - // Will never add IObject, so [1] is always defined - ((void **) thisItf)[1] = thisObject; - VoidHook init = MPH_init_table[MPH].mInit; - // paranoid double-check for presence of an initialization hook - if (NULL != init) { - (*init)(thisItf); - ((size_t *) thisItf)[0] ^= ~0; + BoolHook expose = MPH_init_table[MPH].mExpose; + // call the optional expose hook + if ((NULL == expose) || (*expose)(thisItf)) { + result = SL_RESULT_SUCCESS; + } else { + result = SL_RESULT_FEATURE_UNSUPPORTED; } - result = SL_RESULT_SUCCESS; // re-lock mutex to update state object_lock_exclusive(thisObject); assert(INTERFACE_ADDING_2 == *interfaceStateP); - state = INTERFACE_ADDED; + if (SL_RESULT_SUCCESS == result) { + ((size_t *) thisItf)[0] ^= ~0; + state = INTERFACE_ADDED; + } else { + state = INTERFACE_INITIALIZED; + } } break; case INTERFACE_ADDING_1A: // operation was aborted while on work queue result = SL_RESULT_OPERATION_ABORTED; - state = INTERFACE_UNINITIALIZED; + state = INTERFACE_INITIALIZED; break; default: // impossible @@ -116,8 +116,8 @@ static SLresult IDynamicInterfaceManagement_AddInterface(SLDynamicInterfaceManag const ClassTable *class__ = thisObject->mClass; int MPH, index; if ((0 > (MPH = IID_to_MPH(iid))) || - // there must be an initialization hook present - (NULL == MPH_init_table[MPH].mInit) || + // no need to check for an initialization hook + // (NULL == MPH_init_table[MPH].mInit) || (0 > (index = class__->mMPH_to_index[MPH]))) { result = SL_RESULT_FEATURE_UNSUPPORTED; } else { @@ -128,7 +128,7 @@ static SLresult IDynamicInterfaceManagement_AddInterface(SLDynamicInterfaceManag object_lock_exclusive(thisObject); switch (*interfaceStateP) { - case INTERFACE_UNINITIALIZED: // normal case + case INTERFACE_INITIALIZED: // normal case if (async) { // Asynchronous: mark operation pending and cancellable *interfaceStateP = INTERFACE_ADDING_1; @@ -144,7 +144,7 @@ static SLresult IDynamicInterfaceManagement_AddInterface(SLDynamicInterfaceManag switch (*interfaceStateP) { case INTERFACE_ADDING_1: // normal case INTERFACE_ADDING_1A: // operation aborted while mutex unlocked - *interfaceStateP = INTERFACE_UNINITIALIZED; + *interfaceStateP = INTERFACE_INITIALIZED; break; default: // unexpected // leave state alone @@ -160,24 +160,24 @@ static SLresult IDynamicInterfaceManagement_AddInterface(SLDynamicInterfaceManag // this section runs with mutex unlocked const struct iid_vtable *x = &class__->mInterfaces[index]; size_t offset = x->mOffset; - size_t size = ((SLuint32) (index + 1) == class__->mInterfaceCount ? - class__->mSize : x[1].mOffset) - offset; void *thisItf = (char *) thisObject + offset; - memset(thisItf, 0, size); - // Will never add IObject, so [1] is always defined - ((void **) thisItf)[1] = thisObject; - // paranoid double-check for presence of an initialization hook - VoidHook init = MPH_init_table[MPH].mInit; - if (NULL != init) { - (*init)(thisItf); - ((size_t *) thisItf)[0] ^= ~0; + // call the optional expose hook + BoolHook expose = MPH_init_table[MPH].mExpose; + if ((NULL == expose) || (*expose)(thisItf)) { + result = SL_RESULT_SUCCESS; + } else { + result = SL_RESULT_FEATURE_UNSUPPORTED; } - result = SL_RESULT_SUCCESS; // re-lock mutex to update state object_lock_exclusive(thisObject); assert(INTERFACE_ADDING_2 == *interfaceStateP); - *interfaceStateP = INTERFACE_ADDED; + if (SL_RESULT_SUCCESS == result) { + ((size_t *) thisItf)[0] ^= ~0; + *interfaceStateP = INTERFACE_ADDED; + } else { + *interfaceStateP = INTERFACE_INITIALIZED; + } } // mutex is still locked @@ -231,24 +231,22 @@ static SLresult IDynamicInterfaceManagement_RemoveInterface( thisObject->mGottenMask &= ~(1 << index); object_unlock_exclusive(thisObject); - // The deinitialization is done with mutex unlocked +#if 0 // remove hook is not yet implemented + // The removal is done with mutex unlocked const struct iid_vtable *x = &class__->mInterfaces[index]; size_t offset = x->mOffset; void *thisItf = (char *) thisObject + offset; - VoidHook deinit = MPH_init_table[MPH].mDeinit; - if (NULL != deinit) - (*deinit)(thisItf); -#ifdef USE_DEBUG - size_t size = ((SLuint32) (index + 1) == class__->mInterfaceCount ? - class__->mSize : x[1].mOffset) - offset; - memset(thisItf, 0x55, size); + VoidHook remove = MPH_init_table[MPH].mRemove; + if (NULL != remove) { + (*remove)(thisItf); + } #endif result = SL_RESULT_SUCCESS; // Note that this was previously locked, but then unlocked for the deinit hook object_lock_exclusive(thisObject); assert(INTERFACE_REMOVING == *interfaceStateP); - *interfaceStateP = INTERFACE_UNINITIALIZED; + *interfaceStateP = INTERFACE_INITIALIZED; } // mutex is still locked @@ -305,8 +303,9 @@ static void HandleResume(void *self, int MPH) size_t offset = x->mOffset; void *thisItf = (char *) thisObject + offset; VoidHook resume = MPH_init_table[MPH].mResume; - if (NULL != resume) + if (NULL != resume) { (*resume)(thisItf); + } result = SL_RESULT_SUCCESS; // re-lock mutex to update state @@ -404,8 +403,9 @@ static SLresult IDynamicInterfaceManagement_ResumeInterface(SLDynamicInterfaceMa size_t offset = x->mOffset; void *thisItf = (char *) this + offset; VoidHook resume = MPH_init_table[MPH].mResume; - if (NULL != resume) + if (NULL != resume) { (*resume)(thisItf); + } result = SL_RESULT_SUCCESS; // re-lock mutex to update state diff --git a/opensles/libopensles/IDynamicSource.c b/opensles/libopensles/IDynamicSource.c index ef9fe202..19bf0a4e 100644 --- a/opensles/libopensles/IDynamicSource.c +++ b/opensles/libopensles/IDynamicSource.c @@ -54,5 +54,6 @@ void IDynamicSource_init(void *self) { IDynamicSource *this = (IDynamicSource *) self; this->mItf = &IDynamicSource_Itf; - // mDataSource will be initialized later in CreateAudioPlayer etc. + // mDataSource will be re-initialized later in the containing object constructor + this->mDataSource = NULL; } diff --git a/opensles/libopensles/IEngine.c b/opensles/libopensles/IEngine.c index ed012726..6e0a6f68 100644 --- a/opensles/libopensles/IEngine.c +++ b/opensles/libopensles/IEngine.c @@ -121,13 +121,49 @@ static SLresult IEngine_CreateAudioPlayer(SLEngineItf self, SLObjectItf *pPlayer do { // Initialize private fields not associated with an interface + + // Default data source in case of failure in checkDataSource + this->mDataSource.mLocator.mLocatorType = SL_DATALOCATOR_NULL; + this->mDataSource.mFormat.mFormatType = SL_DATAFORMAT_NULL; + + // Default data sink in case of failure in checkDataSink + this->mDataSink.mLocator.mLocatorType = SL_DATALOCATOR_NULL; + this->mDataSink.mFormat.mFormatType = SL_DATAFORMAT_NULL; + + // Default is no per-channel mute or solo this->mMuteMask = 0; this->mSoloMask = 0; + // Will be set soon for PCM buffer queues, or later by platform-specific code // during Realize or Prefetch this->mNumChannels = 0; this->mSampleRateMilliHz = 0; + // More default values, in case destructor needs to be called early + this->mDirectLevel = 0; +#ifdef USE_OUTPUTMIXEXT + this->mTrack = NULL; + this->mGains[0] = 1.0f; + this->mGains[1] = 1.0f; + this->mDestroyRequested = SL_BOOLEAN_FALSE; +#endif +#ifdef USE_SNDFILE + this->mSndFile.mPathname = NULL; + this->mSndFile.mSNDFILE = NULL; + memset(&this->mSndFile.mSfInfo, 0, sizeof(SF_INFO)); + memset(&this->mSndFile.mMutex, 0, sizeof(pthread_mutex_t)); + this->mSndFile.mEOF = SL_BOOLEAN_FALSE; + this->mSndFile.mWhich = 0; + memset(this->mSndFile.mBuffer, 0, sizeof(this->mSndFile.mBuffer)); +#endif +#ifdef ANDROID + // extra safe initializations of pointers, in case of incomplete construction + this->mpLock = NULL; + this->mAudioTrack = NULL; + // placement new (explicit constructor) + (void) new (&this->mSfPlayer) android::sp(); +#endif + // Check the source and sink parameters against generic constraints, // and make a local copy of all parameters in case other application threads // change memory concurrently. @@ -280,6 +316,14 @@ static SLresult IEngine_CreateAudioRecorder(SLEngineItf self, SLObjectItf *pReco // Initialize fields not associated with any interface + // Default data source in case of failure in checkDataSource + this->mDataSource.mLocator.mLocatorType = SL_DATALOCATOR_NULL; + this->mDataSource.mFormat.mFormatType = SL_DATAFORMAT_NULL; + + // Default data sink in case of failure in checkDataSink + this->mDataSink.mLocator.mLocatorType = SL_DATALOCATOR_NULL; + this->mDataSink.mFormat.mFormatType = SL_DATAFORMAT_NULL; + // These fields are set to real values by // android_audioRecorder_checkSourceSinkSupport. Note that the data sink is // always PCM buffer queue, so we know the channel count and sample rate early. @@ -753,7 +797,7 @@ void IEngine_init(void *self) { IEngine *this = (IEngine *) self; this->mItf = &IEngine_Itf; - // mLossOfControlGlobal is initialized in CreateEngine + // mLossOfControlGlobal is initialized in slCreateEngine #ifdef USE_SDL this->mOutputMix = NULL; #endif @@ -766,8 +810,29 @@ void IEngine_init(void *self) } this->mShutdown = SL_BOOLEAN_FALSE; this->mShutdownAck = SL_BOOLEAN_FALSE; + // mThreadPool is initialized in CEngine_Realize + memset(&this->mThreadPool, 0, sizeof(ThreadPool)); #if defined(ANDROID) && !defined(USE_BACKPORT) this->mEqNumPresets = 0; this->mEqPresetNames = NULL; #endif } + +void IEngine_deinit(void *self) +{ +#if defined(ANDROID) && !defined(USE_BACKPORT) + IEngine *this = (IEngine *) self; + // free equalizer preset names + if (NULL != this->mEqPresetNames) { + for (unsigned i = 0; i < this->mEqNumPresets; ++i) { + if (NULL != this->mEqPresetNames[i]) { + delete[] this->mEqPresetNames[i]; + this->mEqPresetNames[i] = NULL; + } + } + delete[] this->mEqPresetNames; + this->mEqPresetNames = NULL; + } + this->mEqNumPresets = 0; +#endif +} diff --git a/opensles/libopensles/IEnvironmentalReverb.c b/opensles/libopensles/IEnvironmentalReverb.c index b568c2ad..f61add8c 100644 --- a/opensles/libopensles/IEnvironmentalReverb.c +++ b/opensles/libopensles/IEnvironmentalReverb.c @@ -748,12 +748,31 @@ void IEnvironmentalReverb_init(void *self) IEnvironmentalReverb *this = (IEnvironmentalReverb *) self; this->mItf = &IEnvironmentalReverb_Itf; this->mProperties = IEnvironmentalReverb_default; +#if defined(ANDROID) && !defined(USE_BACKPORT) + memset(&this->mEnvironmentalReverbDescriptor, 0, sizeof(effect_descriptor_t)); + // placement new (explicit constructor) + (void) new (&this->mEnvironmentalReverbEffect) android::sp(); +#endif +} +void IEnvironmentalReverb_deinit(void *self) +{ #if defined(ANDROID) && !defined(USE_BACKPORT) + IEnvironmentalReverb *this = (IEnvironmentalReverb *) self; + // explicit destructor + this->mEnvironmentalReverbEffect.~sp(); +#endif +} + +bool IEnvironmentalReverb_Expose(void *self) +{ +#if defined(ANDROID) && !defined(USE_BACKPORT) + IEnvironmentalReverb *this = (IEnvironmentalReverb *) self; if (!android_fx_initEffectDescriptor(SL_IID_ENVIRONMENTALREVERB, &this->mEnvironmentalReverbDescriptor)) { - // PresetReverb init failed SL_LOGE("EnvironmentalReverb initialization failed."); + return false; } #endif + return true; } diff --git a/opensles/libopensles/IEqualizer.c b/opensles/libopensles/IEqualizer.c index 874a4456..2c7fe1b2 100644 --- a/opensles/libopensles/IEqualizer.c +++ b/opensles/libopensles/IEqualizer.c @@ -477,7 +477,7 @@ void IEqualizer_init(void *self) this->mItf = &IEqualizer_Itf; this->mEnabled = SL_BOOLEAN_FALSE; this->mPreset = SL_EQUALIZER_UNDEFINED; -#if (0 < MAX_EQ_BANDS) +#if 0 < MAX_EQ_BANDS unsigned band; for (band = 0; band < MAX_EQ_BANDS; ++band) this->mLevels[band] = 0; @@ -491,15 +491,34 @@ void IEqualizer_init(void *self) #endif this->mBandLevelRangeMin = 0; this->mBandLevelRangeMax = 0; +#if defined(ANDROID) && !defined(USE_BACKPORT) + memset(&this->mEqDescriptor, 0, sizeof(effect_descriptor_t)); + // placement new (explicit constructor) + (void) new (&this->mEqEffect) android::sp(); +#endif +} +void IEqualizer_deinit(void *self) +{ #if defined(ANDROID) && !defined(USE_BACKPORT) + IEqualizer *this = (IEqualizer *) self; + // explicit destructor + this->mEqEffect.~sp(); +#endif +} +bool IEqualizer_Expose(void *self) +{ +#if defined(ANDROID) && !defined(USE_BACKPORT) + IEqualizer *this = (IEqualizer *) self; if (!android_fx_initEffectDescriptor(SL_IID_EQUALIZER, &this->mEqDescriptor)) { - // EQ init failed + SL_LOGE("Equalizer initialization failed"); this->mNumPresets = 0; this->mNumBands = 0; this->mBandLevelRangeMin = 0; this->mBandLevelRangeMax = 0; + return false; } #endif + return true; } diff --git a/opensles/libopensles/IMetadataExtraction.c b/opensles/libopensles/IMetadataExtraction.c index 2af0d9ec..0fabbb59 100644 --- a/opensles/libopensles/IMetadataExtraction.c +++ b/opensles/libopensles/IMetadataExtraction.c @@ -171,4 +171,5 @@ void IMetadataExtraction_init(void *self) this->mValueLangCountry = 0 /*TBD*/; this->mValueEncoding = 0 /*TBD*/; this->mFilterMask = 0 /*TBD*/; + this->mKeyFilter = 0; } diff --git a/opensles/libopensles/IObject.c b/opensles/libopensles/IObject.c index e06e1f5c..e7950a96 100644 --- a/opensles/libopensles/IObject.c +++ b/opensles/libopensles/IObject.c @@ -323,8 +323,8 @@ static SLresult IObject_GetInterface(SLObjectItf self, const SLInterfaceID iid, const ClassTable *class__ = this->mClass; int MPH, index; if ((0 > (MPH = IID_to_MPH(iid))) || - // there must an initialization hook present - (NULL == MPH_init_table[MPH].mInit) || + // no need to check for an initialization hook + // (NULL == MPH_init_table[MPH].mInit) || (0 > (index = class__->mMPH_to_index[MPH]))) { result = SL_RESULT_FEATURE_UNSUPPORTED; } else { @@ -353,7 +353,8 @@ static SLresult IObject_GetInterface(SLObjectItf self, const SLInterfaceID iid, } result = SL_RESULT_SUCCESS; break; - // Can't get interface if uninitialized/suspend(ed,ing)/resuming/adding/removing + // Can't get interface if uninitialized, initialized, suspended, + // suspending, resuming, adding, or removing default: result = SL_RESULT_FEATURE_UNSUPPORTED; break; @@ -550,11 +551,10 @@ void IObject_Destroy(SLObjectItf self) if (NULL != destroy) { (*destroy)(this); } - // Call the deinitializer for each currently exposed interface, + // Call the deinitializer for each currently initialized interface, // whether it is implicit, explicit, optional, or dynamically added. // The deinitializers are called in the reverse order that the // initializers were called, so that IObject_deinit is called last. - unsigned incorrect = 0; unsigned index = class__->mInterfaceCount; const struct iid_vtable *x = &class__->mInterfaces[index]; SLuint8 *interfaceStateP = &this->mInterfaceStates[index]; @@ -567,11 +567,17 @@ void IObject_Destroy(SLObjectItf self) case INTERFACE_EXPOSED: // quiescent states case INTERFACE_ADDED: case INTERFACE_SUSPENDED: + // here is where we would call the remove hook + // fall through + case INTERFACE_INITIALIZED: { + size_t offset = x->mOffset; + void *thisItf = (char *) this + offset; VoidHook deinit = MPH_init_table[x->mMPH].mDeinit; if (NULL != deinit) { - (*deinit)((char *) this + x->mOffset); + (*deinit)(thisItf); } + *interfaceStateP = INTERFACE_UNINITIALIZED; } break; case INTERFACE_ADDING_1: // active states indicate incorrect use of API @@ -582,7 +588,7 @@ void IObject_Destroy(SLObjectItf self) case INTERFACE_RESUMING_2: case INTERFACE_REMOVING: case INTERFACE_SUSPENDING: - ++incorrect; + SL_LOGE("Object::Destroy(%p) while interface %u active", this, index); break; default: assert(SL_BOOLEAN_FALSE); @@ -594,8 +600,6 @@ void IObject_Destroy(SLObjectItf self) memset(this, 0x55, class__->mSize); #endif free(this); - // one or more interfaces was actively changing at time of Destroy - assert(incorrect == 0); SL_LEAVE_INTERFACE_VOID } @@ -719,7 +723,7 @@ void IObject_init(void *self) // mInstanceID // mLossOfControlMask // mEngine - // mInstanceStates + // mInterfaceStates this->mState = SL_OBJECT_STATE_UNREALIZED; this->mGottenMask = 1; // IObject this->mAttributesMask = 0; diff --git a/opensles/libopensles/IPlaybackRate.c b/opensles/libopensles/IPlaybackRate.c index 5b88a022..6e0b7e57 100644 --- a/opensles/libopensles/IPlaybackRate.c +++ b/opensles/libopensles/IPlaybackRate.c @@ -186,7 +186,6 @@ static const struct SLPlaybackRateItf_ IPlaybackRate_Itf = { void IPlaybackRate_init(void *self) { - //SL_LOGV("IPlaybackRate_init called"); IPlaybackRate *this = (IPlaybackRate *) self; this->mItf = &IPlaybackRate_Itf; this->mProperties = SL_RATEPROP_NOPITCHCORAUDIO; @@ -196,7 +195,6 @@ void IPlaybackRate_init(void *self) this->mMaxRate = 2000; this->mStepSize = 0; #ifdef ANDROID - this->mStepSize = 0; // for an AudioPlayer, mCapabilities will be initialized in sles_to_android_audioPlayerCreate #endif // The generic implementation sets no capabilities because the generic diff --git a/opensles/libopensles/IPresetReverb.c b/opensles/libopensles/IPresetReverb.c index 0b701258..aaa57326 100644 --- a/opensles/libopensles/IPresetReverb.c +++ b/opensles/libopensles/IPresetReverb.c @@ -100,11 +100,31 @@ void IPresetReverb_init(void *self) IPresetReverb *this = (IPresetReverb *) self; this->mItf = &IPresetReverb_Itf; this->mPreset = SL_REVERBPRESET_NONE; +#if defined(ANDROID) && !defined(USE_BACKPORT) + memset(&this->mPresetReverbDescriptor, 0, sizeof(effect_descriptor_t)); + // placement new (explicit constructor) + (void) new (&this->mPresetReverbEffect) android::sp(); +#endif +} +void IPresetReverb_deinit(void *self) +{ #if defined(ANDROID) && !defined(USE_BACKPORT) + IPresetReverb *this = (IPresetReverb *) self; + // explicit destructor + this->mPresetReverbEffect.~sp(); +#endif +} + +bool IPresetReverb_Expose(void *self) +{ +#if defined(ANDROID) && !defined(USE_BACKPORT) + IPresetReverb *this = (IPresetReverb *) self; if (!android_fx_initEffectDescriptor(SL_IID_PRESETREVERB, &this->mPresetReverbDescriptor)) { // PresetReverb init failed SL_LOGE("PresetReverb initialization failed."); + return false; } #endif + return true; } diff --git a/opensles/libopensles/IRecord.c b/opensles/libopensles/IRecord.c index b131d901..e48cb617 100644 --- a/opensles/libopensles/IRecord.c +++ b/opensles/libopensles/IRecord.c @@ -289,7 +289,6 @@ static const struct SLRecordItf_ IRecord_Itf = { void IRecord_init(void *self) { - //SL_LOGV("IRecord_init(%p) entering", self); IRecord *this = (IRecord *) self; this->mItf = &IRecord_Itf; this->mState = SL_RECORDSTATE_STOPPED; @@ -300,5 +299,4 @@ void IRecord_init(void *self) this->mCallbackEventsMask = 0; this->mMarkerPosition = 0; this->mPositionUpdatePeriod = 1000; - } diff --git a/opensles/libopensles/IThreadSync.c b/opensles/libopensles/IThreadSync.c index e3269b9d..937e4c6c 100644 --- a/opensles/libopensles/IThreadSync.c +++ b/opensles/libopensles/IThreadSync.c @@ -83,3 +83,11 @@ void IThreadSync_init(void *self) this->mWaiting = 0; memset(&this->mOwner, 0, sizeof(pthread_t)); } + +void IThreadSync_deinit(void *self) +{ + IThreadSync *this = (IThreadSync *) self; + if (this->mInCriticalSection) { + SL_LOGW("ThreadSync::EnterCriticalSection was active at Engine::Destroy"); + } +} diff --git a/opensles/libopensles/IVirtualizer.c b/opensles/libopensles/IVirtualizer.c index 7248dade..440a42a7 100644 --- a/opensles/libopensles/IVirtualizer.c +++ b/opensles/libopensles/IVirtualizer.c @@ -187,11 +187,31 @@ void IVirtualizer_init(void *self) this->mItf = &IVirtualizer_Itf; this->mEnabled = SL_BOOLEAN_FALSE; this->mStrength = 0; +#if defined(ANDROID) && !defined(USE_BACKPORT) + memset(&this->mVirtualizerDescriptor, 0, sizeof(effect_descriptor_t)); + // placement new (explicit constructor) + (void) new (&this->mVirtualizerEffect) android::sp(); +#endif +} +void IVirtualizer_deinit(void *self) +{ #if defined(ANDROID) && !defined(USE_BACKPORT) + IVirtualizer *this = (IVirtualizer *) self; + // explicit destructor + this->mVirtualizerEffect.~sp(); +#endif +} + +bool IVirtualizer_Expose(void *self) +{ +#if defined(ANDROID) && !defined(USE_BACKPORT) + IVirtualizer *this = (IVirtualizer *) self; if (!android_fx_initEffectDescriptor(SL_IID_VIRTUALIZER, &this->mVirtualizerDescriptor)) { // Virtualizer init failed SL_LOGE("Virtualizer initialization failed."); + return false; } #endif + return true; } diff --git a/opensles/libopensles/android_AudioPlayer.cpp b/opensles/libopensles/android_AudioPlayer.cpp index aa2e68c8..67a23e09 100644 --- a/opensles/libopensles/android_AudioPlayer.cpp +++ b/opensles/libopensles/android_AudioPlayer.cpp @@ -18,6 +18,8 @@ #include "utils/RefBase.h" #include "android_prompts.h" +template class android::KeyedVector ; + #define KEY_STREAM_TYPE_PARAMSIZE sizeof(SLint32) //----------------------------------------------------------------------------- @@ -836,7 +838,8 @@ SLresult android_audioPlayer_create( pAudioPlayer->mStreamType = ANDROID_DEFAULT_OUTPUT_STREAM_TYPE; pAudioPlayer->mAudioTrack = NULL; #ifndef USE_BACKPORT - pAudioPlayer->mSfPlayer.clear(); + // no longer needed, as placement new (explicit constructor) already does this + // pAudioPlayer->mSfPlayer.clear(); #endif #ifndef USE_BACKPORT @@ -851,10 +854,7 @@ SLresult android_audioPlayer_create( // initialize interface-specific fields that can be used regardless of whether the interface // is exposed on the AudioPlayer or not - pAudioPlayer->mAndroidEffect.mEffects = - new android::KeyedVector(); - pAudioPlayer->mSeek.mLoopEnabled = SL_BOOLEAN_FALSE; - pAudioPlayer->mPlaybackRate.mRate = 1000; + // (section no longer applicable, as all previous initializations were the same as the defaults) return result; @@ -1067,6 +1067,7 @@ SLresult android_audioPlayer_destroy(CAudioPlayer *pAudioPlayer) { //----------------------------------- // MediaPlayer case MEDIAPLAYER: + // FIXME might no longer be needed since we call explicit destructor if (pAudioPlayer->mSfPlayer != 0) { pAudioPlayer->mSfPlayer.clear(); } @@ -1084,25 +1085,11 @@ SLresult android_audioPlayer_destroy(CAudioPlayer *pAudioPlayer) { pAudioPlayer->mAudioTrack = NULL; } + // FIXME might not be needed pAudioPlayer->mAndroidObjType = INVALID_TYPE; -#ifndef USE_BACKPORT - // FIXME this shouldn't have to be done here, there should be an "interface destroy" hook, - // just like there is an interface init hook, to avoid memory leaks. - pAudioPlayer->mEqualizer.mEqEffect.clear(); - pAudioPlayer->mBassBoost.mBassBoostEffect.clear(); - pAudioPlayer->mVirtualizer.mVirtualizerEffect.clear(); - if (NULL != pAudioPlayer->mAndroidEffect.mEffects) { - if (!pAudioPlayer->mAndroidEffect.mEffects->isEmpty()) { - for (size_t i = 0 ; i < pAudioPlayer->mAndroidEffect.mEffects->size() ; i++) { - delete pAudioPlayer->mAndroidEffect.mEffects->valueAt(i); - } - pAudioPlayer->mAndroidEffect.mEffects->clear(); - } - delete pAudioPlayer->mAndroidEffect.mEffects; - pAudioPlayer->mAndroidEffect.mEffects = NULL; - } -#endif + // explicit destructor + pAudioPlayer->mSfPlayer.~sp(); if (pAudioPlayer->mpLock != NULL) { delete pAudioPlayer->mpLock; diff --git a/opensles/libopensles/android_AudioRecorder.cpp b/opensles/libopensles/android_AudioRecorder.cpp index aa1b4faf..a5c6ceb6 100644 --- a/opensles/libopensles/android_AudioRecorder.cpp +++ b/opensles/libopensles/android_AudioRecorder.cpp @@ -423,8 +423,10 @@ void android_audioRecorder_destroy(CAudioRecorder* ar) { } #ifdef MONITOR_RECORDING - if (NULL != gMonitorFp) { fclose(gMonitorFp); } - gMonitorFp = NULL; + if (NULL != gMonitorFp) { + fclose(gMonitorFp); + gMonitorFp = NULL; + } #endif } diff --git a/opensles/libopensles/android_OutputMix.cpp b/opensles/libopensles/android_OutputMix.cpp index fb082072..58717841 100644 --- a/opensles/libopensles/android_OutputMix.cpp +++ b/opensles/libopensles/android_OutputMix.cpp @@ -20,13 +20,8 @@ SLresult android_outputMix_create(COutputMix *om) { - SLresult result = SL_RESULT_SUCCESS; - SL_LOGV("Create outputMix=%p", om); - - om->mAndroidEffect.mEffects = new android::KeyedVector(); - - return result; + return SL_RESULT_SUCCESS; } @@ -68,27 +63,6 @@ SLresult android_outputMix_realize(COutputMix *om, SLboolean async) { SLresult android_outputMix_destroy(COutputMix *om) { - SLresult result = SL_RESULT_SUCCESS; SL_LOGV("Destroy outputMix=%p", om); - - -#ifndef USE_BACKPORT - // FIXME this shouldn't have to be done here, there should be an "interface destroy" hook, - // just like there is an interface init hook, to avoid memory leaks. - om->mEqualizer.mEqEffect.clear(); - om->mBassBoost.mBassBoostEffect.clear(); - om->mVirtualizer.mVirtualizerEffect.clear(); - om->mEnvironmentalReverb.mEnvironmentalReverbEffect.clear(); - om->mPresetReverb.mPresetReverbEffect.clear(); - if (!om->mAndroidEffect.mEffects->isEmpty()) { - for (size_t i = 0 ; i < om->mAndroidEffect.mEffects->size() ; i++) { - delete om->mAndroidEffect.mEffects->valueAt(i); - } - om->mAndroidEffect.mEffects->clear(); - } - delete om->mAndroidEffect.mEffects; -#endif - - return result; + return SL_RESULT_SUCCESS; } - diff --git a/opensles/libopensles/sles.c b/opensles/libopensles/sles.c index 2f028514..51a15b47 100644 --- a/opensles/libopensles/sles.c +++ b/opensles/libopensles/sles.c @@ -191,7 +191,9 @@ SLresult checkInterfaces(const ClassTable *class__, SLuint32 numInterfaces, class__->mName, i, MPH); return SL_RESULT_FEATURE_UNSUPPORTED; } - // Application said it didn't really need the interface, so ignore + // Application said it didn't really need the interface, so ignore with warning + SL_LOGW("class %s interface %lu requested but unavailable MPH=%d", + class__->mName, i, MPH); continue; } // The requested interface was both found and available, so expose it @@ -370,7 +372,7 @@ static SLresult checkDataLocator(void *pLocator, DataLocator *pDataLocator) SL_OBJECTID_OUTPUTMIX); if (SL_RESULT_SUCCESS != result) { SL_LOGE("locatorType is SL_DATALOCATOR_OUTPUTMIX, but outputMix field %p does not " \ - "refer to an SL_OBJECTID_OUTPUTMIX or is not realized", \ + "refer to an SL_OBJECTID_OUTPUTMIX or the output mix is not realized", \ pDataLocator->mOutputMix.outputMix); pDataLocator->mOutputMix.outputMix = NULL; return result; @@ -834,18 +836,17 @@ void freeDataLocatorFormat(DataLocatorFormat *dlf) extern void I3DCommit_init(void *), I3DDoppler_init(void *), - I3DGrouping_deinit(void *), I3DGrouping_init(void *), I3DLocation_init(void *), I3DMacroscopic_init(void *), I3DSource_init(void *), IAndroidConfiguration_init(void *), + IAndroidEffect_init(void *), IAndroidEffectCapabilities_init(void *), IAndroidEffectSend_init(void *), - IAndroidEffect_init(void *), IAudioDecoderCapabilities_init(void *), - IAudioEncoderCapabilities_init(void *), IAudioEncoder_init(void *), + IAudioEncoderCapabilities_init(void *), IAudioIODeviceCapabilities_init(void *), IBassBoost_init(void *), IBufferQueue_init(void *), @@ -853,8 +854,8 @@ extern void IDynamicInterfaceManagement_init(void *), IDynamicSource_init(void *), IEffectSend_init(void *), - IEngineCapabilities_init(void *), IEngine_init(void *), + IEngineCapabilities_init(void *), IEnvironmentalReverb_init(void *), IEqualizer_init(void *), ILEDArray_init(void *), @@ -866,8 +867,8 @@ extern void IMetadataTraversal_init(void *), IMuteSolo_init(void *), IObject_init(void *), - IOutputMixExt_init(void *), IOutputMix_init(void *), + IOutputMixExt_init(void *), IPitch_init(void *), IPlay_init(void *), IPlaybackRate_init(void *), @@ -883,7 +884,26 @@ extern void IVolume_init(void *); extern void - IObject_deinit(void *); + I3DGrouping_deinit(void *), + IAndroidEffect_deinit(void *), + IAndroidEffectCapabilities_deinit(void *), + IBassBoost_deinit(void *), + IBufferQueue_deinit(void *), + IEngine_deinit(void *), + IEnvironmentalReverb_deinit(void *), + IEqualizer_deinit(void *), + IObject_deinit(void *), + IPresetReverb_deinit(void *), + IThreadSync_deinit(void *), + IVirtualizer_deinit(void *); + +extern bool + IAndroidEffectCapabilities_Expose(void *), + IBassBoost_Expose(void *), + IEnvironmentalReverb_Expose(void *), + IEqualizer_Expose(void *), + IPresetReverb_Expose(void *), + IVirtualizer_Expose(void *); #if !(USE_PROFILES & USE_PROFILES_MUSIC) #define IDynamicSource_init NULL @@ -919,6 +939,7 @@ extern void #define IEngineCapabilities_init NULL #define IOutputMix_init NULL #define IThreadSync_init NULL +#define IThreadSync_deinit NULL #endif #if !(USE_PROFILES & USE_PROFILES_OPTIONAL) @@ -927,10 +948,13 @@ extern void #endif #ifndef ANDROID -#define IAndroidConfiguration_init NULL -#define IAndroidEffect_init NULL -#define IAndroidEffectCapabilities_init NULL -#define IAndroidEffectSend_init NULL +#define IAndroidConfiguration_init NULL +#define IAndroidEffect_init NULL +#define IAndroidEffectCapabilities_init NULL +#define IAndroidEffectSend_init NULL +#define IAndroidEffect_deinit NULL +#define IAndroidEffectCapabilities_deinit NULL +#define IAndroidEffectCapabilities_Expose NULL #endif #ifndef USE_OUTPUTMIXEXT @@ -939,56 +963,59 @@ extern void /*static*/ const struct MPH_init MPH_init_table[MPH_MAX] = { - { /* MPH_3DCOMMIT, */ I3DCommit_init, NULL, NULL }, - { /* MPH_3DDOPPLER, */ I3DDoppler_init, NULL, NULL }, - { /* MPH_3DGROUPING, */ I3DGrouping_init, NULL, I3DGrouping_deinit }, - { /* MPH_3DLOCATION, */ I3DLocation_init, NULL, NULL }, - { /* MPH_3DMACROSCOPIC, */ I3DMacroscopic_init, NULL, NULL }, - { /* MPH_3DSOURCE, */ I3DSource_init, NULL, NULL }, - { /* MPH_AUDIODECODERCAPABILITIES, */ IAudioDecoderCapabilities_init, NULL, NULL }, - { /* MPH_AUDIOENCODER, */ IAudioEncoder_init, NULL, NULL }, - { /* MPH_AUDIOENCODERCAPABILITIES, */ IAudioEncoderCapabilities_init, NULL, NULL }, - { /* MPH_AUDIOIODEVICECAPABILITIES, */ IAudioIODeviceCapabilities_init, NULL, NULL }, - { /* MPH_BASSBOOST, */ IBassBoost_init, NULL, NULL }, - { /* MPH_BUFFERQUEUE, */ IBufferQueue_init, NULL, NULL }, - { /* MPH_DEVICEVOLUME, */ IDeviceVolume_init, NULL, NULL }, - { /* MPH_DYNAMICINTERFACEMANAGEMENT, */ IDynamicInterfaceManagement_init, NULL, NULL }, - { /* MPH_DYNAMICSOURCE, */ IDynamicSource_init, NULL, NULL }, - { /* MPH_EFFECTSEND, */ IEffectSend_init, NULL, NULL }, - { /* MPH_ENGINE, */ IEngine_init, NULL, NULL }, - { /* MPH_ENGINECAPABILITIES, */ IEngineCapabilities_init, NULL, NULL }, - { /* MPH_ENVIRONMENTALREVERB, */ IEnvironmentalReverb_init, NULL, NULL }, - { /* MPH_EQUALIZER, */ IEqualizer_init, NULL, NULL }, - { /* MPH_LED, */ ILEDArray_init, NULL, NULL }, - { /* MPH_METADATAEXTRACTION, */ IMetadataExtraction_init, NULL, NULL }, - { /* MPH_METADATATRAVERSAL, */ IMetadataTraversal_init, NULL, NULL }, - { /* MPH_MIDIMESSAGE, */ IMIDIMessage_init, NULL, NULL }, - { /* MPH_MIDITIME, */ IMIDITime_init, NULL, NULL }, - { /* MPH_MIDITEMPO, */ IMIDITempo_init, NULL, NULL }, - { /* MPH_MIDIMUTESOLO, */ IMIDIMuteSolo_init, NULL, NULL }, - { /* MPH_MUTESOLO, */ IMuteSolo_init, NULL, NULL }, - { /* MPH_NULL, */ NULL, NULL, NULL }, - { /* MPH_OBJECT, */ IObject_init, NULL, IObject_deinit }, - { /* MPH_OUTPUTMIX, */ IOutputMix_init, NULL, NULL }, - { /* MPH_PITCH, */ IPitch_init, NULL, NULL }, - { /* MPH_PLAY, */ IPlay_init, NULL, NULL }, - { /* MPH_PLAYBACKRATE, */ IPlaybackRate_init, NULL, NULL }, - { /* MPH_PREFETCHSTATUS, */ IPrefetchStatus_init, NULL, NULL }, - { /* MPH_PRESETREVERB, */ IPresetReverb_init, NULL, NULL }, - { /* MPH_RATEPITCH, */ IRatePitch_init, NULL, NULL }, - { /* MPH_RECORD, */ IRecord_init, NULL, NULL }, - { /* MPH_SEEK, */ ISeek_init, NULL, NULL }, - { /* MPH_THREADSYNC, */ IThreadSync_init, NULL, NULL }, - { /* MPH_VIBRA, */ IVibra_init, NULL, NULL }, - { /* MPH_VIRTUALIZER, */ IVirtualizer_init, NULL, NULL }, - { /* MPH_VISUALIZATION, */ IVisualization_init, NULL, NULL }, - { /* MPH_VOLUME, */ IVolume_init, NULL, NULL }, - { /* MPH_OUTPUTMIXEXT, */ IOutputMixExt_init, NULL, NULL }, - { /* MPH_ANDROIDEFFECT */ IAndroidEffect_init, NULL, NULL }, - { /* MPH_ANDROIDEFFECTCAPABILITIES */ IAndroidEffectCapabilities_init, NULL, NULL }, - { /* MPH_ANDROIDEFFECTSEND */ IAndroidEffectSend_init, NULL, NULL }, - { /* MPH_ANDROIDCONFIGURATION */ IAndroidConfiguration_init, NULL, NULL }, - { /* MPH_ANDROIDSIMPLEBUFFERQUEUE, */ IBufferQueue_init /* alias */, NULL, NULL } + { /* MPH_3DCOMMIT, */ I3DCommit_init, NULL, NULL, NULL }, + { /* MPH_3DDOPPLER, */ I3DDoppler_init, NULL, NULL, NULL }, + { /* MPH_3DGROUPING, */ I3DGrouping_init, NULL, I3DGrouping_deinit, NULL }, + { /* MPH_3DLOCATION, */ I3DLocation_init, NULL, NULL, NULL }, + { /* MPH_3DMACROSCOPIC, */ I3DMacroscopic_init, NULL, NULL, NULL }, + { /* MPH_3DSOURCE, */ I3DSource_init, NULL, NULL, NULL }, + { /* MPH_AUDIODECODERCAPABILITIES, */ IAudioDecoderCapabilities_init, NULL, NULL, NULL }, + { /* MPH_AUDIOENCODER, */ IAudioEncoder_init, NULL, NULL, NULL }, + { /* MPH_AUDIOENCODERCAPABILITIES, */ IAudioEncoderCapabilities_init, NULL, NULL, NULL }, + { /* MPH_AUDIOIODEVICECAPABILITIES, */ IAudioIODeviceCapabilities_init, NULL, NULL, NULL }, + { /* MPH_BASSBOOST, */ IBassBoost_init, NULL, IBassBoost_deinit, IBassBoost_Expose }, + { /* MPH_BUFFERQUEUE, */ IBufferQueue_init, NULL, IBufferQueue_deinit, NULL }, + { /* MPH_DEVICEVOLUME, */ IDeviceVolume_init, NULL, NULL, NULL }, + { /* MPH_DYNAMICINTERFACEMANAGEMENT, */ IDynamicInterfaceManagement_init, NULL, NULL, NULL }, + { /* MPH_DYNAMICSOURCE, */ IDynamicSource_init, NULL, NULL, NULL }, + { /* MPH_EFFECTSEND, */ IEffectSend_init, NULL, NULL, NULL }, + { /* MPH_ENGINE, */ IEngine_init, NULL, IEngine_deinit, NULL }, + { /* MPH_ENGINECAPABILITIES, */ IEngineCapabilities_init, NULL, NULL, NULL }, + { /* MPH_ENVIRONMENTALREVERB, */ IEnvironmentalReverb_init, NULL, IEnvironmentalReverb_deinit, + IEnvironmentalReverb_Expose }, + { /* MPH_EQUALIZER, */ IEqualizer_init, NULL, IEqualizer_deinit, IEqualizer_Expose }, + { /* MPH_LED, */ ILEDArray_init, NULL, NULL, NULL }, + { /* MPH_METADATAEXTRACTION, */ IMetadataExtraction_init, NULL, NULL, NULL }, + { /* MPH_METADATATRAVERSAL, */ IMetadataTraversal_init, NULL, NULL, NULL }, + { /* MPH_MIDIMESSAGE, */ IMIDIMessage_init, NULL, NULL, NULL }, + { /* MPH_MIDITIME, */ IMIDITime_init, NULL, NULL, NULL }, + { /* MPH_MIDITEMPO, */ IMIDITempo_init, NULL, NULL, NULL }, + { /* MPH_MIDIMUTESOLO, */ IMIDIMuteSolo_init, NULL, NULL, NULL }, + { /* MPH_MUTESOLO, */ IMuteSolo_init, NULL, NULL, NULL }, + { /* MPH_NULL, */ NULL, NULL, NULL, NULL }, + { /* MPH_OBJECT, */ IObject_init, NULL, IObject_deinit, NULL }, + { /* MPH_OUTPUTMIX, */ IOutputMix_init, NULL, NULL, NULL }, + { /* MPH_PITCH, */ IPitch_init, NULL, NULL, NULL }, + { /* MPH_PLAY, */ IPlay_init, NULL, NULL, NULL }, + { /* MPH_PLAYBACKRATE, */ IPlaybackRate_init, NULL, NULL, NULL }, + { /* MPH_PREFETCHSTATUS, */ IPrefetchStatus_init, NULL, NULL, NULL }, + { /* MPH_PRESETREVERB, */ IPresetReverb_init, NULL, IPresetReverb_deinit, + IPresetReverb_Expose }, + { /* MPH_RATEPITCH, */ IRatePitch_init, NULL, NULL, NULL }, + { /* MPH_RECORD, */ IRecord_init, NULL, NULL, NULL }, + { /* MPH_SEEK, */ ISeek_init, NULL, NULL, NULL }, + { /* MPH_THREADSYNC, */ IThreadSync_init, NULL, IThreadSync_deinit, NULL }, + { /* MPH_VIBRA, */ IVibra_init, NULL, NULL, NULL }, + { /* MPH_VIRTUALIZER, */ IVirtualizer_init, NULL, IVirtualizer_deinit, IVirtualizer_Expose }, + { /* MPH_VISUALIZATION, */ IVisualization_init, NULL, NULL, NULL }, + { /* MPH_VOLUME, */ IVolume_init, NULL, NULL, NULL }, + { /* MPH_OUTPUTMIXEXT, */ IOutputMixExt_init, NULL, NULL, NULL }, + { /* MPH_ANDROIDEFFECT */ IAndroidEffect_init, NULL, IAndroidEffect_deinit, NULL }, + { /* MPH_ANDROIDEFFECTCAPABILITIES */ IAndroidEffectCapabilities_init, NULL, + IAndroidEffectCapabilities_deinit, IAndroidEffectCapabilities_Expose }, + { /* MPH_ANDROIDEFFECTSEND */ IAndroidEffectSend_init, NULL, NULL, NULL }, + { /* MPH_ANDROIDCONFIGURATION */ IAndroidConfiguration_init, NULL, NULL, NULL }, + { /* MPH_ANDROIDSIMPLEBUFFERQUEUE, */ IBufferQueue_init /* alias */, NULL, NULL, NULL } }; @@ -1000,6 +1027,7 @@ IObject *construct(const ClassTable *class__, unsigned exposedMask, SLEngineItf // Do not change this to malloc; we depend on the object being memset to zero this = (IObject *) calloc(1, class__->mSize); if (NULL != this) { + SL_LOGV("construct %s at %p", class__->mName, this); unsigned lossOfControlMask = 0; // a NULL engine means we are constructing the engine IEngine *thisEngine = (IEngine *) engine; @@ -1030,22 +1058,27 @@ IObject *construct(const ClassTable *class__, unsigned exposedMask, SLEngineItf SLuint32 index; for (index = 0; index < class__->mInterfaceCount; ++index, ++x, exposedMask >>= 1) { SLuint8 state; - if (exposedMask & 1) { + // initialize all interfaces with init hooks, even if not exposed + const struct MPH_init *mi = &MPH_init_table[x->mMPH]; + VoidHook init = mi->mInit; + if (NULL != init) { void *self = (char *) this + x->mOffset; // IObject does not have an mThis, so [1] is not always defined if (index) { ((IObject **) self)[1] = this; } - VoidHook init = MPH_init_table[x->mMPH].mInit; - // paranoid double-check for presence of an initialization hook - if (NULL != init) { - (*init)(self); - } + // call the initialization hook + (*init)(self); // IObject does not require a call to GetInterface if (index) { ((size_t *) self)[0] ^= ~0; } - state = INTERFACE_EXPOSED; + // if interface is exposed, also call the optional expose hook + BoolHook expose; + state = (exposedMask & 1) && ((NULL == (expose = mi->mExpose)) || (*expose)(self)) ? + INTERFACE_EXPOSED : INTERFACE_INITIALIZED; + // FIXME log or report to application if an expose hook on a + // required explicit interface fails at creation time } else { state = INTERFACE_UNINITIALIZED; } @@ -1131,9 +1164,13 @@ SLresult SLAPIENTRY slCreateEngine(SLObjectItf *pEngine, SLuint32 numOptions, break; } + // initialize fields not associated with an interface + memset(&this->mSyncThread, 0, sizeof(pthread_t)); + // initialize fields related to an interface this->mObject.mLossOfControlMask = lossOfControlGlobal ? ~0 : 0; this->mEngine.mLossOfControlGlobal = lossOfControlGlobal; this->mEngineCapabilities.mThreadSafe = threadSafe; + // FIXME publish the engine here *pEngine = &this->mObject.mItf; } while(0); diff --git a/opensles/libopensles/sles_allinclusive.h b/opensles/libopensles/sles_allinclusive.h index f361f742..b428df3b 100644 --- a/opensles/libopensles/sles_allinclusive.h +++ b/opensles/libopensles/sles_allinclusive.h @@ -110,7 +110,7 @@ typedef struct COutputMix_struct COutputMix; // Hook functions typedef void (*VoidHook)(void *self); -typedef SLresult (*StatusHook)(void *self); +//typedef SLresult (*ResultHook)(void *self); typedef SLresult (*AsyncHook)(void *self, SLboolean async); typedef bool (*BoolHook)(void *self); @@ -171,18 +171,19 @@ typedef bool (*BoolHook)(void *self); // Describes how an interface is related to a given object -#define INTERFACE_UNINITIALIZED 1 ///< /not requested at object creation time -#define INTERFACE_EXPOSED 2 ///< /requested at object creation time -#define INTERFACE_ADDING_1 3 ///< /part 1 of asynchronous AddInterface, pending -#define INTERFACE_ADDING_2 4 ///< /synchronous AddInterface, or part 2 of asynchronous -#define INTERFACE_ADDED 5 ///< /AddInterface has completed -#define INTERFACE_REMOVING 6 ///< /unlocked phase of (synchronous) RemoveInterface -#define INTERFACE_SUSPENDING 7 ///< /suspend in progress -#define INTERFACE_SUSPENDED 8 ///< /suspend has completed -#define INTERFACE_RESUMING_1 9 ///< /part 1 of asynchronous ResumeInterface, pending -#define INTERFACE_RESUMING_2 10 ///< /synchronous ResumeInterface, or part 2 of asynchronous -#define INTERFACE_ADDING_1A 11 ///< /part 1 of asynchronous AddInterface, aborted -#define INTERFACE_RESUMING_1A 12 ///< /part 1 of asynchronous ResumeInterface, aborted +#define INTERFACE_UNINITIALIZED 0 ///< not available +#define INTERFACE_INITIALIZED 1 ///< not requested at object creation time +#define INTERFACE_EXPOSED 2 ///< requested at object creation time +#define INTERFACE_ADDING_1 3 ///< part 1 of asynchronous AddInterface, pending +#define INTERFACE_ADDING_2 4 ///< synchronous AddInterface, or part 2 of asynchronous +#define INTERFACE_ADDED 5 ///< AddInterface has completed +#define INTERFACE_REMOVING 6 ///< unlocked phase of (synchronous) RemoveInterface +#define INTERFACE_SUSPENDING 7 ///< suspend in progress +#define INTERFACE_SUSPENDED 8 ///< suspend has completed +#define INTERFACE_RESUMING_1 9 ///< part 1 of asynchronous ResumeInterface, pending +#define INTERFACE_RESUMING_2 10 ///< synchronous ResumeInterface, or part 2 of asynchronous +#define INTERFACE_ADDING_1A 11 ///< part 1 of asynchronous AddInterface, aborted +#define INTERFACE_RESUMING_1A 12 ///< part 1 of asynchronous ResumeInterface, aborted // Maps an interface ID to its offset within the class that exposes it @@ -491,7 +492,7 @@ typedef struct BufferQueue_interface { BufferHeader mTypical[BUFFER_HEADER_TYPICAL+1]; } IBufferQueue; -#define MAX_DEVICE 2 +#define MAX_DEVICE 2 // hard-coded array size for default in/out typedef struct { const struct SLDeviceVolumeItf_ *mItf; @@ -590,12 +591,16 @@ typedef struct { IObject *mThis; SLboolean mEnabled; SLuint16 mPreset; +#if 0 < MAX_EQ_BANDS SLmillibel mLevels[MAX_EQ_BANDS]; +#endif // const to end of struct SLuint16 mNumPresets; SLuint16 mNumBands; +#if !defined(ANDROID) || defined(USE_BACKPORT) const struct EqualizerBand *mBands; const struct EqualizerPreset *mPresets; +#endif SLmillibel mBandLevelRangeMin; SLmillibel mBandLevelRangeMax; #if defined(ANDROID) && !defined(USE_BACKPORT) @@ -819,7 +824,6 @@ typedef struct { #endif } IVirtualizer; - typedef struct { const struct SLVisualizationItf_ *mItf; IObject *mThis; @@ -849,6 +853,7 @@ typedef struct /*Volume_interface*/ { I3DDoppler m3DDoppler; I3DSource m3DSource; I3DMacroscopic m3DMacroscopic; + // remaining are per-instance private fields not associated with an interface unsigned mMemberMask; // set of member objects } /*C3DGroup*/; @@ -948,7 +953,7 @@ enum AndroidObject_state { IPlaybackRate mPlaybackRate; IVirtualizer mVirtualizer; IVisualization mVisualization; - // rest of fields are not related to the interfaces + // remaining are per-instance private fields not associated with an interface DataLocatorFormat mDataSource; DataLocatorFormat mDataSink; // cached data for this instance @@ -1023,7 +1028,7 @@ enum AndroidObject_state { IBufferQueue mBufferQueue; IAndroidConfiguration mAndroidConfiguration; #endif - // rest of fields are not related to the interfaces + // remaining are per-instance private fields not associated with an interface DataLocatorFormat mDataSource; DataLocatorFormat mDataSink; // cached data for this instance @@ -1060,7 +1065,7 @@ typedef struct { #endif // optional interfaces IDeviceVolume mDeviceVolume; - // rest of fields are not related to the interfaces + // remaining are per-instance private fields not associated with an interface pthread_t mSyncThread; } CEngine; @@ -1071,6 +1076,7 @@ typedef struct { SLuint8 mInterfaceStates2[INTERFACES_LEDDevice - INTERFACES_Default]; IDynamicInterfaceManagement mDynamicInterfaceManagement; ILEDArray mLEDArray; + // remaining are per-instance private fields not associated with an interface SLuint32 mDeviceID; } CLEDDevice; @@ -1082,6 +1088,7 @@ typedef struct { IDynamicInterfaceManagement mDynamicInterfaceManagement; I3DDoppler m3DDoppler; I3DLocation m3DLocation; + // remaining are per-instance private fields not associated with an interface } CListener; typedef struct { @@ -1094,6 +1101,7 @@ typedef struct { IDynamicSource mDynamicSource; IMetadataExtraction mMetadataExtraction; IMetadataTraversal mMetadataTraversal; + // remaining are per-instance private fields not associated with an interface } CMetadataExtractor; typedef struct { @@ -1131,6 +1139,7 @@ typedef struct { IPlaybackRate mPlaybackRate; IVirtualizer mVirtualizer; IVisualization mVisualization; + // remaining are per-instance private fields not associated with an interface } CMidiPlayer; /*typedef*/ struct COutputMix_struct { @@ -1158,7 +1167,7 @@ typedef struct { #ifdef ANDROID IAndroidEffect mAndroidEffect; #endif - // implementation-specific data for this instance + // remaining are per-instance private fields not associated with an interface } /*COutputMix*/; typedef struct { @@ -1168,15 +1177,18 @@ typedef struct { SLuint8 mInterfaceStates2[INTERFACES_VibraDevice - INTERFACES_Default]; IDynamicInterfaceManagement mDynamicInterfaceManagement; IVibra mVibra; - // + // remaining are per-instance private fields not associated with an interface SLuint32 mDeviceID; } CVibraDevice; struct MPH_init { - // unsigned char mMPH; - VoidHook mInit; - VoidHook mResume; - VoidHook mDeinit; + VoidHook mInit; // called first to initialize the interface, right after object is allocated + // Each interface is initialized regardless whether it is exposed to application. + VoidHook mResume; // called to resume interface after suspension, not currently used + VoidHook mDeinit; // called last when object is about to be destroyed + BoolHook mExpose; // called after initialization, only if interface is exposed to application + // will need a remove hook after expose: VoidHook mRemove + // will need a suspend hook when suspend is implemented }; extern /*static*/ int IID_to_MPH(const SLInterfaceID iid); @@ -1337,7 +1349,6 @@ extern SLresult IBufferQueue_Enqueue(SLBufferQueueItf self, const void *pBuffer, extern SLresult IBufferQueue_Clear(SLBufferQueueItf self); extern SLresult IBufferQueue_RegisterCallback(SLBufferQueueItf self, slBufferQueueCallback callback, void *pContext); -extern void IBufferQueue_Destroy(IBufferQueue *this); extern bool IsInterfaceInitialized(IObject *this, unsigned MPH); extern SLresult AcquireStrongRef(IObject *object, SLuint32 expectedObjectID); -- 2.11.0