多平台声音播放方案
多平台声音播放本质是引擎提供统一播放接口,根据平台不同调用各平台的api。
/********************************************************************
Copyright(C), 2012-2013,
FileName:AudioEngine.h
Description:
Author:cloud
Created:2014/10/24
history:
24:10:2014 13:45 by
*********************************************************************/
#pragma once
#include "Singleton.h"
#include <map>
#include <list>
#include <string>
namespace cloud
{
//wraper of cocosDension
class AudioEngine : public Singleton<AudioEngine>
{
public:
DECLARE_SINGLETON_CREATE_DESTROY
void setVolume(float volume);
void setBGMVolume(float volume);
void setSFXVolume(float volume);
void playMusic(const std::string& fileName,bool bLoop = false);
void stopMusic();
void pauseBackgroundMusic();
void resumeBackgroundMusic();
void stopAllMusic();
void stopAllSFX();
void playSound(unsigned int soundId,bool bLoop = false);
void playSoundOnce(const std::string& fileName);
void stopSound(unsigned int soundId);
void loadSound(const std::string& fileName,unsigned int soundId);
void unLoadSound(unsigned int soundId);
void clearSounds();
bool isBGMEnabled() const;
void setBGMEnabled(bool bBGMEnabled);
bool isSFXEnabled() const;
void setSFXEnabled(bool bSFXEnabled);
protected:
AudioEngine();
~AudioEngine();
typedef std::map<unsigned int,std::string> SoundIDMap;
typedef std::multimap<unsigned int,unsigned int> SoundRTMap;
SoundIDMap m_soundIdResMap;
SoundRTMap m_soundRtMap;
bool m_bgmEnabled;
bool m_sfxEnabled;
};
}
/********************************************************************
Copyright(C), 2012-2013,
FileName:AudioEngine.cpp
Description:
Author:cloud
Created:2014/10/24
history:
24:10:2014 13:46 by
*********************************************************************/
#include "AudioEngine.h"
#include "AudioEngineCore.h"
namespace cloud
{
IMPLEMENT_SINGLETON_ALL(AudioEngine)
AudioEngine::AudioEngine()
:Singleton<AudioEngine>(),m_bgmEnabled(true),m_sfxEnabled(true)
{
}
AudioEngine::~AudioEngine()
{
stopAllMusic();
clearSounds();
AudioEngineCore::end();
}
void AudioEngine::setVolume(float volume)
{
AudioEngineCore::setEffectsVolume(volume);
AudioEngineCore::setBackgroundMusicVolume(volume);
}
void AudioEngine::setBGMVolume(float volume)
{
AudioEngineCore::setBackgroundMusicVolume(volume);
}
void AudioEngine::setSFXVolume(float volume)
{
AudioEngineCore::setEffectsVolume(volume);
}
void AudioEngine::playMusic(const std::string& fileName,bool bLoop /* = false */)
{
stopMusic();
if (m_bgmEnabled)
{
AudioEngineCore::playBackgroundMusic(fileName.c_str(),bLoop);
}
}
void AudioEngine::stopMusic()
{
AudioEngineCore::stopBackgroundMusic(true);
}
void AudioEngine::pauseBackgroundMusic()
{
AudioEngineCore::pauseBackgroundMusic();
}
void AudioEngine::resumeBackgroundMusic()
{
AudioEngineCore::resumeBackgroundMusic();
}
void AudioEngine::stopAllSFX()
{
AudioEngineCore::stopAllEffects();
m_soundRtMap.clear();
}
void AudioEngine::stopAllMusic()
{
stopMusic();
}
void AudioEngine::playSoundOnce(const std::string& fileName)
{
if (m_sfxEnabled)
{
AudioEngineCore::playEffect(fileName.c_str());
}
}
void AudioEngine::playSound(unsigned int soundId,bool bLoop /* = false */)
{
if (m_sfxEnabled)
{
unsigned int rtId = AudioEngineCore::playEffect(m_soundIdResMap[soundId].c_str(),bLoop);
m_soundRtMap.insert(std::make_pair(soundId,rtId));
}
}
void AudioEngine::stopSound(unsigned int soundId)
{
SoundRTMap::iterator iter = m_soundRtMap.find(soundId);
size_t count = m_soundRtMap.count(soundId);
for (size_t i = 0;i < count;++i)
{
SoundRTMap::iterator tempIter=iter;
AudioEngineCore::stopEffect(iter->second);
++iter;
m_soundRtMap.erase(tempIter);
}
}
void AudioEngine::loadSound(const std::string& fileName,unsigned int soundId)
{
const char* fullName = fileName.c_str();
AudioEngineCore::preloadEffect(fullName);
m_soundIdResMap.insert(std::make_pair(soundId,std::string(fullName)));
}
void AudioEngine::unLoadSound(unsigned int soundId)
{
stopSound(soundId);
AudioEngineCore::unloadEffect(m_soundIdResMap[soundId].c_str());
}
void AudioEngine::clearSounds()
{
stopAllSFX();
for (SoundIDMap::iterator itB = m_soundIdResMap.begin(),itE=m_soundIdResMap.end();itB!=itE;++itB)
{
AudioEngineCore::unloadEffect(itB->second.c_str());
}
m_soundIdResMap.clear();
}
bool AudioEngine::isBGMEnabled() const
{
return m_bgmEnabled;
}
bool AudioEngine::isSFXEnabled() const
{
return m_sfxEnabled;
}
void AudioEngine::setBGMEnabled(bool bBGMEnabled)
{
m_bgmEnabled = bBGMEnabled;
if (!m_bgmEnabled)
{
stopAllMusic();
}
}
void AudioEngine::setSFXEnabled(bool bSFXEnabled)
{
m_sfxEnabled = bSFXEnabled;
if (!bSFXEnabled)
{
stopAllSFX();
}
}
}
这部分代码用的cocos2dx的代码,cocos2dx似乎用的某个开源库,看了下,没什么好优化的。但要注意的是,android c++调用java的用法。
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
cloud::JniHelper::setJavaVM(vm); //获取JavaVM接口
return JNI_VERSION_1_4; //告知java使用什么版本的VM
}
namespace cloud {
JavaVM* JniHelper::_psJavaVM = nullptr;
void JniHelper::setJavaVM(JavaVM *javaVM) {
_psJavaVM = javaVM;
}
bool JniHelper::getEnv(JNIEnv **env) {
bool bRet = false;
do {
if (_psJavaVM->GetEnv((void**) env, JNI_VERSION_1_4) != JNI_OK) {
LOG("Failed to get the environment using GetEnv()");
break;
}
if (_psJavaVM->AttachCurrentThread(env, 0) < 0) {
LOG("Failed to get the environment using AttachCurrentThread()");
break;
}
bRet = true;
} while (0);
return bRet;
}
bool JniHelper::getStaticMethodInfo(JniMethodInfo &methodinfo,
const char *methodName, const char *paramCode) {
JNIEnv* env = nullptr;
getEnv(&env);
if(env != nullptr)
{
jclass classID = env->FindClass("com/cloudgame/org/GameJniHelper");
jmethodID java_method = env->GetStaticMethodID(
classID, methodName, paramCode);
methodinfo.env = env;
methodinfo.classID = classID;
methodinfo.methodID = java_method;
if (java_method == 0) {
return false;
}
return true;
}
else
{
return false;
}
}
}
这里的逻辑是一个进程会有一个jvm,但不同线程有不同的JNIEnv。
JNI_Load 是java调用System.loadLibrary("cloudGameEngine_share");时首次加载的地方。
findclass,getstaticMethodInfo,得到java中的函数。
至此,2d游戏引擎的底层架构已经完全实现,除了点击,(稍后做放到eglView中去)。接下来就是开发者会密切调用到的一些功能块的设计了。