#include "SimpleAudioEngine.h" #include #include #include #include #include #include #include #include #include using namespace std; using namespace Osp::Media; using namespace Osp::System; using namespace Osp::Base::Runtime; using namespace Osp::Base::Collection; #define BREAK_IF(cond) if (cond) break; namespace CocosDenshion { #define MAX_BUFFER_SIZE 2520 // 840 byte typedef map EffectList; typedef pair Effect; static SimpleAudioEngine *s_pSharedAudioEngine = NULL; static Player *s_pBackPlayer = NULL; static EffectList s_List; static float s_fBackgroundMusicVolume = 1.0f; static float s_fEffectsVolume = 1.0f; static bool s_bWillPlayBackgroundMusic = false; static string s_strResourcePath = "/Res/"; static unsigned int _Hash(const char *key) { unsigned int len = strlen(key); const char *end=key+len; unsigned int hash; for (hash = 0; key < end; key++) { hash *= 16777619; hash ^= (unsigned int) (unsigned char) toupper(*key); } return (hash); } class MyPlayerEventListener : public IPlayerEventListener { public: /** * Notifies that audio/video content was opened asynchronously. * * @param[in] r The cause of the error * @exception E_SUCCESS The method was successful. * @exception E_SYSTEM A system error occurred. * @exception E_CONNECTION_FAILED Network connection failed. * @exception E_UNSUPPORTED_FORMAT The specified format is not supported. * @exception E_UNSUPPORTED_CODEC The specified codec is not supported. * @exception E_OUT_OF_MEMORY Insufficient memory. * @see Player::OpenFile(), Player::OpenUrl(), Player::OpenBuffer() */ virtual void OnPlayerOpened( result r ) { AppLog("OnPlayerOpened"); } /** * Notifies that the Player has reached the end of the clip. * */ virtual void OnPlayerEndOfClip(void) { AppLog("OnPlayerEndOfClip"); } /** * Notifies that the position of the audio/video content was moved asynchronously. * * @exception E_SUCCESS The method was successful. * @exception E_SYSTEM A system error occurred. * @see Player::SeekTo() */ virtual void OnPlayerSeekCompleted( result r ) { AppLog("OnPlayerSeekCompleted"); } /** * Notifies that streaming data is being buffered. * * @param[in] percent The percentage of buffering completed * @see Player::OpenUrl() */ virtual void OnPlayerBuffering(int percent) { AppLog("OnPlayerBuffering"); } /** * Notifies that an error has occurred while the Player is working. * * @param[in] r A player error reason of type ::PlayerErrorReason * @remark While playing streaming media, the player might throw an error like ::PLAYER_ERROR_CONNECTION_LOST @n * ::PLAYER_ERROR_STREAMING_TIMEOUT, ::PLAYER_ERROR_TRANSPORT or ::PLAYER_ERROR_SERVER. @n * If the content includes invalid data, ::PLAYER_ERROR_INVALID_DATA may occur. * @see PlayerErrorReason */ virtual void OnPlayerErrorOccurred( PlayerErrorReason r ) { AppLog("OnPlayerErrorOccurred"); } /** * Notifies that the Player is being interrupted by a task of higher priority than Player. * */ virtual void OnPlayerInterrupted(void) { //Insert your code here AppLog("OnPlayerInterrupted"); if (s_pBackPlayer->GetState() == PLAYER_STATE_PLAYING) s_pBackPlayer->Pause(); } /** * Notifies that the interrupting Player has been released. * */ virtual void OnPlayerReleased(void) { //Insert your code here AppLog("OnPlayerReleased"); if (s_pBackPlayer->GetState() != PLAYER_STATE_PLAYING) s_pBackPlayer->Play(); } }; static MyPlayerEventListener s_playerListener; static void closeMediaPlayer(Player*& pPlayer) { if (pPlayer != NULL) { PlayerState nowState = pPlayer->GetState(); if( nowState == PLAYER_STATE_PLAYING || nowState == PLAYER_STATE_PAUSED ) { pPlayer->Stop(); pPlayer->Close(); AppLog("audio player closed"); } else if(nowState == PLAYER_STATE_OPENED || nowState == PLAYER_STATE_ENDOFCLIP || nowState == PLAYER_STATE_STOPPED ) { pPlayer->Close(); AppLog("audio player closed"); } } } static bool openMediaPlayer(Player*& pPlayer, const char* pszFilePath, bool bLoop) { bool bRet = false; result r = E_FAILURE; do { closeMediaPlayer(pPlayer); if (pPlayer == NULL) { pPlayer = new Player(); r = pPlayer->Construct(s_playerListener, null); if (IsFailed(r)) { AppLog("player construct fails, pszFilePath = %s", pszFilePath); delete pPlayer; pPlayer = NULL; break; } } string strFilePath = s_strResourcePath+pszFilePath; // OpenFile must use synchronous param, for after that it will playing. r = pPlayer->OpenFile(strFilePath.c_str(), false); if (IsFailed(r)) { AppLog("Open (%s) fails\n", strFilePath.c_str()); delete pPlayer; pPlayer = NULL; break; } else { pPlayer->SetLooping(bLoop); bRet = true; } } while (0); return bRet; } SimpleAudioEngine::SimpleAudioEngine() { } SimpleAudioEngine::~SimpleAudioEngine() { AppLog("destroy SimpleAudioEngine"); for (EffectList::iterator it = s_List.begin(); it != s_List.end(); ++it) { closeMediaPlayer(it->second); delete it->second; } s_List.clear(); closeMediaPlayer(s_pBackPlayer); delete s_pBackPlayer; s_pBackPlayer = NULL; } SimpleAudioEngine* SimpleAudioEngine::sharedEngine() { if (s_pSharedAudioEngine == NULL) { s_pSharedAudioEngine = new SimpleAudioEngine; } return s_pSharedAudioEngine; } void SimpleAudioEngine::end() { if (s_pSharedAudioEngine) { delete s_pSharedAudioEngine; s_pSharedAudioEngine = NULL; } } void SimpleAudioEngine::setResource(const char* pszZipFileName) { } void SimpleAudioEngine::setResourcePath(const char *pszResourcePath) { s_strResourcePath = pszResourcePath; } void SimpleAudioEngine::preloadBackgroundMusic(const char* pszFilePath) { } void SimpleAudioEngine::playBackgroundMusic(const char* pszFilePath, bool bLoop) { result r = E_FAILURE; bool bRet = false; bRet = openMediaPlayer(s_pBackPlayer, pszFilePath, bLoop); setBackgroundMusicVolume(s_fBackgroundMusicVolume); if (bRet && s_fBackgroundMusicVolume > 0.0f) { r = s_pBackPlayer->Play(); } } void SimpleAudioEngine::stopBackgroundMusic(bool bReleaseData) { if (s_pBackPlayer && PLAYER_STATE_PLAYING == s_pBackPlayer->GetState()) { s_pBackPlayer->Stop(); } } void SimpleAudioEngine::pauseBackgroundMusic() { if (s_pBackPlayer && PLAYER_STATE_PLAYING == s_pBackPlayer->GetState()) { s_pBackPlayer->Pause(); } } void SimpleAudioEngine::resumeBackgroundMusic() { if (s_pBackPlayer && PLAYER_STATE_PLAYING != s_pBackPlayer->GetState()) { s_pBackPlayer->Play(); } } void SimpleAudioEngine::rewindBackgroundMusic() { if (s_pBackPlayer) { s_pBackPlayer->SeekTo(0); if (PLAYER_STATE_PLAYING != s_pBackPlayer->GetState()) { s_pBackPlayer->Play(); } } } bool SimpleAudioEngine::willPlayBackgroundMusic() { return s_bWillPlayBackgroundMusic; } bool SimpleAudioEngine::isBackgroundMusicPlaying() { bool bRet = false; if (s_pBackPlayer) { if (s_pBackPlayer->GetState() == PLAYER_STATE_PLAYING) { bRet = true; } } return bRet; } // properties float SimpleAudioEngine::getBackgroundMusicVolume() { return s_fBackgroundMusicVolume; } void SimpleAudioEngine::setBackgroundMusicVolume(float volume) { if (volume > 1.0f) { volume = 1.0f; } else if (volume < 0.0f) { volume = 0.0f; } if (s_pBackPlayer) { s_pBackPlayer->SetVolume((int) (volume * 99)); if (volume > 0.0f && s_pBackPlayer->GetVolume() == 0) { s_pBackPlayer->SetVolume(1); } } AppLog("volume = %f", volume); s_fBackgroundMusicVolume = volume; } float SimpleAudioEngine::getEffectsVolume() { return s_fEffectsVolume; } void SimpleAudioEngine::setEffectsVolume(float volume) { if (volume > 1.0f) { volume = 1.0f; } else if (volume < 0.0f) { volume = 0.0f; } s_fEffectsVolume = volume; } // for sound effects unsigned int SimpleAudioEngine::playEffect(const char* pszFilePath, bool bLoop/* = false*/) { result r = E_FAILURE; string strFilePath = s_strResourcePath+pszFilePath; unsigned int nRet = _Hash(strFilePath.c_str()); preloadEffect(pszFilePath); EffectList::iterator p = s_List.find(nRet); if (p != s_List.end()) { p->second->SetVolume((int) (s_fEffectsVolume * 99)); if (s_fEffectsVolume > 0.0f && p->second->GetVolume() == 0) { p->second->SetVolume(1); } if (PLAYER_STATE_PLAYING == p->second->GetState()) { r = p->second->Stop(); } r = p->second->Play(); if (IsFailed(r)) { AppLog("play effect fails, error code = %d", r); } } return nRet; } void SimpleAudioEngine::stopEffect(unsigned int nSoundId) { Player*& pPlayer = s_List[nSoundId]; if (pPlayer != NULL) { pPlayer->Stop(); } } void SimpleAudioEngine::preloadEffect(const char* pszFilePath) { int nRet = 0; Player* pEffectPlayer = NULL; do { BREAK_IF(! pszFilePath); string strFilePath = s_strResourcePath+pszFilePath; nRet = _Hash(strFilePath.c_str()); BREAK_IF(s_List.end() != s_List.find(nRet)); // bada only support 10 player instance, we use one for background music, other for effect music. if (s_List.size() >= 9) { // get the first effect, and remove it form list AppLog("effect preload more than 9, delete the first effect"); pEffectPlayer = s_List.begin()->second; closeMediaPlayer(pEffectPlayer); s_List.erase(s_List.begin()->first); } if (openMediaPlayer(pEffectPlayer, pszFilePath, false)) { s_List.insert(Effect(nRet, pEffectPlayer)); } } while (0); } void SimpleAudioEngine::unloadEffect(const char* pszFilePath) { string strFilePath = s_strResourcePath+pszFilePath; unsigned int nSoundId = _Hash(strFilePath.c_str()); Player*& pPlayer = s_List[nSoundId]; closeMediaPlayer(pPlayer); } } // end of namespace CocosDenshion