| /* |
| * Copyright (C) 2010 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /* Initial global entry points */ |
| |
| #include "sles_allinclusive.h" |
| |
| #ifdef ANDROID |
| #include <media/stagefright/DataSource.h> |
| #include <binder/ProcessState.h> |
| #endif |
| |
| /** \brief Internal code shared by slCreateEngine and xaCreateEngine */ |
| |
| LI_API SLresult liCreateEngine(SLObjectItf *pEngine, SLuint32 numOptions, |
| const SLEngineOption *pEngineOptions, SLuint32 numInterfaces, |
| const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired, |
| const ClassTable *pCEngine_class) |
| { |
| SLresult result; |
| |
| int ok; |
| ok = pthread_mutex_lock(&theOneTrueMutex); |
| assert(0 == ok); |
| bool needToUnlockTheOneTrueMutex = true; |
| |
| do { |
| |
| if (NULL == pEngine) { |
| result = SL_RESULT_PARAMETER_INVALID; |
| break; |
| } |
| *pEngine = NULL; |
| |
| if ((0 < numOptions) && (NULL == pEngineOptions)) { |
| SL_LOGE("numOptions=%u and pEngineOptions=NULL", numOptions); |
| result = SL_RESULT_PARAMETER_INVALID; |
| break; |
| } |
| |
| // default values |
| SLboolean threadSafe = SL_BOOLEAN_TRUE; |
| SLboolean lossOfControlGlobal = SL_BOOLEAN_FALSE; |
| |
| // process engine options |
| SLuint32 i; |
| const SLEngineOption *option = pEngineOptions; |
| result = SL_RESULT_SUCCESS; |
| for (i = 0; i < numOptions; ++i, ++option) { |
| switch (option->feature) { |
| case SL_ENGINEOPTION_THREADSAFE: |
| threadSafe = SL_BOOLEAN_FALSE != (SLboolean) option->data; // normalize |
| break; |
| case SL_ENGINEOPTION_LOSSOFCONTROL: |
| lossOfControlGlobal = SL_BOOLEAN_FALSE != (SLboolean) option->data; // normalize |
| break; |
| default: |
| SL_LOGE("unknown engine option: feature=%u data=%u", |
| option->feature, option->data); |
| result = SL_RESULT_PARAMETER_INVALID; |
| break; |
| } |
| } |
| if (SL_RESULT_SUCCESS != result) { |
| break; |
| } |
| |
| unsigned exposedMask; |
| assert(NULL != pCEngine_class); |
| result = checkInterfaces(pCEngine_class, numInterfaces, |
| pInterfaceIds, pInterfaceRequired, &exposedMask, NULL); |
| if (SL_RESULT_SUCCESS != result) { |
| break; |
| } |
| |
| // if an engine already exists, then increment its ref count |
| CEngine *thiz = theOneTrueEngine; |
| if (NULL != thiz) { |
| assert(0 < theOneTrueRefCount); |
| ++theOneTrueRefCount; |
| |
| // In order to update the engine object, we need to lock it, |
| // but that would violate the lock order and potentially deadlock. |
| // So we unlock now and note that it should not be unlocked later. |
| ok = pthread_mutex_unlock(&theOneTrueMutex); |
| assert(0 == ok); |
| needToUnlockTheOneTrueMutex = false; |
| object_lock_exclusive(&thiz->mObject); |
| |
| // now expose additional interfaces not requested by the earlier engine create |
| const struct iid_vtable *x = pCEngine_class->mInterfaces; |
| SLuint8 *interfaceStateP = thiz->mObject.mInterfaceStates; |
| SLuint32 index; |
| for (index = 0; index < pCEngine_class->mInterfaceCount; ++index, ++x, |
| exposedMask >>= 1, ++interfaceStateP) { |
| switch (*interfaceStateP) { |
| case INTERFACE_EXPOSED: // previously exposed |
| break; |
| case INTERFACE_INITIALIZED: // not exposed during the earlier create |
| if (exposedMask & 1) { |
| const struct MPH_init *mi = &MPH_init_table[x->mMPH]; |
| BoolHook expose = mi->mExpose; |
| if ((NULL == expose) || (*expose)((char *) thiz + x->mOffset)) { |
| *interfaceStateP = INTERFACE_EXPOSED; |
| } |
| // FIXME log or report to application that expose hook failed |
| } |
| break; |
| case INTERFACE_UNINITIALIZED: // no init hook |
| break; |
| default: // impossible |
| assert(false); |
| break; |
| } |
| } |
| object_unlock_exclusive(&thiz->mObject); |
| // return the shared engine object |
| *pEngine = &thiz->mObject.mItf; |
| break; |
| } |
| |
| // here when creating the first engine reference |
| assert(0 == theOneTrueRefCount); |
| |
| #ifdef ANDROID |
| android::ProcessState::self()->startThreadPool(); |
| android::DataSource::RegisterDefaultSniffers(); |
| #endif |
| |
| thiz = (CEngine *) construct(pCEngine_class, exposedMask, NULL); |
| if (NULL == thiz) { |
| result = SL_RESULT_MEMORY_FAILURE; |
| break; |
| } |
| |
| // initialize fields not associated with an interface |
| // mThreadPool is initialized in CEngine_Realize |
| memset(&thiz->mThreadPool, 0, sizeof(ThreadPool)); |
| memset(&thiz->mSyncThread, 0, sizeof(pthread_t)); |
| #if defined(ANDROID) |
| thiz->mEqNumPresets = 0; |
| thiz->mEqPresetNames = NULL; |
| #endif |
| // initialize fields related to an interface |
| thiz->mObject.mLossOfControlMask = lossOfControlGlobal ? ~0 : 0; |
| thiz->mEngine.mLossOfControlGlobal = lossOfControlGlobal; |
| thiz->mEngineCapabilities.mThreadSafe = threadSafe; |
| IObject_Publish(&thiz->mObject); |
| theOneTrueEngine = thiz; |
| theOneTrueRefCount = 1; |
| // return the new engine object |
| *pEngine = &thiz->mObject.mItf; |
| |
| } while(0); |
| |
| if (needToUnlockTheOneTrueMutex) { |
| ok = pthread_mutex_unlock(&theOneTrueMutex); |
| assert(0 == ok); |
| } |
| |
| return result; |
| } |
| |
| |
| /** Internal function for slQuerySupportedEngineInterfaces and xaQuerySupportedEngineInterfaces */ |
| |
| LI_API SLresult liQueryNumSupportedInterfaces(SLuint32 *pNumSupportedInterfaces, |
| const ClassTable *clazz) |
| { |
| SLresult result; |
| if (NULL == pNumSupportedInterfaces) { |
| result = SL_RESULT_PARAMETER_INVALID; |
| } else { |
| assert(NULL != clazz); |
| SLuint32 count = 0; |
| SLuint32 i; |
| for (i = 0; i < clazz->mInterfaceCount; ++i) { |
| switch (clazz->mInterfaces[i].mInterface) { |
| case INTERFACE_IMPLICIT: |
| case INTERFACE_IMPLICIT_PREREALIZE: |
| case INTERFACE_EXPLICIT: |
| case INTERFACE_EXPLICIT_PREREALIZE: |
| case INTERFACE_DYNAMIC: |
| ++count; |
| break; |
| case INTERFACE_UNAVAILABLE: |
| break; |
| default: |
| assert(false); |
| break; |
| } |
| } |
| *pNumSupportedInterfaces = count; |
| result = SL_RESULT_SUCCESS; |
| } |
| return result; |
| } |
| |
| |
| /** Internal function for slQuerySupportedEngineInterfaces and xaQuerySupportedEngineInterfaces */ |
| |
| LI_API SLresult liQuerySupportedInterfaces(SLuint32 index, SLInterfaceID *pInterfaceId, |
| const ClassTable *clazz) |
| { |
| SLresult result; |
| if (NULL == pInterfaceId) { |
| result = SL_RESULT_PARAMETER_INVALID; |
| } else { |
| *pInterfaceId = NULL; |
| assert(NULL != clazz); |
| result = SL_RESULT_PARAMETER_INVALID; // will be reset later |
| SLuint32 i; |
| for (i = 0; i < clazz->mInterfaceCount; ++i) { |
| switch (clazz->mInterfaces[i].mInterface) { |
| case INTERFACE_IMPLICIT: |
| case INTERFACE_IMPLICIT_PREREALIZE: |
| case INTERFACE_EXPLICIT: |
| case INTERFACE_EXPLICIT_PREREALIZE: |
| case INTERFACE_DYNAMIC: |
| break; |
| case INTERFACE_UNAVAILABLE: |
| continue; |
| default: |
| assert(false); |
| break; |
| } |
| if (index == 0) { |
| *pInterfaceId = &SL_IID_array[clazz->mInterfaces[i].mMPH]; |
| result = SL_RESULT_SUCCESS; |
| break; |
| } |
| --index; |
| } |
| } |
| return result; |
| } |