cocos2dx 音频模块分析(4): 音效部分
发表于2015-12-02
cocos2dx 音频模块分析(4): 音效部分
- 我们上面几篇分析了cocos2dx音频模块的音乐部分,从这篇开始,
- 我们分析下音效部分:
- 1、
- //预加载音效文件:pszFilePath 音效文件名
- void SimpleAudioEngine::preloadEffect(const char* pszFilePath)
- {
- //获取音效文件的全路径,如果是apk包里的路径,则不包含assets/
- std::string fullPath = getFullPathWithoutAssetsPrefix(pszFilePath);
- preloadEffectJNI(fullPath.c_str());
- }
- --->>>// 这里通过jni调用java端的方法
- void preloadEffectJNI(const char *path)
- {
- // void preloadEffect(String)
- JniMethodInfo methodInfo;
- if (! getStaticMethodInfo(methodInfo, "preloadEffect", "(Ljava/lang/String;)V"))
- {
- return ;
- }
- jstring stringArg = methodInfo.env->NewStringUTF(path);
- methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID, stringArg);
- methodInfo.env->DeleteLocalRef(stringArg);
- methodInfo.env->DeleteLocalRef(methodInfo.classID);
- }
- ----->>>//Cocos2dxHelper类中的方法:
- public static void preloadEffect(final String path) {
- //Cocos2dxSound类是专门处理音效的类
- Cocos2dxHelper.sCocos2dSound.preloadEffect(path);
- }
- --->>>//Cocos2dxSound类的方法:
- public int preloadEffect(final String pPath) {
- //private final HashMap
mPathSoundIDMap = new HashMap (); - //这个是音效路径对应音效ID的map
- Integer soundID = this.mPathSoundIDMap.get(pPath);
- if (soundID == null) {
- //
- soundID = this.createSoundIDFromAsset(pPath);
- // save value just in case if file is really loaded
- // 如果createSoundIDFromAsset函数调用成功,则添加到mPathSoundIDMap中。
- if (soundID != Cocos2dxSound.INVALID_SOUND_ID) {
- this.mPathSoundIDMap.put(pPath, soundID);
- }
- }
- return soundID;
- }
- ----->>>>根据我们传入的音效文件路径,加载音效
- public int createSoundIDFromAsset(final String pPath) {
- int soundID = Cocos2dxSound.INVALID_SOUND_ID;
- try {
- //根据传入的路径不同,做不同处理,一个是绝对路径一个是包里的路径,加载音效文件
- //The SoundPool class manages and plays audio resources for applications.
- //private SoundPool mSoundPool;音效缓存池
- if (pPath.startsWith("/")) {
- soundID = this.mSoundPool.load(pPath, 0);
- } else {
- soundID = this.mSoundPool.load(this.mContext.getAssets().openFd(pPath), 0);
- }
- } catch (final Exception e) {
- soundID = Cocos2dxSound.INVALID_SOUND_ID;
- Log.e(Cocos2dxSound.TAG, "error: " e.getMessage(), e);
- }
- // mSoundPool.load returns 0 if something goes wrong, for example a file does not exist
- if (soundID == 0) {
- soundID = Cocos2dxSound.INVALID_SOUND_ID;
- }
- return soundID;
- }
- 2、
- 播放音效文件。
- pszFilePath:音效文件名;bLoop 是否循环播放
- unsigned int SimpleAudioEngine::playEffect(const char* pszFilePath, bool bLoop)
- {
- std::string fullPath = getFullPathWithoutAssetsPrefix(pszFilePath);
- return playEffectJNI(fullPath.c_str(), bLoop);
- }
- ----->>>playEffectJNI:
- unsigned int playEffectJNI(const char* path, bool bLoop)
- {
- // int playEffect(String)
- JniMethodInfo methodInfo;
- int ret = 0;
- if (! getStaticMethodInfo(methodInfo, "playEffect", "(Ljava/lang/String;Z)I"))
- {
- return ret;
- }
- jstring stringArg = methodInfo.env->NewStringUTF(path);
- ret = methodInfo.env->CallStaticIntMethod(methodInfo.classID, methodInfo.methodID, stringArg, bLoop);
- methodInfo.env->DeleteLocalRef(stringArg);
- methodInfo.env->DeleteLocalRef(methodInfo.classID);
- return (unsigned int)ret;
- }
- ------>>>>playEffect:
- public int playEffect(final String pPath, final boolean pLoop) {
- //从mPathSoundIDMap中,根据音效path得到音效ID
- Integer soundID = this.mPathSoundIDMap.get(pPath);
- int streamID = Cocos2dxSound.INVALID_STREAM_ID;
- if (soundID != null) {
- // play sound
- // 如果音效ID存在,则表明我们已经预先加载过这个音效文件,则调用mSoundPool.play直接播放
- /*
- private int doPlayEffect(final String pPath, final int soundId, final boolean pLoop) {
- // play sound
- // Play a sound from a sound ID.
- // return non-zero streamID if successful, zero if failed如果成功会返回一个streamID
- int streamID = this.mSoundPool.play(soundId, this.mLeftVolume, this.mRightVolume, Cocos2dxSound.SOUND_PRIORITY, pLoop ? -1 : 0, Cocos2dxSound.SOUND_RATE);
- // record stream id
- // 记录上面调用mSoundPool.play返回的streamID,至于为什么需要这样,看下面源码的说明:
- // sound path and stream ids map
- // a file may be played many times at the same time
- // so there is an array map to a file path
- // private final HashMap<string, arraylist
> mPathStreamIDsMap = new HashMap<string, arraylist >();</string, arraylist </string, arraylist - ArrayList
streamIDs = this.mPathStreamIDsMap.get(pPath); - if (streamIDs == null) {
- streamIDs = new ArrayList
(); - this.mPathStreamIDsMap.put(pPath, streamIDs);
- }
- streamIDs.add(streamID);
- return streamID;
- }
- */
- streamID = this.doPlayEffect(pPath, soundID.intValue(), pLoop);
- } else {
- // the effect is not prepared,如果音效没有预先加载,则需要先加载
- soundID = this.preloadEffect(pPath); //加载音效文件
- if (soundID == Cocos2dxSound.INVALID_SOUND_ID) {
- // can not preload effect
- return Cocos2dxSound.INVALID_SOUND_ID;
- }
- // only allow one playEffect at a time, or the semaphore will not work correctly
- synchronized(this.mSoundPool) {
- // add this effect into mEffecToPlayWhenLoadedArray, and it will be played when loaded completely
- // 这个应该和mSoundPool加载音效文件有关,我也不是很明白
- /*
- 不过在初始化时设置了一个:this.mSoundPool.setOnLoadCompleteListener(new OnLoadCompletedListener());
- //加载完成回调函数,应该和这个有关,这里我们就不关心了。 只需要知道如果我们提前加载音效文件
- //也可以直接调用play函数,在调用play函数时会调用加载函数,并放入加载队列中,加载完成后进行播放。
- //这样做会有一些延时,所以我们还是最好先加载,然后在播放。这个延时只在第一次播放时有,以后就不会了,
- //不过最好还是先加载。
- */
- /*
- @Override
- //加载完成回调函数。
- public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
- if (status == 0)
- {
- // only play effect that are in mEffecToPlayWhenLoadedArray
- for ( SoundInfoForLoadedCompleted info : mEffecToPlayWhenLoadedArray) {
- if (sampleId == info.soundID) {
- // set the stream id which will be returned by playEffect()
- // 加载完成后调用doPlayEffect进行播放,并从mEffecToPlayWhenLoadedArray加载列表中
- // 移除。
- mStreamIdSyn = doPlayEffect(info.path, info.soundID, info.isLoop);
- // remove it from array, because we will break here
- // so it is safe to do
- mEffecToPlayWhenLoadedArray.remove(info);
- break;
- }
- }
- } else {
- mStreamIdSyn = Cocos2dxSound.INVALID_SOUND_ID;
- }
- mSemaphore.release();
- }
- }
- */
- mEffecToPlayWhenLoadedArray.add(new SoundInfoForLoadedCompleted(pPath, soundID.intValue(), pLoop));
- try {
- // wait OnloadedCompleteListener to set streamID
- this.mSemaphore.acquire();
- streamID = this.mStreamIdSyn;
- } catch(Exception e) {
- return Cocos2dxSound.INVALID_SOUND_ID;
- }
- }
- }
- return streamID;
- }