123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337 |
- /**
- * @author cesarpachon
- */
- #include <cstring>
- #include <cstdint>
- #include "audio/linux/AudioEngine-linux.h"
- #include "base/CCDirector.h"
- #include "base/CCScheduler.h"
- #include "platform/CCFileUtils.h"
- using namespace cocos2d;
- using namespace cocos2d::experimental;
- AudioEngineImpl * g_AudioEngineImpl = nullptr;
- void ERRCHECKWITHEXIT(FMOD_RESULT result)
- {
- if (result != FMOD_OK) {
- printf("FMOD error! (%d) %s\n", result, FMOD_ErrorString(result));
- }
- }
- bool ERRCHECK(FMOD_RESULT result)
- {
- if (result != FMOD_OK) {
- printf("FMOD error! (%d) %s\n", result, FMOD_ErrorString(result));
- return true;
- }
- return false;
- }
- FMOD_RESULT F_CALLBACK channelCallback(FMOD_CHANNELCONTROL *channelcontrol,
- FMOD_CHANNELCONTROL_TYPE controltype,
- FMOD_CHANNELCONTROL_CALLBACK_TYPE callbacktype,
- void *commandData1, void *commandData2)
- {
- if (controltype == FMOD_CHANNELCONTROL_CHANNEL && callbacktype == FMOD_CHANNELCONTROL_CALLBACK_END) {
- g_AudioEngineImpl->onSoundFinished((FMOD::Channel *)channelcontrol);
- }
- return FMOD_OK;
- }
- AudioEngineImpl::AudioEngineImpl()
- {
- }
- AudioEngineImpl::~AudioEngineImpl()
- {
- FMOD_RESULT result;
- result = pSystem->close();
- ERRCHECKWITHEXIT(result);
- result = pSystem->release();
- ERRCHECKWITHEXIT(result);
- }
- bool AudioEngineImpl::init()
- {
- FMOD_RESULT result;
- /*
- Create a System object and initialize.
- */
- result = FMOD::System_Create(&pSystem);
- ERRCHECKWITHEXIT(result);
- result = pSystem->setOutput(FMOD_OUTPUTTYPE_AUTODETECT);
- ERRCHECKWITHEXIT(result);
- result = pSystem->init(32, FMOD_INIT_NORMAL, 0);
- ERRCHECKWITHEXIT(result);
- mapChannelInfo.clear();
- mapSound.clear();
- auto scheduler = cocos2d::Director::getInstance()->getScheduler();
- scheduler->schedule(schedule_selector(AudioEngineImpl::update), this, 0.05f, false);
- g_AudioEngineImpl = this;
- return true;
- }
- int AudioEngineImpl::play2d(const std::string &fileFullPath, bool loop, float volume)
- {
- int id = preload(fileFullPath, nullptr);
- if (id >= 0) {
- mapChannelInfo[id].loop=loop;
- mapChannelInfo[id].channel->setPaused(true);
- mapChannelInfo[id].volume = volume;
- AudioEngine::_audioIDInfoMap[id].state = AudioEngine::AudioState::PAUSED;
- resume(id);
- }
- return id;
- }
- void AudioEngineImpl::setVolume(int audioID, float volume)
- {
- try {
- mapChannelInfo[audioID].channel->setVolume(volume);
- }
- catch (const std::out_of_range& oor) {
- printf("AudioEngineImpl::setVolume: invalid audioID: %d\n", audioID);
- }
- }
- void AudioEngineImpl::setLoop(int audioID, bool loop)
- {
- try {
- mapChannelInfo[audioID].channel->setLoopCount(loop ? -1 : 0);
- }
- catch (const std::out_of_range& oor) {
- printf("AudioEngineImpl::setLoop: invalid audioID: %d\n", audioID);
- }
- }
- bool AudioEngineImpl::pause(int audioID)
- {
- try {
- mapChannelInfo[audioID].channel->setPaused(true);
- AudioEngine::_audioIDInfoMap[audioID].state = AudioEngine::AudioState::PAUSED;
- return true;
- }
- catch (const std::out_of_range& oor) {
- printf("AudioEngineImpl::pause: invalid audioID: %d\n", audioID);
- return false;
- }
- }
- bool AudioEngineImpl::resume(int audioID)
- {
- try {
- if (!mapChannelInfo[audioID].channel) {
- FMOD::Channel *channel = nullptr;
- FMOD::ChannelGroup *channelgroup = nullptr;
- //starts the sound in pause mode, use the channel to unpause
- FMOD_RESULT result = pSystem->playSound(mapChannelInfo[audioID].sound, channelgroup, true, &channel);
- if (ERRCHECK(result)) {
- return false;
- }
- channel->setMode(mapChannelInfo[audioID].loop ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF);
- channel->setLoopCount(mapChannelInfo[audioID].loop ? -1 : 0);
- channel->setVolume(mapChannelInfo[audioID].volume);
- channel->setUserData(reinterpret_cast<void *>(static_cast<std::intptr_t>(mapChannelInfo[audioID].id)));
- mapChannelInfo[audioID].channel = channel;
- }
- mapChannelInfo[audioID].channel->setPaused(false);
- AudioEngine::_audioIDInfoMap[audioID].state = AudioEngine::AudioState::PLAYING;
- return true;
- }
- catch (const std::out_of_range& oor) {
- printf("AudioEngineImpl::resume: invalid audioID: %d\n", audioID);
- return false;
- }
- }
- bool AudioEngineImpl::stop(int audioID)
- {
- try {
- mapChannelInfo[audioID].channel->stop();
- mapChannelInfo[audioID].channel = nullptr;
- return true;
- }
- catch (const std::out_of_range& oor) {
- printf("AudioEngineImpl::stop: invalid audioID: %d\n", audioID);
- return false;
- }
- }
- void AudioEngineImpl::stopAll()
- {
- for (auto& it : mapChannelInfo) {
- ChannelInfo & audioRef = it.second;
- audioRef.channel->stop();
- audioRef.channel = nullptr;
- }
- }
- float AudioEngineImpl::getDuration(int audioID)
- {
- try {
- FMOD::Sound * sound = mapChannelInfo[audioID].sound;
- unsigned int length;
- FMOD_RESULT result = sound->getLength(&length, FMOD_TIMEUNIT_MS);
- ERRCHECK(result);
- float duration = (float)length / 1000.0f;
- return duration;
- }
- catch (const std::out_of_range& oor) {
- printf("AudioEngineImpl::getDuration: invalid audioID: %d\n", audioID);
- return AudioEngine::TIME_UNKNOWN;
- }
- }
- float AudioEngineImpl::getCurrentTime(int audioID)
- {
- try {
- unsigned int position;
- FMOD_RESULT result = mapChannelInfo[audioID].channel->getPosition(&position, FMOD_TIMEUNIT_MS);
- ERRCHECK(result);
- float currenttime = position /1000.0f;
- return currenttime;
- }
- catch (const std::out_of_range& oor) {
- printf("AudioEngineImpl::getCurrentTime: invalid audioID: %d\n", audioID);
- return AudioEngine::TIME_UNKNOWN;
- }
- }
- bool AudioEngineImpl::setCurrentTime(int audioID, float time)
- {
- bool ret = false;
- try {
- unsigned int position = (unsigned int)(time * 1000.0f);
- FMOD_RESULT result = mapChannelInfo[audioID].channel->setPosition(position, FMOD_TIMEUNIT_MS);
- ret = !ERRCHECK(result);
- }
- catch (const std::out_of_range& oor) {
- printf("AudioEngineImpl::setCurrentTime: invalid audioID: %d\n", audioID);
- }
- return ret;
- }
- void AudioEngineImpl::setFinishCallback(int audioID, const std::function<void (int, const std::string &)> &callback)
- {
- try {
- FMOD::Channel * channel = mapChannelInfo[audioID].channel;
- mapChannelInfo[audioID].callback = callback;
- FMOD_RESULT result = channel->setCallback(channelCallback);
- ERRCHECK(result);
- }
- catch (const std::out_of_range& oor) {
- printf("AudioEngineImpl::setFinishCallback: invalid audioID: %d\n", audioID);
- }
- }
- void AudioEngineImpl::onSoundFinished(FMOD::Channel * channel)
- {
- int id = 0;
- try {
- void * data;
- channel->getUserData(&data);
- id = static_cast<int>(reinterpret_cast<std::intptr_t>(data));
- if (mapChannelInfo[id].callback) {
- mapChannelInfo[id].callback(id, mapChannelInfo[id].path);
- }
- mapChannelInfo[id].channel = nullptr;
- }
- catch (const std::out_of_range& oor) {
- printf("AudioEngineImpl::onSoundFinished: invalid audioID: %d\n", id);
- }
- }
- void AudioEngineImpl::uncache(const std::string& path)
- {
- std::string fullPath = FileUtils::getInstance()->fullPathForFilename(path);
- std::map<std::string, FMOD::Sound *>::const_iterator it = mapSound.find(fullPath);
- if (it!=mapSound.end()) {
- FMOD::Sound * sound = it->second;
- if (sound) {
- sound->release();
- }
- mapSound.erase(it);
- }
- if (mapId.find(path) != mapId.end())
- mapId.erase(path);
- }
- void AudioEngineImpl::uncacheAll()
- {
- for (const auto& it : mapSound) {
- auto sound = it.second;
- if (sound) {
- sound->release();
- }
- }
- mapSound.clear();
- mapId.clear();
- }
- int AudioEngineImpl::preload(const std::string& filePath, std::function<void(bool isSuccess)> callback)
- {
- FMOD::Sound * sound = findSound(filePath);
- if (!sound) {
- std::string fullPath = FileUtils::getInstance()->fullPathForFilename(filePath);
- FMOD_RESULT result = pSystem->createSound(fullPath.c_str(), FMOD_LOOP_OFF, 0, &sound);
- if (ERRCHECK(result)) {
- printf("sound effect in %s could not be preload\n", filePath.c_str());
- if (callback) {
- callback(false);
- }
- return -1;
- }
- mapSound[fullPath] = sound;
- }
- int id = static_cast<int>(mapChannelInfo.size()) + 1;
- if (mapId.find(filePath) == mapId.end())
- mapId.insert({filePath, id});
- else
- id = mapId.at(filePath);
- auto& chanelInfo = mapChannelInfo[id];
- chanelInfo.sound = sound;
- chanelInfo.id = id;
- chanelInfo.channel = nullptr;
- chanelInfo.callback = nullptr;
- chanelInfo.path = filePath;
- //we are going to use UserData to store pointer to Channel when playing
- chanelInfo.sound->setUserData(reinterpret_cast<void *>(static_cast<std::intptr_t>(id)));
- if (callback) {
- callback(true);
- }
- return id;
- }
- void AudioEngineImpl::update(float dt)
- {
- pSystem->update();
- }
- FMOD::Sound * AudioEngineImpl::findSound(const std::string &path)
- {
- std::string fullPath = FileUtils::getInstance()->fullPathForFilename(path);
- std::map<std::string, FMOD::Sound *>::const_iterator it = mapSound.find(fullPath);
- return (it != mapSound.end()) ? (it->second) : nullptr;
- }
- FMOD::Channel * AudioEngineImpl::getChannel(FMOD::Sound *sound)
- {
- void * data;
- sound->getUserData(&data);
- int id = static_cast<int>(reinterpret_cast<std::intptr_t>(data));
- return mapChannelInfo[id].channel;
- }
|