三星S2 i9100机子声音驱动有bug,导致SoundPool播放音效过多的时候崩溃。子弹连续射击的音效在这台机子上几乎是必杀技。
cocos2d-x有解决这个问题,使用了OpenSL,这个是类似OpenGL的一种声音标准,android2.3以上的系统有支持。 非i9100的设备使用SoundPool,i9100设备使用OpenSL播放音效。
cocos2d-x的声音播放引擎CocosDenshion尚有瑕疵,OpenSL读取文件的时候使用了AssetsManager,但是不支持SD卡的音效文件读取。而我的游戏的实现是这样的,所有资源打包到pak文件中,播放声音的时候如果SD卡没有对应文件则把声音拷贝到SD卡,然后播放SD卡的声音文件。 显然cocos2d-x不兼容这种方式。
修改方式很简单,OpenSLEngine.cpp文件中修改getFileDescriptor函数:
int getFileDescriptor(const char * filename, off_t & start, off_t & length, bool inapk) { if (!inapk) { FILE* fp = fopen(filename, "rb"); fseek(fp, 0, SEEK_END); length = ftell(fp); fseek(fp, 0, SEEK_SET); start = 0; return fileno(fp); } else { JniMethodInfo methodInfo; if (! getStaticMethodInfo(methodInfo, ASSET_MANAGER_GETTER, "()Landroid/content/res/AssetManager;")) { methodInfo.env->DeleteLocalRef(methodInfo.classID); return FILE_NOT_FOUND; } jobject assetManager = methodInfo.env->CallStaticObjectMethod(methodInfo.classID, methodInfo.methodID); methodInfo.env->DeleteLocalRef(methodInfo.classID); AAssetManager* (*AAssetManager_fromJava)(JNIEnv* env, jobject assetManager); AAssetManager_fromJava = (AAssetManager* (*)(JNIEnv* env, jobject assetManager)) dlsym(s_pAndroidHandle, "AAssetManager_fromJava"); AAssetManager* mgr = AAssetManager_fromJava(methodInfo.env, assetManager); assert(NULL != mgr); 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"); AAsset* Asset = AAssetManager_open(mgr, filename, AASSET_MODE_UNKNOWN); if (NULL == Asset) { LOGD("file not found! Stop preload file: %s", filename); return FILE_NOT_FOUND; } // open asset as file descriptor 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"); int fd = AAsset_openFileDescriptor(Asset, &start, &length); assert(0 <= fd); void (*AAsset_close)(AAsset* asset); AAsset_close = (void (*)(AAsset* asset)) dlsym(s_pAndroidHandle, "AAsset_close"); AAsset_close(Asset); return fd; } }