2012-07-26 15:30:09 +08:00
|
|
|
#include "OpenSLEngine.h"
|
|
|
|
|
|
|
|
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,"OPENSL_ENGINE.CPP", __VA_ARGS__)
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
|
|
|
|
OpenSLEngine::OpenSLEngine()
|
|
|
|
:m_musicVolume(0),
|
|
|
|
m_effectVolume(0)
|
|
|
|
{}
|
|
|
|
|
|
|
|
OpenSLEngine::~OpenSLEngine()
|
|
|
|
{
|
|
|
|
closeEngine();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**********************************************************************************
|
|
|
|
* jni
|
|
|
|
**********************************************************************************/
|
2012-10-16 16:20:41 +08:00
|
|
|
#define CLASS_NAME "org/cocos2dx/lib/Cocos2dxHelper"
|
2012-07-26 15:30:09 +08:00
|
|
|
|
|
|
|
typedef struct JniMethodInfo_
|
|
|
|
{
|
|
|
|
JNIEnv * env;
|
|
|
|
jclass classID;
|
|
|
|
jmethodID methodID;
|
|
|
|
} JniMethodInfo;
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
static JNIEnv* getJNIEnv(void)
|
|
|
|
{
|
|
|
|
|
|
|
|
JavaVM* jvm = cocos2d::JniHelper::getJavaVM();
|
|
|
|
if (NULL == jvm) {
|
|
|
|
LOGD("Failed to get JNIEnv. JniHelper::getJavaVM() is NULL");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
JNIEnv *env = NULL;
|
|
|
|
// get jni environment
|
|
|
|
jint ret = jvm->GetEnv((void**)&env, JNI_VERSION_1_4);
|
|
|
|
|
|
|
|
switch (ret) {
|
|
|
|
case JNI_OK :
|
|
|
|
// Success!
|
|
|
|
return env;
|
|
|
|
|
|
|
|
case JNI_EDETACHED :
|
|
|
|
// Thread not attached
|
|
|
|
|
|
|
|
// TODO : If calling AttachCurrentThread() on a native thread
|
|
|
|
// must call DetachCurrentThread() in future.
|
|
|
|
// see: http://developer.android.com/guide/practices/design/jni.html
|
|
|
|
|
|
|
|
if (jvm->AttachCurrentThread(&env, NULL) < 0)
|
|
|
|
{
|
|
|
|
LOGD("Failed to get the environment using AttachCurrentThread()");
|
|
|
|
return NULL;
|
|
|
|
} else {
|
|
|
|
// Success : Attached and obtained JNIEnv!
|
|
|
|
return env;
|
|
|
|
}
|
|
|
|
|
|
|
|
case JNI_EVERSION :
|
|
|
|
// Cannot recover from this error
|
|
|
|
LOGD("JNI interface version 1.4 not supported");
|
|
|
|
default :
|
|
|
|
LOGD("Failed to get the environment using GetEnv()");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static jclass getClassID(JNIEnv *pEnv)
|
|
|
|
{
|
|
|
|
jclass ret = pEnv->FindClass(CLASS_NAME);
|
|
|
|
if (! ret)
|
|
|
|
{
|
|
|
|
LOGD("Failed to find class of %s", CLASS_NAME);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool getStaticMethodInfo(JniMethodInfo &methodinfo, const char *methodName, const char *paramCode)
|
|
|
|
{
|
|
|
|
jmethodID methodID = 0;
|
|
|
|
JNIEnv *pEnv = 0;
|
|
|
|
bool bRet = false;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
pEnv = getJNIEnv();
|
|
|
|
if (! pEnv)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
jclass classID = getClassID(pEnv);
|
|
|
|
|
|
|
|
methodID = pEnv->GetStaticMethodID(classID, methodName, paramCode);
|
|
|
|
if (! methodID)
|
|
|
|
{
|
|
|
|
LOGD("Failed to find static method id of %s", methodName);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
methodinfo.classID = classID;
|
|
|
|
methodinfo.env = pEnv;
|
|
|
|
methodinfo.methodID = methodID;
|
|
|
|
|
|
|
|
bRet = true;
|
|
|
|
} while (0);
|
|
|
|
|
|
|
|
return bRet;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/*********************************************************************************
|
|
|
|
* helper
|
|
|
|
********************************************************************************/
|
2012-08-02 14:28:40 +08:00
|
|
|
#define PLAYSTATE_UNKNOWN 0
|
2012-07-26 15:30:09 +08:00
|
|
|
#define FILE_NOT_FOUND -1
|
2012-08-02 14:28:40 +08:00
|
|
|
|
2012-07-26 15:30:09 +08:00
|
|
|
#define ASSET_MANAGER_GETTER "getAssetManager"
|
2012-08-20 12:49:59 +08:00
|
|
|
#define LIBANDROID "libandroid.so"
|
2012-07-26 15:30:09 +08:00
|
|
|
|
2012-08-02 14:28:40 +08:00
|
|
|
#define MIN_VOLUME_MILLIBEL -4000
|
|
|
|
#define MAX_VOLUME_MILLIBEL 0
|
|
|
|
#define RANGE_VOLUME_MILLIBEL 4000
|
|
|
|
|
2012-07-26 15:30:09 +08:00
|
|
|
struct AudioPlayer
|
|
|
|
{
|
|
|
|
SLDataSource audioSrc;
|
|
|
|
SLObjectItf fdPlayerObject;
|
|
|
|
SLPlayItf fdPlayerPlay;
|
|
|
|
SLSeekItf fdPlayerSeek;
|
|
|
|
SLVolumeItf fdPlayerVolume;
|
|
|
|
} musicPlayer; /* for background music */
|
|
|
|
|
2012-08-02 14:28:40 +08:00
|
|
|
typedef map<unsigned int, vector<AudioPlayer*>* > EffectList;
|
|
|
|
typedef pair<unsigned int, vector<AudioPlayer*>* > Effect;
|
2012-07-26 15:30:09 +08:00
|
|
|
|
2012-08-20 12:49:59 +08:00
|
|
|
void* s_pAndroidHandle = NULL;
|
|
|
|
void* s_pOpenSLESHandle = NULL;
|
2012-08-17 09:51:49 +08:00
|
|
|
|
2012-07-26 15:30:09 +08:00
|
|
|
static EffectList& sharedList()
|
|
|
|
{
|
|
|
|
static EffectList s_List;
|
|
|
|
return s_List;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int _Hash(const char *key)
|
|
|
|
{
|
|
|
|
unsigned int len = strlen(key);
|
|
|
|
const char *end=key+len;
|
|
|
|
unsigned int hash;
|
|
|
|
|
|
|
|
for (hash = 0; key < end; key++)
|
|
|
|
{
|
|
|
|
hash *= 16777619;
|
|
|
|
hash ^= (unsigned int) (unsigned char) toupper(*key);
|
|
|
|
}
|
|
|
|
return (hash);
|
|
|
|
}
|
|
|
|
|
2012-08-17 09:51:49 +08:00
|
|
|
SLInterfaceID getInterfaceID(const char *value)
|
|
|
|
{
|
|
|
|
// clear the error stack
|
|
|
|
dlerror();
|
2012-08-20 12:49:59 +08:00
|
|
|
SLInterfaceID* IID = (SLInterfaceID*)dlsym(s_pOpenSLESHandle, value);
|
2012-08-17 09:51:49 +08:00
|
|
|
const char* errorInfo = dlerror();
|
|
|
|
if (errorInfo)
|
|
|
|
{
|
|
|
|
LOGD("Get interface id: %s from OpenSL failed", errorInfo);
|
|
|
|
IID = NULL;
|
|
|
|
}
|
|
|
|
return *IID;
|
|
|
|
}
|
|
|
|
|
|
|
|
void* getFuncPtr(const char *value)
|
|
|
|
{
|
|
|
|
// clear the error stack
|
|
|
|
dlerror();
|
2012-08-20 12:49:59 +08:00
|
|
|
void* funcPtr = dlsym(s_pOpenSLESHandle, value);
|
2012-08-17 09:51:49 +08:00
|
|
|
const char* errorInfo = dlerror();
|
|
|
|
if (errorInfo)
|
|
|
|
{
|
|
|
|
LOGD("Get function from OpenSL failed: %s", errorInfo);
|
|
|
|
funcPtr = NULL;
|
|
|
|
}
|
|
|
|
return funcPtr;
|
|
|
|
}
|
|
|
|
|
2012-08-02 14:28:40 +08:00
|
|
|
int getFileDescriptor(const char * filename, off_t & start, off_t & length)
|
2012-07-26 15:30:09 +08:00
|
|
|
{
|
|
|
|
JniMethodInfo methodInfo;
|
|
|
|
if (! getStaticMethodInfo(methodInfo, ASSET_MANAGER_GETTER, "()Landroid/content/res/AssetManager;"))
|
|
|
|
{
|
2012-08-13 17:14:33 +08:00
|
|
|
methodInfo.env->DeleteLocalRef(methodInfo.classID);
|
2012-07-26 15:30:09 +08:00
|
|
|
return FILE_NOT_FOUND;
|
|
|
|
}
|
|
|
|
jobject assetManager = methodInfo.env->CallStaticObjectMethod(methodInfo.classID, methodInfo.methodID);
|
|
|
|
methodInfo.env->DeleteLocalRef(methodInfo.classID);
|
|
|
|
|
2012-08-20 12:49:59 +08:00
|
|
|
AAssetManager* (*AAssetManager_fromJava)(JNIEnv* env, jobject assetManager);
|
|
|
|
AAssetManager_fromJava = (AAssetManager* (*)(JNIEnv* env, jobject assetManager))
|
|
|
|
dlsym(s_pAndroidHandle, "AAssetManager_fromJava");
|
2012-07-26 15:30:09 +08:00
|
|
|
AAssetManager* mgr = AAssetManager_fromJava(methodInfo.env, assetManager);
|
|
|
|
assert(NULL != mgr);
|
|
|
|
|
2012-08-20 12:49:59 +08:00
|
|
|
AAsset* (*AAssetManager_open)(AAssetManager* mgr, const char* filename, int mode);
|
|
|
|
AAssetManager_open = (AAsset* (*)(AAssetManager* mgr, const char* filename, int mode))
|
|
|
|
dlsym(s_pAndroidHandle, "AAssetManager_open");
|
2012-08-02 14:28:40 +08:00
|
|
|
AAsset* Asset = AAssetManager_open(mgr, filename, AASSET_MODE_UNKNOWN);
|
|
|
|
if (NULL == Asset)
|
2012-07-26 15:30:09 +08:00
|
|
|
{
|
2013-03-04 14:54:43 +08:00
|
|
|
//LOGD("file not found! Stop preload file: %s", filename);
|
2012-07-26 15:30:09 +08:00
|
|
|
return FILE_NOT_FOUND;
|
|
|
|
}
|
|
|
|
|
|
|
|
// open asset as file descriptor
|
2012-08-20 12:49:59 +08:00
|
|
|
int (*AAsset_openFileDescriptor)(AAsset* asset, off_t* outStart, off_t* outLength);
|
|
|
|
AAsset_openFileDescriptor = (int (*)(AAsset* asset, off_t* outStart, off_t* outLength))
|
|
|
|
dlsym(s_pAndroidHandle, "AAsset_openFileDescriptor");
|
2012-08-02 14:28:40 +08:00
|
|
|
int fd = AAsset_openFileDescriptor(Asset, &start, &length);
|
2012-07-26 15:30:09 +08:00
|
|
|
assert(0 <= fd);
|
2012-08-20 12:49:59 +08:00
|
|
|
|
|
|
|
void (*AAsset_close)(AAsset* asset);
|
|
|
|
AAsset_close = (void (*)(AAsset* asset))
|
|
|
|
dlsym(s_pAndroidHandle, "AAsset_close");
|
2012-08-02 14:28:40 +08:00
|
|
|
AAsset_close(Asset);
|
2012-07-26 15:30:09 +08:00
|
|
|
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************************************************************
|
|
|
|
* engine
|
|
|
|
**********************************************************************************/
|
2012-07-26 16:45:21 +08:00
|
|
|
static SLObjectItf s_pEngineObject = NULL;
|
|
|
|
static SLEngineItf s_pEngineEngine = NULL;
|
|
|
|
static SLObjectItf s_pOutputMixObject = NULL;
|
2012-07-26 15:30:09 +08:00
|
|
|
|
2012-08-02 14:28:40 +08:00
|
|
|
bool createAudioPlayerBySource(AudioPlayer* player)
|
2012-07-26 15:30:09 +08:00
|
|
|
{
|
|
|
|
// configure audio sink
|
2012-07-26 16:45:21 +08:00
|
|
|
SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, s_pOutputMixObject};
|
2012-07-26 15:30:09 +08:00
|
|
|
SLDataSink audioSnk = {&loc_outmix, NULL};
|
|
|
|
|
|
|
|
// create audio player
|
2012-08-17 09:51:49 +08:00
|
|
|
const SLInterfaceID ids[3] = {
|
|
|
|
getInterfaceID("SL_IID_SEEK"), getInterfaceID("SL_IID_MUTESOLO"), getInterfaceID("SL_IID_VOLUME")};
|
2012-07-26 15:30:09 +08:00
|
|
|
const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
|
2012-07-26 16:45:21 +08:00
|
|
|
SLresult result = (*s_pEngineEngine)->CreateAudioPlayer(s_pEngineEngine, &(player->fdPlayerObject), &(player->audioSrc), &audioSnk, 3, ids, req);
|
2012-08-02 14:28:40 +08:00
|
|
|
if (SL_RESULT_MEMORY_FAILURE == result)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2012-07-26 15:30:09 +08:00
|
|
|
|
|
|
|
// realize the player
|
|
|
|
result = (*(player->fdPlayerObject))->Realize(player->fdPlayerObject, SL_BOOLEAN_FALSE);
|
|
|
|
assert(SL_RESULT_SUCCESS == result);
|
|
|
|
|
|
|
|
// get the play interface
|
2012-08-17 09:51:49 +08:00
|
|
|
result = (*(player->fdPlayerObject))->GetInterface(player->fdPlayerObject, getInterfaceID("SL_IID_PLAY"), &(player->fdPlayerPlay));
|
2012-07-26 15:30:09 +08:00
|
|
|
assert(SL_RESULT_SUCCESS == result);
|
|
|
|
|
|
|
|
// get the volume interface
|
2012-08-17 09:51:49 +08:00
|
|
|
result = (*(player->fdPlayerObject))->GetInterface(player->fdPlayerObject, getInterfaceID("SL_IID_VOLUME"), &(player->fdPlayerVolume));
|
2012-07-26 15:30:09 +08:00
|
|
|
assert(SL_RESULT_SUCCESS == result);
|
|
|
|
|
2012-08-02 14:28:40 +08:00
|
|
|
// get the seek interface
|
2012-08-17 09:51:49 +08:00
|
|
|
result = (*(player->fdPlayerObject))->GetInterface(player->fdPlayerObject, getInterfaceID("SL_IID_SEEK"), &(player->fdPlayerSeek));
|
2012-07-26 15:30:09 +08:00
|
|
|
assert(SL_RESULT_SUCCESS == result);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-08-02 14:28:40 +08:00
|
|
|
bool initAudioPlayer(AudioPlayer* player, const char* filename)
|
|
|
|
{
|
|
|
|
// configure audio source
|
|
|
|
off_t start, length;
|
|
|
|
int fd = getFileDescriptor(filename, start, length);
|
|
|
|
if (FILE_NOT_FOUND == fd)
|
|
|
|
{
|
2013-03-04 14:54:43 +08:00
|
|
|
FILE* fp = fopen(filename , "rb");
|
|
|
|
if(fp){
|
|
|
|
SLDataLocator_URI loc_fd = {SL_DATALOCATOR_URI , (SLchar*)filename};
|
|
|
|
SLDataFormat_MIME format_mime = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED};
|
2013-06-09 15:08:52 +08:00
|
|
|
player->audioSrc.pLocator = &loc_fd;
|
|
|
|
player->audioSrc.pFormat = &format_mime;
|
2013-03-04 14:54:43 +08:00
|
|
|
return createAudioPlayerBySource(player);
|
|
|
|
}
|
|
|
|
LOGD("file not found! Stop preload file: %s", filename);
|
2012-08-02 14:28:40 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
SLDataLocator_AndroidFD loc_fd = {SL_DATALOCATOR_ANDROIDFD, fd, start, length};
|
|
|
|
SLDataFormat_MIME format_mime = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED};
|
2012-12-22 13:58:30 +08:00
|
|
|
player->audioSrc.pLocator = &loc_fd;
|
|
|
|
player->audioSrc.pFormat = &format_mime;
|
2012-08-02 14:28:40 +08:00
|
|
|
|
|
|
|
return createAudioPlayerBySource(player);
|
|
|
|
}
|
|
|
|
|
2012-07-26 15:30:09 +08:00
|
|
|
void destroyAudioPlayer(AudioPlayer * player)
|
|
|
|
{
|
2012-08-02 14:28:40 +08:00
|
|
|
if (player && player->fdPlayerObject != NULL)
|
|
|
|
{
|
|
|
|
SLresult result;
|
|
|
|
result = (*(player->fdPlayerPlay))->SetPlayState(player->fdPlayerPlay, SL_PLAYSTATE_STOPPED);
|
|
|
|
assert(SL_RESULT_SUCCESS == result);
|
|
|
|
|
2012-07-26 15:30:09 +08:00
|
|
|
(*(player->fdPlayerObject))->Destroy(player->fdPlayerObject);
|
|
|
|
player->fdPlayerObject = NULL;
|
|
|
|
player->fdPlayerPlay = NULL;
|
|
|
|
player->fdPlayerSeek = NULL;
|
|
|
|
player->fdPlayerVolume = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-17 09:51:49 +08:00
|
|
|
void OpenSLEngine::createEngine(void* pHandle)
|
2012-07-26 15:30:09 +08:00
|
|
|
{
|
2012-08-20 12:49:59 +08:00
|
|
|
assert(pHandle != NULL);
|
|
|
|
s_pOpenSLESHandle = pHandle;
|
|
|
|
|
|
|
|
// clear the error stack
|
|
|
|
dlerror();
|
|
|
|
s_pAndroidHandle = dlopen(LIBANDROID, RTLD_LAZY);
|
|
|
|
const char* errorInfo = dlerror();
|
|
|
|
if (errorInfo)
|
|
|
|
{
|
|
|
|
LOGD(errorInfo);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-07-26 15:30:09 +08:00
|
|
|
SLresult result;
|
2012-07-26 16:45:21 +08:00
|
|
|
if (s_pEngineObject == NULL)
|
2012-07-26 15:30:09 +08:00
|
|
|
{
|
2012-08-02 14:28:40 +08:00
|
|
|
// create engine
|
2012-08-17 09:51:49 +08:00
|
|
|
SLresult (*slCreateEngine)(SLObjectItf *pEngine, SLuint32 numOptions, const SLEngineOption *pEngineOptions, SLuint32 numInterfaces, const SLInterfaceID *pInterfaceIds, const SLboolean * pInterfaceRequired );
|
|
|
|
slCreateEngine = (SLresult (*)(SLObjectItf *pEngine, SLuint32 numOptions, const SLEngineOption *pEngineOptions, SLuint32 numInterfaces, const SLInterfaceID *pInterfaceIds, const SLboolean * pInterfaceRequired ))
|
|
|
|
getFuncPtr("slCreateEngine");
|
2012-07-26 16:45:21 +08:00
|
|
|
result = slCreateEngine(&s_pEngineObject, 0, NULL, 0, NULL, NULL);
|
2012-07-26 15:30:09 +08:00
|
|
|
assert(SL_RESULT_SUCCESS == result);
|
|
|
|
|
|
|
|
// realize the engine
|
2012-07-26 16:45:21 +08:00
|
|
|
result = (*s_pEngineObject)->Realize(s_pEngineObject, SL_BOOLEAN_FALSE);
|
2012-07-26 15:30:09 +08:00
|
|
|
assert(SL_RESULT_SUCCESS == result);
|
|
|
|
|
|
|
|
// get the engine interface, which is needed in order to create other objects
|
2012-08-17 09:51:49 +08:00
|
|
|
result = (*s_pEngineObject)->GetInterface(s_pEngineObject, getInterfaceID("SL_IID_ENGINE"), &s_pEngineEngine);
|
2012-07-26 15:30:09 +08:00
|
|
|
assert(SL_RESULT_SUCCESS == result);
|
|
|
|
|
|
|
|
// create output mix
|
2012-08-17 09:51:49 +08:00
|
|
|
const SLInterfaceID ids[1] = {getInterfaceID("SL_IID_ENVIRONMENTALREVERB")};
|
2012-07-26 15:30:09 +08:00
|
|
|
const SLboolean req[1] = {SL_BOOLEAN_FALSE};
|
2012-07-26 16:45:21 +08:00
|
|
|
result = (*s_pEngineEngine)->CreateOutputMix(s_pEngineEngine, &s_pOutputMixObject, 1, ids, req);
|
2012-07-26 15:30:09 +08:00
|
|
|
assert(SL_RESULT_SUCCESS == result);
|
|
|
|
|
2012-08-02 14:28:40 +08:00
|
|
|
// realize the output mix object in sync. mode
|
|
|
|
result = (*s_pOutputMixObject)->Realize(s_pOutputMixObject, SL_BOOLEAN_FALSE);
|
|
|
|
assert(SL_RESULT_SUCCESS == result);
|
|
|
|
}
|
2012-07-26 15:30:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void OpenSLEngine::closeEngine()
|
|
|
|
{
|
|
|
|
// destroy background players
|
|
|
|
destroyAudioPlayer(&musicPlayer);
|
|
|
|
|
|
|
|
// destroy effect players
|
2012-08-02 14:28:40 +08:00
|
|
|
vector<AudioPlayer*>* vec;
|
2012-07-26 15:30:09 +08:00
|
|
|
EffectList::iterator p = sharedList().begin();
|
|
|
|
while (p != sharedList().end())
|
|
|
|
{
|
2012-08-02 14:28:40 +08:00
|
|
|
vec = p->second;
|
|
|
|
for (vector<AudioPlayer*>::iterator iter = vec->begin() ; iter != vec->end() ; ++ iter)
|
|
|
|
{
|
|
|
|
destroyAudioPlayer(*iter);
|
|
|
|
}
|
|
|
|
vec->clear();
|
2012-07-26 15:30:09 +08:00
|
|
|
p++;
|
2012-08-02 14:28:40 +08:00
|
|
|
}
|
2012-07-26 15:30:09 +08:00
|
|
|
sharedList().clear();
|
|
|
|
|
|
|
|
// destroy output mix interface
|
2012-08-02 14:28:40 +08:00
|
|
|
if (s_pOutputMixObject)
|
|
|
|
{
|
2012-07-26 16:45:21 +08:00
|
|
|
(*s_pOutputMixObject)->Destroy(s_pOutputMixObject);
|
|
|
|
s_pOutputMixObject = NULL;
|
2012-07-26 15:30:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// destroy opensl engine
|
2012-08-02 14:28:40 +08:00
|
|
|
if (s_pEngineObject)
|
|
|
|
{
|
2012-07-26 16:45:21 +08:00
|
|
|
(*s_pEngineObject)->Destroy(s_pEngineObject);
|
|
|
|
s_pEngineObject = NULL;
|
|
|
|
s_pEngineEngine = NULL;
|
2012-07-26 15:30:09 +08:00
|
|
|
}
|
2012-08-02 14:28:40 +08:00
|
|
|
|
|
|
|
LOGD("engine destory");
|
2012-07-26 15:30:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************************************************************
|
|
|
|
* sound effect
|
|
|
|
**********************************************************************************/
|
2012-08-02 14:28:40 +08:00
|
|
|
typedef struct _CallbackContext
|
|
|
|
{
|
|
|
|
vector<AudioPlayer*>* vec;
|
|
|
|
AudioPlayer* player;
|
|
|
|
} CallbackContext;
|
2012-07-26 15:30:09 +08:00
|
|
|
|
2012-08-02 14:28:40 +08:00
|
|
|
void PlayOverEvent(SLPlayItf caller, void* pContext, SLuint32 playEvent)
|
2012-07-26 15:30:09 +08:00
|
|
|
{
|
2012-08-02 14:28:40 +08:00
|
|
|
CallbackContext* context = (CallbackContext*)pContext;
|
|
|
|
if (playEvent == SL_PLAYEVENT_HEADATEND)
|
|
|
|
{
|
|
|
|
vector<AudioPlayer*>::iterator iter;
|
|
|
|
for (iter = (context->vec)->begin() ; iter != (context->vec)->end() ; ++ iter)
|
|
|
|
{
|
|
|
|
if (*iter == context->player)
|
|
|
|
{
|
|
|
|
(context->vec)->erase(iter);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
destroyAudioPlayer(context->player);
|
|
|
|
free(context);
|
2012-07-26 15:30:09 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-02 14:28:40 +08:00
|
|
|
void setSingleEffectVolume(AudioPlayer* player, SLmillibel volume)
|
|
|
|
{
|
|
|
|
SLresult result;
|
|
|
|
result = (*(player->fdPlayerVolume))->SetVolumeLevel(player->fdPlayerVolume, volume);
|
|
|
|
assert(result == SL_RESULT_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
int getSingleEffectState(AudioPlayer * player)
|
2012-07-27 10:36:05 +08:00
|
|
|
{
|
|
|
|
SLuint32 state = 0;
|
|
|
|
SLresult result;
|
|
|
|
result = (*(player->fdPlayerPlay))->GetPlayState(player->fdPlayerPlay, &state);
|
|
|
|
assert(result == SL_RESULT_SUCCESS);
|
|
|
|
|
|
|
|
return (int)state;
|
|
|
|
}
|
|
|
|
|
2012-08-02 14:28:40 +08:00
|
|
|
void setSingleEffectState(AudioPlayer * player, int state)
|
|
|
|
{
|
|
|
|
SLresult result;
|
|
|
|
if (player->fdPlayerPlay != NULL)
|
|
|
|
{
|
|
|
|
// don't set to PAUSED state if it's already set to STOPPED state
|
|
|
|
int oldState = getSingleEffectState(player);
|
|
|
|
if (oldState == SL_PLAYSTATE_STOPPED && state == SL_PLAYSTATE_PAUSED)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
result = (*(player->fdPlayerPlay))->SetPlayState(player->fdPlayerPlay, state);
|
|
|
|
assert(SL_RESULT_SUCCESS == result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-27 10:36:05 +08:00
|
|
|
void resumeSingleEffect(AudioPlayer * player)
|
|
|
|
{
|
2012-08-02 14:28:40 +08:00
|
|
|
int state = getSingleEffectState(player);
|
2012-07-27 10:36:05 +08:00
|
|
|
// only resume the effect that has been paused
|
2012-08-02 14:28:40 +08:00
|
|
|
if (state == SL_PLAYSTATE_PAUSED)
|
|
|
|
{
|
|
|
|
setSingleEffectState(player, SL_PLAYSTATE_PLAYING);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool OpenSLEngine::recreatePlayer(const char* filename)
|
|
|
|
{
|
|
|
|
unsigned int effectID = _Hash(filename);
|
|
|
|
EffectList::iterator p = sharedList().find(effectID);
|
|
|
|
vector<AudioPlayer*>* vec = p->second;
|
|
|
|
AudioPlayer* newPlayer = new AudioPlayer();
|
|
|
|
if (!initAudioPlayer(newPlayer, filename))
|
2012-07-27 10:36:05 +08:00
|
|
|
{
|
2012-08-02 14:28:40 +08:00
|
|
|
LOGD("failed to recreate");
|
|
|
|
return false;
|
2012-07-27 10:36:05 +08:00
|
|
|
}
|
2012-08-02 14:28:40 +08:00
|
|
|
vec->push_back(newPlayer);
|
|
|
|
|
|
|
|
// set callback
|
|
|
|
SLresult result;
|
|
|
|
CallbackContext* context = new CallbackContext();
|
|
|
|
context->vec = vec;
|
|
|
|
context->player = newPlayer;
|
|
|
|
result = (*(newPlayer->fdPlayerPlay))->RegisterCallback(newPlayer->fdPlayerPlay, PlayOverEvent, (void*)context);
|
|
|
|
assert(SL_RESULT_SUCCESS == result);
|
|
|
|
|
|
|
|
result = (*(newPlayer->fdPlayerPlay))->SetCallbackEventsMask(newPlayer->fdPlayerPlay, SL_PLAYEVENT_HEADATEND);
|
|
|
|
assert(SL_RESULT_SUCCESS == result);
|
|
|
|
|
|
|
|
// set volume
|
|
|
|
setSingleEffectVolume(newPlayer, m_effectVolume);
|
|
|
|
setSingleEffectState(newPlayer, SL_PLAYSTATE_STOPPED);
|
|
|
|
setSingleEffectState(newPlayer, SL_PLAYSTATE_PLAYING);
|
|
|
|
|
|
|
|
// LOGD("vec count is %d of effectID %d", vec->size(), effectID);
|
|
|
|
return true;
|
2012-07-27 10:36:05 +08:00
|
|
|
}
|
|
|
|
|
2012-07-26 15:30:09 +08:00
|
|
|
unsigned int OpenSLEngine::preloadEffect(const char * filename)
|
|
|
|
{
|
|
|
|
unsigned int nID = _Hash(filename);
|
|
|
|
// if already exists
|
2012-08-02 14:28:40 +08:00
|
|
|
EffectList::iterator p = sharedList().find(nID);
|
|
|
|
if (p != sharedList().end())
|
2012-07-26 15:30:09 +08:00
|
|
|
{
|
|
|
|
return nID;
|
|
|
|
}
|
2012-08-02 14:28:40 +08:00
|
|
|
|
2012-07-26 15:30:09 +08:00
|
|
|
AudioPlayer* player = new AudioPlayer();
|
|
|
|
if (!initAudioPlayer(player, filename))
|
|
|
|
{
|
|
|
|
free(player);
|
|
|
|
return FILE_NOT_FOUND;
|
|
|
|
}
|
2012-08-02 14:28:40 +08:00
|
|
|
|
2012-07-26 15:30:09 +08:00
|
|
|
// set the new player's volume as others'
|
2012-08-02 14:28:40 +08:00
|
|
|
setSingleEffectVolume(player, m_effectVolume);
|
2012-07-26 15:30:09 +08:00
|
|
|
|
2012-08-02 14:28:40 +08:00
|
|
|
vector<AudioPlayer*>* vec = new vector<AudioPlayer*>;
|
|
|
|
vec->push_back(player);
|
|
|
|
sharedList().insert(Effect(nID, vec));
|
2012-07-26 15:30:09 +08:00
|
|
|
return nID;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpenSLEngine::unloadEffect(const char * filename)
|
|
|
|
{
|
|
|
|
unsigned int nID = _Hash(filename);
|
|
|
|
|
|
|
|
EffectList::iterator p = sharedList().find(nID);
|
|
|
|
if (p != sharedList().end())
|
|
|
|
{
|
2012-08-02 14:28:40 +08:00
|
|
|
vector<AudioPlayer*>* vec = p->second;
|
|
|
|
for (vector<AudioPlayer*>::iterator iter = vec->begin() ; iter != vec->end() ; ++ iter)
|
|
|
|
{
|
|
|
|
destroyAudioPlayer(*iter);
|
|
|
|
}
|
|
|
|
vec->clear();
|
2012-07-26 15:30:09 +08:00
|
|
|
sharedList().erase(nID);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-02 14:28:40 +08:00
|
|
|
int OpenSLEngine::getEffectState(unsigned int effectID)
|
2012-07-26 15:30:09 +08:00
|
|
|
{
|
2012-08-02 14:28:40 +08:00
|
|
|
int state = PLAYSTATE_UNKNOWN;
|
2012-07-26 15:30:09 +08:00
|
|
|
EffectList::iterator p = sharedList().find(effectID);
|
|
|
|
if (p != sharedList().end())
|
|
|
|
{
|
2012-08-02 14:28:40 +08:00
|
|
|
vector<AudioPlayer*>* vec = p->second;
|
|
|
|
// get the last player's state
|
|
|
|
vector<AudioPlayer*>::reverse_iterator r_iter = vec->rbegin();
|
|
|
|
state = getSingleEffectState(*r_iter);
|
|
|
|
}
|
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpenSLEngine::setEffectState(unsigned int effectID, int state, bool isClear)
|
|
|
|
{
|
|
|
|
EffectList::iterator p = sharedList().find(effectID);
|
|
|
|
if (p != sharedList().end())
|
|
|
|
{
|
|
|
|
vector<AudioPlayer*>* vec = p->second;
|
|
|
|
if (state == SL_PLAYSTATE_STOPPED || state == SL_PLAYSTATE_PAUSED)
|
|
|
|
{
|
|
|
|
// if stopped, clear the recreated players which are unused
|
|
|
|
if (isClear)
|
|
|
|
{
|
|
|
|
setSingleEffectState(*(vec->begin()), state);
|
|
|
|
vector<AudioPlayer*>::reverse_iterator r_iter = vec->rbegin();
|
|
|
|
for (int i = 1, size = vec->size() ; i < size ; ++ i)
|
|
|
|
{
|
|
|
|
destroyAudioPlayer(*r_iter);
|
|
|
|
r_iter ++;
|
|
|
|
vec->pop_back();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
vector<AudioPlayer*>::iterator iter;
|
|
|
|
for (iter = vec->begin() ; iter != vec->end() ; ++ iter)
|
|
|
|
{
|
|
|
|
setSingleEffectState(*iter, state);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
setSingleEffectState(*(vec->rbegin()), state);
|
|
|
|
}
|
2012-07-26 15:30:09 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpenSLEngine::setAllEffectState(int state)
|
|
|
|
{
|
2012-08-02 14:28:40 +08:00
|
|
|
EffectList::iterator p;
|
|
|
|
for (p = sharedList().begin(); p != sharedList().end(); p ++)
|
2012-07-26 15:30:09 +08:00
|
|
|
{
|
2012-08-02 14:28:40 +08:00
|
|
|
vector<AudioPlayer*>* vec = p->second;
|
|
|
|
for (vector<AudioPlayer*>::iterator iter = vec->begin() ; iter != vec->end() ; ++ iter)
|
|
|
|
{
|
|
|
|
setSingleEffectState(*iter, state);
|
|
|
|
}
|
2012-07-26 15:30:09 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-27 10:36:05 +08:00
|
|
|
void OpenSLEngine::resumeEffect(unsigned int effectID)
|
|
|
|
{
|
|
|
|
EffectList::iterator p = sharedList().find(effectID);
|
2012-08-02 14:28:40 +08:00
|
|
|
if (p != sharedList().end())
|
2012-07-27 10:36:05 +08:00
|
|
|
{
|
2012-08-02 14:28:40 +08:00
|
|
|
vector<AudioPlayer*>* vec = p->second;
|
|
|
|
for (vector<AudioPlayer*>::iterator iter = vec->begin() ; iter != vec->end() ; ++ iter)
|
|
|
|
{
|
|
|
|
resumeSingleEffect(*iter);
|
|
|
|
}
|
2012-07-27 10:36:05 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpenSLEngine::resumeAllEffects()
|
|
|
|
{
|
|
|
|
int state;
|
2012-08-02 14:28:40 +08:00
|
|
|
EffectList::iterator p;
|
|
|
|
for (p = sharedList().begin(); p != sharedList().end() ; ++ p)
|
2012-07-27 10:36:05 +08:00
|
|
|
{
|
2012-08-02 14:28:40 +08:00
|
|
|
vector<AudioPlayer*>* vec = p->second;
|
|
|
|
for (vector<AudioPlayer*>::iterator iter = vec->begin() ; iter != vec->end() ; ++ iter)
|
|
|
|
{
|
|
|
|
resumeSingleEffect(*iter);
|
|
|
|
}
|
2012-07-27 10:36:05 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-26 15:30:09 +08:00
|
|
|
void OpenSLEngine::setEffectLooping(unsigned int effectID, bool isLooping)
|
|
|
|
{
|
|
|
|
SLresult result;
|
2012-08-02 14:28:40 +08:00
|
|
|
vector<AudioPlayer*>* vec = sharedList()[effectID];
|
|
|
|
assert(NULL != vec);
|
|
|
|
|
|
|
|
// get the first effect player that to be set loop config
|
|
|
|
vector<AudioPlayer*>::iterator iter = vec->begin();
|
|
|
|
AudioPlayer * player = *iter;
|
2012-07-26 15:30:09 +08:00
|
|
|
|
2012-08-02 14:28:40 +08:00
|
|
|
if (player && player->fdPlayerSeek)
|
2012-07-26 15:30:09 +08:00
|
|
|
{
|
|
|
|
result = (*(player->fdPlayerSeek))->SetLoop(player->fdPlayerSeek, (SLboolean) isLooping, 0, SL_TIME_UNKNOWN);
|
|
|
|
assert(SL_RESULT_SUCCESS == result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-02 14:28:40 +08:00
|
|
|
void OpenSLEngine::setEffectsVolume(float volume)
|
2012-07-26 15:30:09 +08:00
|
|
|
{
|
2012-08-02 14:28:40 +08:00
|
|
|
assert(volume <= 1.0f && volume >= 0.0f);
|
|
|
|
m_effectVolume = int (RANGE_VOLUME_MILLIBEL * volume) + MIN_VOLUME_MILLIBEL;
|
|
|
|
|
2012-07-26 15:30:09 +08:00
|
|
|
SLresult result;
|
2012-08-02 14:28:40 +08:00
|
|
|
EffectList::iterator p;
|
2012-07-26 15:30:09 +08:00
|
|
|
AudioPlayer * player;
|
2012-08-02 14:28:40 +08:00
|
|
|
for (p = sharedList().begin() ; p != sharedList().end() ; ++ p)
|
2012-07-26 15:30:09 +08:00
|
|
|
{
|
2012-08-02 14:28:40 +08:00
|
|
|
vector<AudioPlayer*>* vec = p->second;
|
|
|
|
for (vector<AudioPlayer*>::iterator iter = vec->begin() ; iter != vec->end() ; ++ iter)
|
|
|
|
{
|
|
|
|
player = *iter;
|
|
|
|
result = (*(player->fdPlayerVolume))->SetVolumeLevel(player->fdPlayerVolume, m_effectVolume);
|
|
|
|
assert(SL_RESULT_SUCCESS == result);
|
|
|
|
}
|
2012-07-26 15:30:09 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-02 14:28:40 +08:00
|
|
|
float OpenSLEngine::getEffectsVolume()
|
2012-07-26 15:30:09 +08:00
|
|
|
{
|
2012-08-02 14:28:40 +08:00
|
|
|
float volume = (m_effectVolume - MIN_VOLUME_MILLIBEL) / (1.0f * RANGE_VOLUME_MILLIBEL);
|
|
|
|
return volume;
|
2012-10-16 16:20:41 +08:00
|
|
|
}
|