/** @file JSAudio.cpp @brief @author James @version 1.0 @date 2014_11_26 */ //包含头文件 #include "JSAudio.h" #include "../JSInterface/JSInterface.h" #include #include #include #include #include #include #include #include #include #include "JSFile.h" #include "../../JCScriptRuntime.h" #include #include #include "../../Audio/JCAudioManager.h" namespace laya { ADDJSCLSINFO(JSAudio, JSObjNode); //为了确保mp3只被写入文件一次 std::map ms_vSaveMp3File; //------------------------------------------------------------------------------ JSAudio::JSAudio() { m_nCurrentTime = 0; m_bNeedHandlePlay = false; m_nType = -1; m_bAutoPlay = false; m_bLoop = false; m_bMuted = false; m_nVolume = 1; m_sSrc = ""; m_sLocalFileName = ""; m_bIsOgg = false; m_bDownloaded = false; m_pOpenALInfo = NULL; AdjustAmountOfExternalAllocatedMemory( 534 ); JCMemorySurvey::GetInstance()->newClass( "audio",534,this ); m_CallbackRef.reset(new int(1)); } //------------------------------------------------------------------------------ JSAudio::~JSAudio() { JCMemorySurvey::GetInstance()->releaseClass( "audio",this ); JCAudioManager::GetInstance()->delWav(this); JCAudioManager::GetInstance()->delMp3Obj(this); } //------------------------------------------------------------------------------ void JSAudio::addEventListener( const char* p_sName, JSValueAsParam p_pFunction ) { if( strcmp( p_sName,"ended" ) == 0 ) { m_pJSFunctionAudioEnd.set(0,this,p_pFunction); } else if(strcmp(p_sName,"canplaythrough")==0) { m_pJSFunctionCanPlay.set(1,this,p_pFunction); } else if (strcmp(p_sName, "error") == 0) { m_pJSFunctionError.set(2, this, p_pFunction); } else { LOGW("JSAudio::addEventListener(%s)尚未支持",p_sName ); } } //------------------------------------------------------------------------------ void JSAudio::setAutoPlay( bool p_bAutoPlay ) { m_bAutoPlay = p_bAutoPlay; } //------------------------------------------------------------------------------ bool JSAudio::getAutoPlay() { return m_bAutoPlay; } //------------------------------------------------------------------------------ void JSAudio::setLoop( bool p_bLoop ) { m_bLoop = p_bLoop; } //------------------------------------------------------------------------------ bool JSAudio::getLoop() { return m_bLoop; } //------------------------------------------------------------------------------ void JSAudio::setMuted( bool p_bMuted ) { m_bMuted = p_bMuted; if( m_nType == 0 ) { JCAudioManager::GetInstance()->setMp3Mute( m_bMuted ); } else if( m_nType == 1 ) { if (m_pOpenALInfo && m_pOpenALInfo->m_pAudio == this) { JCAudioManager::GetInstance()->setWavVolume(m_pOpenALInfo, m_bMuted ? 0 : m_nVolume); } } } //------------------------------------------------------------------------------ bool JSAudio::getMuted() { return m_bMuted; } //------------------------------------------------------------------------------ void JSAudio::setSrc( const char* p_sSrc ) { //如果和原来播放的一样,直接播放就行了 std::string sSrc = p_sSrc; if( m_sSrc == sSrc ) { std::weak_ptr cbref(m_CallbackRef); auto pFunction = std::bind(&JSAudio::onCanplayCallJSFunction,this, cbref); JCScriptRuntime::s_JSRT->m_pPoster->postToJS( pFunction ); if( m_bAutoPlay == true ) { //直接播放 play(); } return; } //这段是第一次播放此音乐,先下载走正规流程 m_sSrc = sSrc; //为了android m_sSrc.at(0) = m_sSrc.at(0); //这段代码是查找,是否在缓存中已经有此音乐了,直接找到播放 JCWaveInfo* pWavInfo = JCAudioManager::GetInstance()->FindWaveInfo( p_sSrc ); if( pWavInfo != NULL ) { m_nType = 1; m_bDownloaded = true; std::weak_ptr cbref(m_CallbackRef); std::function pFunction = std::bind(&JSAudio::onCanplayCallJSFunction,this, cbref); JCScriptRuntime::s_JSRT->m_pPoster->postToJS( pFunction ); if( m_bAutoPlay == true ) { play(); } return; } //去掉?后面的,因为可能增加版本号 std::string sTemp = m_sSrc; int p3 = sTemp.rfind('?'); //去下载文件 char* sT = (char*)(sTemp.c_str()); if( p3 != -1 ) { sT[p3]=0; } char* sExtName = (char*)( getExtName( LayaStrlwr( sT ) ) ); if( strcmp( sExtName,"mp3") == 0 ) { m_nType = 0; } else if( strcmp( sExtName,"wav") == 0 ) { m_nType = 1; m_bIsOgg = false; } else if( strcmp( sExtName,"ogg") == 0 ) { m_nType = 1; m_bIsOgg = true; } else { m_nType = -1; LOGW("JSAudio::setSrc extname != mp3 && extname != wav && exname != ogg"); return; } if(m_nType==0) { //必须确保 如果是mp3必须每次都new JSAudio这个类,否则会出问题 //临时用的这种办法,现在不好,因为有二次写文件的事情。。 //TODO以后得修改 std::map::iterator iter = ms_vSaveMp3File.find( m_sSrc ); if( iter == ms_vSaveMp3File.end() ) { laya::JCFileRes* res = JCScriptRuntime::s_JSRT->m_pFileResMgr->getRes(m_sSrc); std::weak_ptr cbref(m_CallbackRef); res->setOnReadyCB( std::bind(&JSAudio::onDownloaded,this, std::placeholders::_1,cbref)); res->setOnErrorCB(std::bind(&JSAudio::onDownloadErr, this, std::placeholders::_1, std::placeholders::_2, cbref)); } else { m_sLocalFileName = iter->second; if(fs::exists(m_sLocalFileName.c_str())) { m_bDownloaded = true; std::weak_ptr cbref(m_CallbackRef); auto pFunction = std::bind(&JSAudio::onCanplayCallJSFunction,this, cbref); JCScriptRuntime::s_JSRT->m_pPoster->postToJS( pFunction ); if( m_nType == 0 ) { if( m_bAutoPlay || m_bNeedHandlePlay == true ) { m_bNeedHandlePlay = false; play(); } } } else { LOGW("JSAudio::setSrc music 当前文件不存在,%s",m_sLocalFileName.c_str()); ms_vSaveMp3File.erase(iter); laya::JCFileRes* res = JCScriptRuntime::s_JSRT->m_pFileResMgr->getRes(m_sSrc); std::weak_ptr cbref(m_CallbackRef); res->setOnReadyCB( std::bind(&JSAudio::onDownloaded,this, std::placeholders::_1,cbref)); res->setOnErrorCB(std::bind(&JSAudio::onDownloadErr, this, std::placeholders::_1, std::placeholders::_2, cbref)); } } } else { laya::JCFileRes* res = JCScriptRuntime::s_JSRT->m_pFileResMgr->getRes(m_sSrc); std::weak_ptr cbref(m_CallbackRef); res->setOnReadyCB( std::bind(&JSAudio::onDownloaded,this, std::placeholders::_1,cbref)); res->setOnErrorCB( std::bind(&JSAudio::onDownloadErr,this,std::placeholders::_1,std::placeholders::_2,cbref)); } } //------------------------------------------------------------------------------ bool JSAudio::onDownloadErr(void* p_pRes, int p_nErrCode,std::weak_ptr callbackref) { if (!callbackref.lock())return false; auto pFunction = std::bind(&JSAudio::onErrorCallJSFunction, this, p_nErrCode,callbackref); JCScriptRuntime::s_JSRT->m_pPoster->postToJS(pFunction); return true; } bool JSAudio::onDownloaded(void* p_pRes, std::weak_ptr callbackref) { if( !callbackref.lock() )return false; laya::JCResStateDispatcher* pRes = (laya::JCResStateDispatcher*)p_pRes; laya::JCFileRes* pFileRes = (laya::JCFileRes*)pRes; if( pFileRes->m_pBuffer.get()==NULL || pFileRes->m_nLength==0 ) { return false; } JCBuffer p_buf; p_buf.m_pPtr=pFileRes->m_pBuffer.get(); p_buf.m_nLen = pFileRes->m_nLength; m_bDownloaded = true; // std::weak_ptr cbref(m_CallbackRef); //std::function pFunction = std::bind(&JSAudio::onCanplayCallJSFunction,this, callbackref); auto pFunction = std::bind(&JSAudio::onCanplayCallJSFunction, this, callbackref); JCScriptRuntime::s_JSRT->m_pPoster->postToJS( pFunction ); if( m_nType == 0 ) { //必须确保 如果是mp3必须每次都new JSAudio这个类,否则会出问题 //临时用的这种办法,现在不好,因为有二次写文件的事情。。 //TODO以后得修改 std::map::iterator iter = ms_vSaveMp3File.find( m_sSrc ); if( iter != ms_vSaveMp3File.end() ) { m_sLocalFileName = iter->second; } else { int p1 = m_sSrc.rfind('/'); int p2 = m_sSrc.rfind('\\'); int pos = std::max(p1,p2); std::string audiofile = m_sSrc.substr(pos+1,m_sSrc.length()); //去掉?后面的,因为可能增加版本号 int p3 = audiofile.rfind('?'); char* sT = (char*)(audiofile.c_str()); if( p3 != -1 ) { sT[p3]=0; } unsigned int hash = JCCachedFileSys::hashRaw(m_sSrc.c_str()); char tmpBuf[32]; sprintf(tmpBuf, "%x_", hash); m_sLocalFileName =JCScriptRuntime::s_JSRT->m_pFileResMgr->m_pFileCache->getAppPath()+"/"+ tmpBuf +audiofile; writeFileSync(m_sLocalFileName.c_str(),p_buf); ms_vSaveMp3File[m_sSrc] = m_sLocalFileName; } } if( m_nType == 0 ) { if( m_bAutoPlay || m_bNeedHandlePlay == true ) { m_bNeedHandlePlay = false; play(); } } else if( m_nType == 1 ) { JCAudioManager::GetInstance()->AddWaveInfo( m_sSrc,p_buf,(int)(p_buf.m_nLen),this,m_bIsOgg ); if( m_bAutoPlay || m_bNeedHandlePlay == true ) { m_bNeedHandlePlay = false; play(); } } return true; } //------------------------------------------------------------------------------ const char* JSAudio::getSrc() { return m_sSrc.c_str(); } //------------------------------------------------------------------------------ void JSAudio::setVolume( float p_nVolume ) { if (p_nVolume > 1)p_nVolume = 1; if (p_nVolume < 0)p_nVolume = 0; m_nVolume = p_nVolume; if( m_nType == 0 ) { JCAudioManager::GetInstance()->setMp3Volume( m_nVolume ); } else if( m_nType == 1 ) { if (m_pOpenALInfo && m_pOpenALInfo->m_pAudio == this) { JCAudioManager::GetInstance()->setWavVolume(m_pOpenALInfo,m_nVolume); } } } //------------------------------------------------------------------------------ float JSAudio::getVolume() { return m_nVolume; } //------------------------------------------------------------------------------ void JSAudio::play() { //if (m_bMuted)return; if( m_bDownloaded == false ) { m_bNeedHandlePlay = true; return; } if( m_nType == 0 ) { JCAudioManager::GetInstance()->stopMp3(); if( m_sLocalFileName.length() > 0 ) { JCAudioManager::GetInstance()->playMp3( m_sLocalFileName.c_str(),m_bLoop?-1:0,(int)m_nCurrentTime,this ); } else { JCAudioManager::GetInstance()->playMp3( m_sSrc.c_str(),m_bLoop?-1:0,(int)m_nCurrentTime,this ); } } else if( m_nType == 1 ) { m_pOpenALInfo = JCAudioManager::GetInstance()->playWav( this,m_sSrc, m_bIsOgg); if (m_pOpenALInfo) { JCAudioManager::GetInstance()->setWavVolume(m_pOpenALInfo, m_nVolume); } } } //------------------------------------------------------------------------------ void JSAudio::pause() { if( m_nType == 0 ) { m_nCurrentTime = JCAudioManager::GetInstance()->getCurrentTime(); JCAudioManager::GetInstance()->pauseMp3(); } else { if (m_pOpenALInfo && m_pOpenALInfo->m_pAudio == this) { JCAudioManager::GetInstance()->stopWav(m_pOpenALInfo); m_pOpenALInfo = NULL; } } } //------------------------------------------------------------------------------ void JSAudio::stop() { if( m_nType == 0 ) { JCAudioManager::GetInstance()->stopMp3(); } else { if (m_pOpenALInfo && m_pOpenALInfo->m_pAudio == this) { JCAudioManager::GetInstance()->stopWav(m_pOpenALInfo); m_pOpenALInfo = NULL; } } } void JSAudio::setCurrentTime(double nCurrentTime) { m_nCurrentTime = nCurrentTime; if( m_nType == 0 ) { //JCAudioManager::GetInstance()->setCurrentTime(nCurrentTime); } else { } } double JSAudio::getCurrentTime() { if( m_nType == 0 ) { return JCAudioManager::GetInstance()->getCurrentTime(); } else { return 0.0f; } } double JSAudio::getDuration() { if( m_nType == 0 ) { return JCAudioManager::GetInstance()->getDuration(); } else { return 0.0f; } } //------------------------------------------------------------------------------ void JSAudio::onPlayEnd() { std::weak_ptr cbref(m_CallbackRef); auto pFunction = std::bind(&JSAudio::onPlayEndCallJSFunction,this, cbref); JCScriptRuntime::s_JSRT->m_pPoster->postToJS( pFunction ); } //------------------------------------------------------------------------------ void JSAudio::onPlayEndCallJSFunction( std::weak_ptr callbackref) { if( !callbackref.lock())return; m_pJSFunctionAudioEnd.Call(); } //------------------------------------------------------------------------------ void JSAudio::onCanplayCallJSFunction( std::weak_ptr callbackref) { if( !callbackref.lock()) return; m_pJSFunctionCanPlay.Call(); } void JSAudio::onErrorCallJSFunction(int p_nErrorCode,std::weak_ptr callbackref) { if (!callbackref.lock())return; m_pJSFunctionError.Call(p_nErrorCode); } void JSAudio::exportJS() { JSP_CLASS("ConchAudio",JSAudio); JSP_ADD_PROPERTY(autoplay, JSAudio, getAutoPlay, setAutoPlay); JSP_ADD_PROPERTY(loop, JSAudio, getLoop, setLoop); JSP_ADD_PROPERTY(muted, JSAudio, getMuted, setMuted); JSP_ADD_PROPERTY(src, JSAudio, getSrc, setSrc); JSP_ADD_PROPERTY(volume, JSAudio, getVolume, setVolume); JSP_ADD_PROPERTY(currentTime, JSAudio, getCurrentTime, setCurrentTime); JSP_ADD_METHOD("setLoop", JSAudio::setLoop); JSP_ADD_METHOD("play", JSAudio::play); JSP_ADD_METHOD("pause", JSAudio::pause); JSP_ADD_METHOD("stop", JSAudio::stop); JSP_ADD_METHOD("addEventListener", JSAudio::addEventListener); JSP_ADD_PROPERTY_RO(duration, JSAudio, getDuration) JSP_INSTALL_CLASS("ConchAudio", JSAudio); } } //------------------------------------------------------------------------------ //-----------------------------END FILE--------------------------------