/*
* 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;
}