cocos2dx 音频模块分析(2):背景音乐

发表于2015-12-02
评论0 1.1k浏览
我在(1)已经分析了一些东西,这里接着分析,这一篇我们主要分析背景音乐文件的播放,  
还是基于android平台:  
  
1、  
这里只是背景音乐的预加载,为什么要进行预加载呢?  
主要是加载音乐文件是比较耗时的,如果我们没有预加载就直接播放也是可以的,  
但是会有一定的延时,因为如果没有预加载,就直接播放,也是会先进行加载音乐文件,  
然后进行播放。  
void SimpleAudioEngine::preloadBackgroundMusic(const char* pszFilePath)  
{  
    std::string fullPath = getFullPathWithoutAssetsPrefix(pszFilePath);  
    preloadBackgroundMusicJNI(fullPath.c_str());  
}  
  
其实加载背景音乐最终调用android端:  
public void preloadBackgroundMusic(final String pPath) {  
        if ((this.mCurrentPath == null) || (!this.mCurrentPath.equals(pPath))) {  
            // preload new background music  
  
            // release old resource and create a new one  
            // 如果我们播放的是一个新的背景音乐文件,那么我们需要先释放旧的播放器,然后创建一个新的  
            // Releases resources associated with this MediaPlayer object.  
            if (this.mBackgroundMediaPlayer != null) {  
                this.mBackgroundMediaPlayer.release();  
            }  
                        //创建一个播放器即MediaPlayer类的实例  
            this.mBackgroundMediaPlayer = this.createMediaplayer(pPath);  
  
            // record the path  
            // 记录当前播放的背景音乐文件,因为下次如果播放的是同一个音乐  
            // 文件,那么我们就可以直接进行播放了,不用再重新创建MediaPlayer类的实例  
            this.mCurrentPath = pPath;   
        }  
    }  
  
----->>>  
    /** 
     * create mediaplayer for music 
     *  
     * @param pPath 
     *            the pPath relative to assets 
     * @return 
     */  
    private MediaPlayer createMediaplayer(final String pPath) {  
        MediaPlayer mediaPlayer = new MediaPlayer();  
  
        try {  
                //对绝对路径和包里的路径进行区分处理,当最终的目的就是设置播放源  
            if (pPath.startsWith("/")) {  
                final FileInputStream fis = new FileInputStream(pPath);  
                mediaPlayer.setDataSource(fis.getFD());  
                fis.close();  
            } else {  
                final AssetFileDescriptor assetFileDescritor = this.mContext.getAssets().openFd(pPath);  
                mediaPlayer.setDataSource(assetFileDescritor.getFileDescriptor(), assetFileDescritor.getStartOffset(), assetFileDescritor.getLength());  
            }  
                        //播放器前需要做些准备工作,这个只是android的api,不明白的话,查下文档。  
            /** 
             * Prepares the player for playback, synchronously. 
             * 
             * After setting the datasource and the display surface, you need to either 
             * call prepare() or prepareAsync(). For files, it is OK to call prepare(), 
             * which blocks until MediaPlayer is ready for playback. 
             * 
             * @throws IllegalStateException if it is called in an invalid state 
             */  
            mediaPlayer.prepare();  
                          
            //设置声音音量  
            mediaPlayer.setVolume(this.mLeftVolume, this.mRightVolume);  
        } catch (final Exception e) {  
            mediaPlayer = null;  
            Log.e(Cocos2dxMusic.TAG, "error: " e.getMessage(), e);  
        }  
  
        return mediaPlayer;  
    }  
  
2、  
音乐播放函数  
//pszFilePath: 音乐文件名  
//bLoop: 是否循环播放,音乐文件我们一般设置为循环播放,看具体情况  
void SimpleAudioEngine::playBackgroundMusic(const char* pszFilePath, bool bLoop)  
{  
    std::string fullPath = getFullPathWithoutAssetsPrefix(pszFilePath);  
    playBackgroundMusicJNI(fullPath.c_str(), bLoop);  
}  
  
--->>> 最终都会调用到android端的playBackgroundMusic函数,并把文件路径,是否循环播放传进来  
    public void playBackgroundMusic(final String path, final boolean isLoop) {  
        if (mCurrentPath == null) {  
            // it is the first time to play background music or end() was called  
            // 如果以前没有播放过音乐文件,那么重新创建一个,上面的英文注释很清楚  
            mBackgroundMediaPlayer = createMediaplayer(path);  
            mCurrentPath = path;  
        } else {  
            if (!mCurrentPath.equals(path)) {  
                // play new background music  
                                   
                //如果这次播放的音乐文件和上次的不同,即是一个新的音乐文件,  
                //那么就需要先释放掉旧的,然后创建一个新的。  
                // release old resource and create a new one  
                if (mBackgroundMediaPlayer != null) {  
                    mBackgroundMediaPlayer.release();  
                }  
                mBackgroundMediaPlayer = createMediaplayer(path);  
  
                // record the path  
                mCurrentPath = path;  
            }  
        }  
  
        if (mBackgroundMediaPlayer == null) {  
            Log.e(Cocos2dxMusic.TAG, "playBackgroundMusic: background media player is null");  
        } else {  
            try {  
                // if the music is playing or paused, stop it  
                // 对playing or paused, stop三种情况进行分别处理  
                if (mPaused) {  
                        //如果是暂停状态,那么就把播放进度设置到0,然后开始。  
                    //这就意味着,如果我们调用了暂停,然后又调用play,那么  
                    //音乐将会从头开始播放,而不是从暂停的地方接着播放。  
                        /** 
                         * Seeks to specified time position. 
                         * 
                         * @param msec the offset in milliseconds from the start to seek to 
                         * @throws IllegalStateException if the internal player engine has not been 
                         * initialized 
                         */  
                    mBackgroundMediaPlayer.seekTo(0);  
  
                    /** 
                     * Starts(开始) or resumes playback(恢复播放). If playback had previously been paused, 
                     * playback will continue from where it was paused. If playback had 
                     * been stopped, or never started before, playback will start at the 
                     * beginning. 
                     * start函数两个功能,一个是开始播放,一个是恢复播放 
                     * 1、如果stopped或者never started before(第一次开始),那么就从头开始播放 
                     * 2、如果paused即暂停,那么将会从暂停的地方接着播放。 
                     */  
                    mBackgroundMediaPlayer.start();  
                } else if (mBackgroundMediaPlayer.isPlaying()) {  
                        //如果处于播放状态,则回到开始,从头播放  
                    mBackgroundMediaPlayer.seekTo(0);  
                } else {  
                        //如果处于stop状态,则从新播放,上面已经说明了start函数的两个作用  
                    mBackgroundMediaPlayer.start();  
                }  
                                /* 
                总结:其实对上面三种情况分别处理,最终达到的效果都是一样的, 
                那就是从头开始播放背景音乐文件。 
                */  
  
                //设置是否循环播放  
                mBackgroundMediaPlayer.setLooping(isLoop);  
  
                //mPaused 表示设为false,表示不处于暂停状态  
                mPaused = false;  
  
                //是否循环播放记录  
                mIsLoop = isLoop;  
            } catch (final Exception e) {  
                Log.e(Cocos2dxMusic.TAG, "playBackgroundMusic: error state");  
            }  
        }  
    }  
  
3、总结:  
从上面的分析我们可以知道,如果预先进行加载即先创建一个MediaPlayer,  
那么我们播放时可以直接进行播放,如果我们我们没有提前进行预加载,  
而是直接调用playBackgroundMusic函数,也可以进行播放,只不过会有一个创建  
MediaPlayer的过程,会有一些时间上的延时。  

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引

标签: