解决三星S2 i9100声音播放崩溃(CocosDenshion)

        三星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;
	}
}

如代码所示,如果资源不是apk包内的资源,则使用fopen的方式获取文件句柄fd。

你可能感兴趣的:(解决三星S2 i9100声音播放崩溃(CocosDenshion))