From 91c6b476770420b5124a50117f7f31f2aa734bdc Mon Sep 17 00:00:00 2001 From: u0u0 Date: Thu, 26 Dec 2019 16:50:44 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8E=BB=E6=8E=89audio=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cocos/CMakeLists.txt | 4 +- cocos/audio/AudioEngine.cpp | 582 ----- cocos/audio/CMakeLists.txt | 140 +- cocos/audio/RDAudio.cpp | 33 + cocos/audio/RDAudio.h | 28 + cocos/audio/android/AssetFd.cpp | 48 - cocos/audio/android/AssetFd.h | 43 - cocos/audio/android/AudioBufferProvider.h | 80 - cocos/audio/android/AudioDecoder.cpp | 294 --- cocos/audio/android/AudioDecoder.h | 64 - cocos/audio/android/AudioDecoderMp3.cpp | 83 - cocos/audio/android/AudioDecoderMp3.h | 43 - cocos/audio/android/AudioDecoderOgg.cpp | 113 - cocos/audio/android/AudioDecoderOgg.h | 46 - cocos/audio/android/AudioDecoderProvider.cpp | 93 - cocos/audio/android/AudioDecoderProvider.h | 41 - cocos/audio/android/AudioDecoderSLES.cpp | 646 ----- cocos/audio/android/AudioDecoderSLES.h | 97 - cocos/audio/android/AudioDecoderWav.cpp | 113 - cocos/audio/android/AudioDecoderWav.h | 47 - cocos/audio/android/AudioEngine-inl.cpp | 494 ---- cocos/audio/android/AudioEngine-inl.h | 107 - cocos/audio/android/AudioMixer.cpp | 2101 ----------------- cocos/audio/android/AudioMixer.h | 389 --- cocos/audio/android/AudioMixerController.cpp | 351 --- cocos/audio/android/AudioMixerController.h | 88 - cocos/audio/android/AudioMixerOps.h | 450 ---- cocos/audio/android/AudioPlayerProvider.cpp | 519 ---- cocos/audio/android/AudioPlayerProvider.h | 128 - cocos/audio/android/AudioResampler.cpp | 788 ------- cocos/audio/android/AudioResampler.h | 181 -- cocos/audio/android/AudioResamplerCubic.cpp | 191 -- cocos/audio/android/AudioResamplerCubic.h | 65 - cocos/audio/android/AudioResamplerPublic.h | 174 -- cocos/audio/android/CCThreadPool.cpp | 443 ---- cocos/audio/android/CCThreadPool.h | 237 -- cocos/audio/android/IAudioPlayer.h | 89 - cocos/audio/android/ICallerThreadUtils.h | 42 - cocos/audio/android/IVolumeProvider.h | 45 - cocos/audio/android/OpenSLHelper.h | 100 - cocos/audio/android/PcmAudioPlayer.cpp | 226 -- cocos/audio/android/PcmAudioPlayer.h | 98 - cocos/audio/android/PcmAudioService.cpp | 200 -- cocos/audio/android/PcmAudioService.h | 82 - cocos/audio/android/PcmBufferProvider.cpp | 102 - cocos/audio/android/PcmBufferProvider.h | 52 - cocos/audio/android/PcmData.cpp | 139 -- cocos/audio/android/PcmData.h | 66 - cocos/audio/android/Track.cpp | 106 - cocos/audio/android/Track.h | 107 - cocos/audio/android/UrlAudioPlayer.cpp | 424 ---- cocos/audio/android/UrlAudioPlayer.h | 135 -- cocos/audio/android/audio.h | 504 ---- cocos/audio/android/audio_utils/format.c | 183 -- .../audio_utils/include/audio_utils/format.h | 79 - .../include/audio_utils/minifloat.h | 81 - .../include/audio_utils/primitives.h | 959 -------- cocos/audio/android/audio_utils/minifloat.cpp | 70 - cocos/audio/android/audio_utils/primitives.c | 526 ----- .../android/audio_utils/private/private.h | 35 - cocos/audio/android/ccdandroidUtils.cpp | 50 - cocos/audio/android/ccdandroidUtils.h | 37 - cocos/audio/android/cutils/bitops.h | 44 - cocos/audio/android/cutils/log.h | 568 ----- cocos/audio/android/mp3reader.cpp | 542 ----- cocos/audio/android/mp3reader.h | 61 - cocos/audio/android/tinysndfile.cpp | 518 ---- cocos/audio/android/tinysndfile.h | 74 - cocos/audio/android/utils/Compat.h | 88 - cocos/audio/android/utils/Errors.h | 88 - cocos/audio/android/utils/Utils.cpp | 35 - cocos/audio/android/utils/Utils.h | 30 - cocos/audio/apple/AudioCache.h | 109 - cocos/audio/apple/AudioCache.mm | 403 ---- cocos/audio/apple/AudioDecoder.h | 120 - cocos/audio/apple/AudioDecoder.mm | 229 -- cocos/audio/apple/AudioEngine-inl.h | 86 - cocos/audio/apple/AudioEngine-inl.mm | 709 ------ cocos/audio/apple/AudioMacros.h | 65 - cocos/audio/apple/AudioPlayer.h | 90 - cocos/audio/apple/AudioPlayer.mm | 369 --- cocos/audio/include/AudioEngine.h | 372 --- cocos/audio/include/Export.h | 52 - cocos/audio/linux/AudioEngine-linux.cpp | 357 --- cocos/audio/linux/AudioEngine-linux.h | 109 - cocos/audio/win32/AudioCache.cpp | 379 --- cocos/audio/win32/AudioCache.h | 119 - cocos/audio/win32/AudioDecoder.cpp | 92 - cocos/audio/win32/AudioDecoder.h | 120 - cocos/audio/win32/AudioDecoderManager.cpp | 71 - cocos/audio/win32/AudioDecoderManager.h | 42 - cocos/audio/win32/AudioDecoderMp3.cpp | 184 -- cocos/audio/win32/AudioDecoderMp3.h | 86 - cocos/audio/win32/AudioDecoderOgg.cpp | 87 - cocos/audio/win32/AudioDecoderOgg.h | 82 - cocos/audio/win32/AudioEngine-win32.cpp | 513 ---- cocos/audio/win32/AudioEngine-win32.h | 84 - cocos/audio/win32/AudioMacros.h | 72 - cocos/audio/win32/AudioPlayer.cpp | 340 --- cocos/audio/win32/AudioPlayer.h | 90 - cocos/audio/win32/MciPlayer.cpp | 261 -- cocos/audio/win32/MciPlayer.h | 103 - .../editor-support/cocostudio/CCComAudio.cpp | 40 +- .../cocostudio/CCSSceneReader.cpp | 2 - .../editor-support/cocostudio/CMakeLists.txt | 2 - cocos/scripting/lua-bindings/CMakeLists.txt | 4 - .../auto/lua_cocos2dx_audioengine_auto.cpp | 1161 --------- .../auto/lua_cocos2dx_audioengine_auto.hpp | 47 - .../lua_cocos2dx_audioengine_manual.cpp | 317 --- .../lua_cocos2dx_audioengine_manual.h | 51 - .../manual/lua_module_register.cpp | 2 - cocos/scripting/lua-bindings/script/init.lua | 2 - tools/CreateProject.py | 1 + 113 files changed, 75 insertions(+), 23278 deletions(-) delete mode 100644 cocos/audio/AudioEngine.cpp create mode 100644 cocos/audio/RDAudio.cpp create mode 100644 cocos/audio/RDAudio.h delete mode 100644 cocos/audio/android/AssetFd.cpp delete mode 100644 cocos/audio/android/AssetFd.h delete mode 100644 cocos/audio/android/AudioBufferProvider.h delete mode 100644 cocos/audio/android/AudioDecoder.cpp delete mode 100644 cocos/audio/android/AudioDecoder.h delete mode 100644 cocos/audio/android/AudioDecoderMp3.cpp delete mode 100644 cocos/audio/android/AudioDecoderMp3.h delete mode 100644 cocos/audio/android/AudioDecoderOgg.cpp delete mode 100644 cocos/audio/android/AudioDecoderOgg.h delete mode 100644 cocos/audio/android/AudioDecoderProvider.cpp delete mode 100644 cocos/audio/android/AudioDecoderProvider.h delete mode 100644 cocos/audio/android/AudioDecoderSLES.cpp delete mode 100644 cocos/audio/android/AudioDecoderSLES.h delete mode 100644 cocos/audio/android/AudioDecoderWav.cpp delete mode 100644 cocos/audio/android/AudioDecoderWav.h delete mode 100644 cocos/audio/android/AudioEngine-inl.cpp delete mode 100644 cocos/audio/android/AudioEngine-inl.h delete mode 100644 cocos/audio/android/AudioMixer.cpp delete mode 100644 cocos/audio/android/AudioMixer.h delete mode 100644 cocos/audio/android/AudioMixerController.cpp delete mode 100644 cocos/audio/android/AudioMixerController.h delete mode 100644 cocos/audio/android/AudioMixerOps.h delete mode 100644 cocos/audio/android/AudioPlayerProvider.cpp delete mode 100644 cocos/audio/android/AudioPlayerProvider.h delete mode 100644 cocos/audio/android/AudioResampler.cpp delete mode 100644 cocos/audio/android/AudioResampler.h delete mode 100644 cocos/audio/android/AudioResamplerCubic.cpp delete mode 100644 cocos/audio/android/AudioResamplerCubic.h delete mode 100644 cocos/audio/android/AudioResamplerPublic.h delete mode 100644 cocos/audio/android/CCThreadPool.cpp delete mode 100644 cocos/audio/android/CCThreadPool.h delete mode 100644 cocos/audio/android/IAudioPlayer.h delete mode 100644 cocos/audio/android/ICallerThreadUtils.h delete mode 100644 cocos/audio/android/IVolumeProvider.h delete mode 100644 cocos/audio/android/OpenSLHelper.h delete mode 100644 cocos/audio/android/PcmAudioPlayer.cpp delete mode 100644 cocos/audio/android/PcmAudioPlayer.h delete mode 100644 cocos/audio/android/PcmAudioService.cpp delete mode 100644 cocos/audio/android/PcmAudioService.h delete mode 100644 cocos/audio/android/PcmBufferProvider.cpp delete mode 100644 cocos/audio/android/PcmBufferProvider.h delete mode 100644 cocos/audio/android/PcmData.cpp delete mode 100644 cocos/audio/android/PcmData.h delete mode 100644 cocos/audio/android/Track.cpp delete mode 100644 cocos/audio/android/Track.h delete mode 100644 cocos/audio/android/UrlAudioPlayer.cpp delete mode 100644 cocos/audio/android/UrlAudioPlayer.h delete mode 100644 cocos/audio/android/audio.h delete mode 100644 cocos/audio/android/audio_utils/format.c delete mode 100644 cocos/audio/android/audio_utils/include/audio_utils/format.h delete mode 100644 cocos/audio/android/audio_utils/include/audio_utils/minifloat.h delete mode 100644 cocos/audio/android/audio_utils/include/audio_utils/primitives.h delete mode 100644 cocos/audio/android/audio_utils/minifloat.cpp delete mode 100644 cocos/audio/android/audio_utils/primitives.c delete mode 100644 cocos/audio/android/audio_utils/private/private.h delete mode 100644 cocos/audio/android/ccdandroidUtils.cpp delete mode 100644 cocos/audio/android/ccdandroidUtils.h delete mode 100644 cocos/audio/android/cutils/bitops.h delete mode 100644 cocos/audio/android/cutils/log.h delete mode 100644 cocos/audio/android/mp3reader.cpp delete mode 100644 cocos/audio/android/mp3reader.h delete mode 100644 cocos/audio/android/tinysndfile.cpp delete mode 100644 cocos/audio/android/tinysndfile.h delete mode 100644 cocos/audio/android/utils/Compat.h delete mode 100644 cocos/audio/android/utils/Errors.h delete mode 100644 cocos/audio/android/utils/Utils.cpp delete mode 100644 cocos/audio/android/utils/Utils.h delete mode 100644 cocos/audio/apple/AudioCache.h delete mode 100644 cocos/audio/apple/AudioCache.mm delete mode 100644 cocos/audio/apple/AudioDecoder.h delete mode 100644 cocos/audio/apple/AudioDecoder.mm delete mode 100644 cocos/audio/apple/AudioEngine-inl.h delete mode 100644 cocos/audio/apple/AudioEngine-inl.mm delete mode 100644 cocos/audio/apple/AudioMacros.h delete mode 100644 cocos/audio/apple/AudioPlayer.h delete mode 100644 cocos/audio/apple/AudioPlayer.mm delete mode 100644 cocos/audio/include/AudioEngine.h delete mode 100644 cocos/audio/include/Export.h delete mode 100644 cocos/audio/linux/AudioEngine-linux.cpp delete mode 100644 cocos/audio/linux/AudioEngine-linux.h delete mode 100644 cocos/audio/win32/AudioCache.cpp delete mode 100644 cocos/audio/win32/AudioCache.h delete mode 100644 cocos/audio/win32/AudioDecoder.cpp delete mode 100644 cocos/audio/win32/AudioDecoder.h delete mode 100644 cocos/audio/win32/AudioDecoderManager.cpp delete mode 100644 cocos/audio/win32/AudioDecoderManager.h delete mode 100644 cocos/audio/win32/AudioDecoderMp3.cpp delete mode 100644 cocos/audio/win32/AudioDecoderMp3.h delete mode 100644 cocos/audio/win32/AudioDecoderOgg.cpp delete mode 100644 cocos/audio/win32/AudioDecoderOgg.h delete mode 100644 cocos/audio/win32/AudioEngine-win32.cpp delete mode 100644 cocos/audio/win32/AudioEngine-win32.h delete mode 100644 cocos/audio/win32/AudioMacros.h delete mode 100644 cocos/audio/win32/AudioPlayer.cpp delete mode 100644 cocos/audio/win32/AudioPlayer.h delete mode 100644 cocos/audio/win32/MciPlayer.cpp delete mode 100644 cocos/audio/win32/MciPlayer.h delete mode 100644 cocos/scripting/lua-bindings/auto/lua_cocos2dx_audioengine_auto.cpp delete mode 100644 cocos/scripting/lua-bindings/auto/lua_cocos2dx_audioengine_auto.hpp delete mode 100644 cocos/scripting/lua-bindings/manual/audioengine/lua_cocos2dx_audioengine_manual.cpp delete mode 100644 cocos/scripting/lua-bindings/manual/audioengine/lua_cocos2dx_audioengine_manual.h diff --git a/cocos/CMakeLists.txt b/cocos/CMakeLists.txt index 50349bf..5345992 100644 --- a/cocos/CMakeLists.txt +++ b/cocos/CMakeLists.txt @@ -76,7 +76,7 @@ set(COCOS_HEADER cocos2d.h ${COCOS_NAVMESH_HEADER} ${COCOS_RENDERER_HEADER} ${COCOS_BASE_HEADER} - ${COCOS_AUDIO_HEADER} + ${AUDIO_HEADER} ${COCOS_UI_HEADER} ${COCOS_NETWORK_HEADER} ${COCOS_EDITOR_SUPPORT_HEADER} @@ -93,7 +93,7 @@ set(COCOS_SRC cocos2d.cpp ${COCOS_NAVMESH_SRC} ${COCOS_RENDERER_SRC} ${COCOS_BASE_SRC} - ${COCOS_AUDIO_SRC} + ${AUDIO_SRC} ${COCOS_UI_SRC} ${COCOS_NETWORK_SRC} ${COCOS_EDITOR_SUPPORT_SRC} diff --git a/cocos/audio/AudioEngine.cpp b/cocos/audio/AudioEngine.cpp deleted file mode 100644 index 423b6c8..0000000 --- a/cocos/audio/AudioEngine.cpp +++ /dev/null @@ -1,582 +0,0 @@ -/**************************************************************************** - Copyright (c) 2014-2016 Chukong Technologies Inc. - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -#include "platform/CCPlatformConfig.h" - -#include "audio/include/AudioEngine.h" -#include -#include -#include "platform/CCFileUtils.h" -#include "base/ccUtils.h" - -#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID -#include "audio/android/AudioEngine-inl.h" -#elif CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_MAC -#include "audio/apple/AudioEngine-inl.h" -#elif CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 -#include "audio/win32/AudioEngine-win32.h" -#elif CC_TARGET_PLATFORM == CC_PLATFORM_LINUX -#include "audio/linux/AudioEngine-linux.h" -#endif - -#define TIME_DELAY_PRECISION 0.0001 - -#ifdef ERROR -#undef ERROR -#endif // ERROR - -using namespace cocos2d; - -const int AudioEngine::INVALID_AUDIO_ID = -1; -const float AudioEngine::TIME_UNKNOWN = -1.0f; - -//audio file path,audio IDs -std::unordered_map> AudioEngine::_audioPathIDMap; -//profileName,ProfileHelper -std::unordered_map AudioEngine::_audioPathProfileHelperMap; -unsigned int AudioEngine::_maxInstances = MAX_AUDIOINSTANCES; -AudioEngine::ProfileHelper* AudioEngine::_defaultProfileHelper = nullptr; -std::unordered_map AudioEngine::_audioIDInfoMap; -AudioEngineImpl* AudioEngine::_audioEngineImpl = nullptr; - -AudioEngine::AudioEngineThreadPool* AudioEngine::s_threadPool = nullptr; -bool AudioEngine::_isEnabled = true; - -AudioEngine::AudioInfo::AudioInfo() -: profileHelper(nullptr) -, volume(1.0f) -, loop(false) -, duration(TIME_UNKNOWN) -, state(AudioState::INITIALIZING) -{ - -} - -AudioEngine::AudioInfo::~AudioInfo() -{ -} - -class AudioEngine::AudioEngineThreadPool -{ -public: - AudioEngineThreadPool(int threads = 4) - : _stop(false) - { - _workers.reserve(threads); - for (int index = 0; index < threads; ++index) - { - _workers.emplace_back(std::bind(&AudioEngineThreadPool::threadFunc, this)); - } - } - - void addTask(const std::function &task){ - std::unique_lock lk(_queueMutex); - _taskQueue.emplace(task); - _taskCondition.notify_one(); - } - - ~AudioEngineThreadPool() - { - { - std::unique_lock lk(_queueMutex); - _stop = true; - _taskCondition.notify_all(); - } - - for (auto&& worker : _workers) { - worker.join(); - } - } - -private: - void threadFunc() - { - while (true) { - std::function task = nullptr; - { - std::unique_lock lk(_queueMutex); - if (_stop) - { - break; - } - if (!_taskQueue.empty()) - { - task = std::move(_taskQueue.front()); - _taskQueue.pop(); - } - else - { - _taskCondition.wait(lk); - continue; - } - } - - if (task) - task(); - } - } - - std::vector _workers; - std::queue< std::function > _taskQueue; - - std::mutex _queueMutex; - std::condition_variable _taskCondition; - bool _stop; -}; - -void AudioEngine::end() -{ - delete s_threadPool; - s_threadPool = nullptr; - - delete _audioEngineImpl; - _audioEngineImpl = nullptr; - - delete _defaultProfileHelper; - _defaultProfileHelper = nullptr; -} - -bool AudioEngine::lazyInit() -{ - if (_audioEngineImpl == nullptr) - { - _audioEngineImpl = new (std::nothrow) AudioEngineImpl(); - if(!_audioEngineImpl || !_audioEngineImpl->init() ){ - delete _audioEngineImpl; - _audioEngineImpl = nullptr; - return false; - } - } - -#if (CC_TARGET_PLATFORM != CC_PLATFORM_ANDROID) - if (_audioEngineImpl && s_threadPool == nullptr) - { - s_threadPool = new (std::nothrow) AudioEngineThreadPool(); - } -#endif - - return true; -} - -int AudioEngine::play2d(const std::string& filePath, bool loop, float volume, const AudioProfile *profile) -{ - int ret = AudioEngine::INVALID_AUDIO_ID; - - do { - if (!isEnabled()) - { - break; - } - - if ( !lazyInit() ){ - break; - } - - if ( !FileUtils::getInstance()->isFileExist(filePath)){ - break; - } - - auto profileHelper = _defaultProfileHelper; - if (profile && profile != &profileHelper->profile){ - CC_ASSERT(!profile->name.empty()); - profileHelper = &_audioPathProfileHelperMap[profile->name]; - profileHelper->profile = *profile; - } - - if (_audioIDInfoMap.size() >= _maxInstances) { - log("Fail to play %s cause by limited max instance of AudioEngine",filePath.c_str()); - break; - } - if (profileHelper) - { - if(profileHelper->profile.maxInstances != 0 && profileHelper->audioIDs.size() >= profileHelper->profile.maxInstances){ - log("Fail to play %s cause by limited max instance of AudioProfile",filePath.c_str()); - break; - } - if (profileHelper->profile.minDelay > TIME_DELAY_PRECISION) { - auto currTime = utils::gettime(); - if (profileHelper->lastPlayTime > TIME_DELAY_PRECISION && currTime - profileHelper->lastPlayTime <= profileHelper->profile.minDelay) { - log("Fail to play %s cause by limited minimum delay",filePath.c_str()); - break; - } - } - } - - if (volume < 0.0f) { - volume = 0.0f; - } - else if (volume > 1.0f){ - volume = 1.0f; - } - - ret = _audioEngineImpl->play2d(filePath, loop, volume); - if (ret != INVALID_AUDIO_ID) - { - _audioPathIDMap[filePath].push_back(ret); - auto it = _audioPathIDMap.find(filePath); - - auto& audioRef = _audioIDInfoMap[ret]; - audioRef.volume = volume; - audioRef.loop = loop; - audioRef.filePath = it->first; - - if (profileHelper) { - profileHelper->lastPlayTime = utils::gettime(); - profileHelper->audioIDs.push_back(ret); - } - audioRef.profileHelper = profileHelper; - } - } while (0); - - return ret; -} - -void AudioEngine::setLoop(int audioID, bool loop) -{ - auto it = _audioIDInfoMap.find(audioID); - if (it != _audioIDInfoMap.end() && it->second.loop != loop){ - _audioEngineImpl->setLoop(audioID, loop); - it->second.loop = loop; - } -} - -void AudioEngine::setVolume(int audioID, float volume) -{ - auto it = _audioIDInfoMap.find(audioID); - if (it != _audioIDInfoMap.end()){ - if (volume < 0.0f) { - volume = 0.0f; - } - else if (volume > 1.0f){ - volume = 1.0f; - } - - if (it->second.volume != volume){ - _audioEngineImpl->setVolume(audioID, volume); - it->second.volume = volume; - } - } -} - -void AudioEngine::pause(int audioID) -{ - auto it = _audioIDInfoMap.find(audioID); - if (it != _audioIDInfoMap.end() && it->second.state == AudioState::PLAYING){ - _audioEngineImpl->pause(audioID); - it->second.state = AudioState::PAUSED; - } -} - -void AudioEngine::pauseAll() -{ - auto itEnd = _audioIDInfoMap.end(); - for (auto it = _audioIDInfoMap.begin(); it != itEnd; ++it) - { - if (it->second.state == AudioState::PLAYING) - { - _audioEngineImpl->pause(it->first); - it->second.state = AudioState::PAUSED; - } - } -} - -void AudioEngine::resume(int audioID) -{ - auto it = _audioIDInfoMap.find(audioID); - if (it != _audioIDInfoMap.end() && it->second.state == AudioState::PAUSED){ - _audioEngineImpl->resume(audioID); - it->second.state = AudioState::PLAYING; - } -} - -void AudioEngine::resumeAll() -{ - auto itEnd = _audioIDInfoMap.end(); - for (auto it = _audioIDInfoMap.begin(); it != itEnd; ++it) - { - if (it->second.state == AudioState::PAUSED) - { - _audioEngineImpl->resume(it->first); - it->second.state = AudioState::PLAYING; - } - } -} - -void AudioEngine::stop(int audioID) -{ - auto it = _audioIDInfoMap.find(audioID); - if (it != _audioIDInfoMap.end()){ - _audioEngineImpl->stop(audioID); - - remove(audioID); - } -} - -void AudioEngine::remove(int audioID) -{ - auto it = _audioIDInfoMap.find(audioID); - if (it != _audioIDInfoMap.end()){ - if (it->second.profileHelper) { - it->second.profileHelper->audioIDs.remove(audioID); - } - _audioPathIDMap[it->second.filePath].remove(audioID); - _audioIDInfoMap.erase(it); - } -} - -void AudioEngine::stopAll() -{ - if(!_audioEngineImpl){ - return; - } - _audioEngineImpl->stopAll(); - auto itEnd = _audioIDInfoMap.end(); - for (auto it = _audioIDInfoMap.begin(); it != itEnd; ++it) - { - if (it->second.profileHelper){ - it->second.profileHelper->audioIDs.remove(it->first); - } - } - _audioPathIDMap.clear(); - _audioIDInfoMap.clear(); -} - -void AudioEngine::uncache(const std::string &filePath) -{ - if(!_audioEngineImpl){ - return; - } - auto audioIDsIter = _audioPathIDMap.find(filePath); - if (audioIDsIter != _audioPathIDMap.end()) - { - //@Note: For safely iterating elements from the audioID list, we need to copy the list - // since 'AudioEngine::remove' may be invoked in '_audioEngineImpl->stop' synchronously. - // If this happens, it will break the iteration, and crash will appear on some devices. - std::list copiedIDs(audioIDsIter->second); - - for (int audioID : copiedIDs) - { - _audioEngineImpl->stop(audioID); - - auto itInfo = _audioIDInfoMap.find(audioID); - if (itInfo != _audioIDInfoMap.end()) - { - if (itInfo->second.profileHelper) - { - itInfo->second.profileHelper->audioIDs.remove(audioID); - } - _audioIDInfoMap.erase(itInfo); - } - } - _audioPathIDMap.erase(filePath); - } - - _audioEngineImpl->uncache(filePath); -} - -void AudioEngine::uncacheAll() -{ - if(!_audioEngineImpl){ - return; - } - stopAll(); - _audioEngineImpl->uncacheAll(); -} - -float AudioEngine::getDuration(int audioID) -{ - auto it = _audioIDInfoMap.find(audioID); - if (it != _audioIDInfoMap.end() && it->second.state != AudioState::INITIALIZING) - { - if (it->second.duration == TIME_UNKNOWN) - { - it->second.duration = _audioEngineImpl->getDuration(audioID); - } - return it->second.duration; - } - - return TIME_UNKNOWN; -} - -bool AudioEngine::setCurrentTime(int audioID, float time) -{ - auto it = _audioIDInfoMap.find(audioID); - if (it != _audioIDInfoMap.end() && it->second.state != AudioState::INITIALIZING) { - return _audioEngineImpl->setCurrentTime(audioID, time); - } - - return false; -} - -float AudioEngine::getCurrentTime(int audioID) -{ - auto it = _audioIDInfoMap.find(audioID); - if (it != _audioIDInfoMap.end() && it->second.state != AudioState::INITIALIZING) { - return _audioEngineImpl->getCurrentTime(audioID); - } - return 0.0f; -} - -void AudioEngine::setFinishCallback(int audioID, const std::function &callback) -{ - auto it = _audioIDInfoMap.find(audioID); - if (it != _audioIDInfoMap.end()){ - _audioEngineImpl->setFinishCallback(audioID, callback); - } -} - -bool AudioEngine::setMaxAudioInstance(int maxInstances) -{ - if (maxInstances > 0 && maxInstances <= MAX_AUDIOINSTANCES) { - _maxInstances = maxInstances; - return true; - } - - return false; -} - -bool AudioEngine::isLoop(int audioID) -{ - auto tmpIterator = _audioIDInfoMap.find(audioID); - if (tmpIterator != _audioIDInfoMap.end()) - { - return tmpIterator->second.loop; - } - - log("AudioEngine::isLoop-->The audio instance %d is non-existent", audioID); - return false; -} - -float AudioEngine::getVolume(int audioID) -{ - auto tmpIterator = _audioIDInfoMap.find(audioID); - if (tmpIterator != _audioIDInfoMap.end()) - { - return tmpIterator->second.volume; - } - - log("AudioEngine::getVolume-->The audio instance %d is non-existent", audioID); - return 0.0f; -} - -AudioEngine::AudioState AudioEngine::getState(int audioID) -{ - auto tmpIterator = _audioIDInfoMap.find(audioID); - if (tmpIterator != _audioIDInfoMap.end()) - { - return tmpIterator->second.state; - } - - return AudioState::ERROR; -} - -AudioProfile* AudioEngine::getProfile(int audioID) -{ - auto it = _audioIDInfoMap.find(audioID); - if (it != _audioIDInfoMap.end()) - { - return &it->second.profileHelper->profile; - } - - return nullptr; -} - -AudioProfile* AudioEngine::getDefaultProfile() -{ - if (_defaultProfileHelper == nullptr) - { - _defaultProfileHelper = new (std::nothrow) ProfileHelper(); - } - - return &_defaultProfileHelper->profile; -} - -AudioProfile* AudioEngine::getProfile(const std::string &name) -{ - auto it = _audioPathProfileHelperMap.find(name); - if (it != _audioPathProfileHelperMap.end()) { - return &it->second.profile; - } else { - return nullptr; - } -} - -void AudioEngine::preload(const std::string& filePath, std::function callback) -{ - if (!isEnabled()) - { - callback(false); - return; - } - - lazyInit(); - - if (_audioEngineImpl) - { - if (!FileUtils::getInstance()->isFileExist(filePath)){ - if (callback) - { - callback(false); - } - return; - } - - _audioEngineImpl->preload(filePath, callback); - } -} - -void AudioEngine::addTask(const std::function& task) -{ - lazyInit(); - - if (_audioEngineImpl && s_threadPool) - { - s_threadPool->addTask(task); - } -} - -int AudioEngine::getPlayingAudioCount() -{ - return static_cast(_audioIDInfoMap.size()); -} - -void AudioEngine::setEnabled(bool isEnabled) -{ - if (_isEnabled != isEnabled) - { - _isEnabled = isEnabled; - - if (!_isEnabled) - { - stopAll(); - } - } -} - -bool AudioEngine::isEnabled() -{ - return _isEnabled; -} - diff --git a/cocos/audio/CMakeLists.txt b/cocos/audio/CMakeLists.txt index b9be171..71dbaec 100644 --- a/cocos/audio/CMakeLists.txt +++ b/cocos/audio/CMakeLists.txt @@ -1,140 +1,8 @@ -set(COCOS_AUDIO_SRC - audio/AudioEngine.cpp +set(AUDIO_SRC + audio/RDAudio.cpp ) -if(WINDOWS) - - set(COCOS_AUDIO_PLATFORM_HEADER - audio/win32/AudioDecoderManager.h - audio/win32/AudioDecoder.h - audio/win32/MciPlayer.h - audio/win32/AudioPlayer.h - audio/win32/AudioDecoderOgg.h - audio/win32/AudioMacros.h - audio/win32/AudioEngine-win32.h - audio/win32/AudioDecoderMp3.h - audio/win32/AudioCache.h - ) - - set(COCOS_AUDIO_PLATFORM_SRC - audio/win32/MciPlayer.cpp - audio/win32/MciPlayer.h - audio/win32/AudioEngine-win32.cpp - audio/win32/AudioCache.cpp - audio/win32/AudioPlayer.cpp - audio/win32/AudioDecoder.cpp - audio/win32/AudioDecoderManager.cpp - audio/win32/AudioDecoderMp3.cpp - audio/win32/AudioDecoderOgg.cpp - ) - -elseif(ANDROID) - - set(COCOS_AUDIO_PLATFORM_HEADER - audio/android/PcmAudioService.h - audio/android/AudioBufferProvider.h - audio/android/IAudioPlayer.h - audio/android/AudioResampler.h - audio/android/AudioDecoder.h - audio/android/AudioResamplerPublic.h - audio/android/AudioMixer.h - audio/android/tinysndfile.h - audio/android/mp3reader.h - audio/android/AudioMixerOps.h - audio/android/cutils/bitops.h - audio/android/cutils/log.h - audio/android/audio.h - audio/android/AudioPlayerProvider.h - audio/android/utils/Utils.h - audio/android/utils/Errors.h - audio/android/utils/Compat.h - audio/android/ccdandroidUtils.h - audio/android/AudioDecoderOgg.h - audio/android/Track.h - audio/android/OpenSLHelper.h - audio/android/PcmAudioPlayer.h - audio/android/AssetFd.h - audio/android/PcmBufferProvider.h - audio/android/CCThreadPool.h - audio/android/audio_utils/include/audio_utils/minifloat.h - audio/android/audio_utils/include/audio_utils/primitives.h - audio/android/audio_utils/include/audio_utils/format.h - audio/android/audio_utils/private/private.h - audio/android/ICallerThreadUtils.h - audio/android/AudioDecoderWav.h - audio/android/AudioDecoderProvider.h - audio/android/UrlAudioPlayer.h - audio/android/AudioDecoderSLES.h - audio/android/AudioDecoderMp3.h - audio/android/PcmData.h - audio/android/AudioMixerController.h - audio/android/AudioResamplerCubic.h - audio/android/AudioEngine-inl.h - audio/android/IVolumeProvider.h - - ) - - set(COCOS_AUDIO_PLATFORM_SRC - audio/android/ccdandroidUtils.cpp - audio/android/AudioEngine-inl.cpp - audio/android/CCThreadPool.cpp - audio/android/AssetFd.cpp - audio/android/AudioDecoder.cpp - audio/android/AudioDecoderProvider.cpp - audio/android/AudioDecoderSLES.cpp - audio/android/AudioDecoderOgg.cpp - audio/android/AudioDecoderMp3.cpp - audio/android/AudioDecoderWav.cpp - audio/android/AudioPlayerProvider.cpp - audio/android/AudioResampler.cpp - audio/android/AudioResamplerCubic.cpp - audio/android/PcmBufferProvider.cpp - audio/android/PcmAudioPlayer.cpp - audio/android/UrlAudioPlayer.cpp - audio/android/PcmData.cpp - audio/android/AudioMixerController.cpp - audio/android/AudioMixer.cpp - audio/android/PcmAudioService.cpp - audio/android/Track.cpp - audio/android/audio_utils/format.c - audio/android/audio_utils/minifloat.cpp - audio/android/audio_utils/primitives.c - audio/android/utils/Utils.cpp - audio/android/mp3reader.cpp - audio/android/tinysndfile.cpp - ) - -elseif(LINUX) - set(COCOS_AUDIO_PLATFORM_HEADER - audio/linux/AudioEngine-linux.h - ) - - set(COCOS_AUDIO_PLATFORM_SRC - audio/linux/AudioEngine-linux.h - audio/linux/AudioEngine-linux.cpp - ) - -elseif(APPLE) - # common - set(COCOS_AUDIO_PLATFORM_HEADER - audio/apple/AudioDecoder.h - audio/apple/AudioPlayer.h - audio/apple/AudioMacros.h - audio/apple/AudioCache.h - audio/apple/AudioEngine-inl.h - ) - set(COCOS_AUDIO_PLATFORM_SRC - audio/apple/AudioCache.mm - audio/apple/AudioDecoder.mm - audio/apple/AudioEngine-inl.mm - audio/apple/AudioPlayer.mm - ) -endif() - -set(COCOS_AUDIO_HEADER - audio/include/AudioEngine.h - audio/include/Export.h - ${COCOS_AUDIO_PLATFORM_HEADER} +set(AUDIO_HEADER + audio/RDAudio.h ) -list(APPEND COCOS_AUDIO_SRC ${COCOS_AUDIO_PLATFORM_SRC}) diff --git a/cocos/audio/RDAudio.cpp b/cocos/audio/RDAudio.cpp new file mode 100644 index 0000000..b7a3867 --- /dev/null +++ b/cocos/audio/RDAudio.cpp @@ -0,0 +1,33 @@ +// Copyright 2016 KeNan Liu +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include "RDAudio.h" + +RDAudio::RDAudio() +{ +} + +RDAudio::~RDAudio() +{ +} + +RDAudio *RDAudio::getInstance() +{ +} + +void RDAudio::destroyInstance() +{ +} diff --git a/cocos/audio/RDAudio.h b/cocos/audio/RDAudio.h new file mode 100644 index 0000000..d3f7bed --- /dev/null +++ b/cocos/audio/RDAudio.h @@ -0,0 +1,28 @@ +// Copyright 2016 KeNan Liu +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef __RDAudio_H__ +#define __RDAudio_H__ + +class RDAudio +{ +public: + RDAudio(); + virtual ~RDAudio(); + + static RDAudio *getInstance(); + static void destroyInstance(); +}; + +#endif // __RDAudio_H__ diff --git a/cocos/audio/android/AssetFd.cpp b/cocos/audio/android/AssetFd.cpp deleted file mode 100644 index 9d6e6a0..0000000 --- a/cocos/audio/android/AssetFd.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ - -#define LOG_TAG "AssetFd" - -#include "audio/android/cutils/log.h" -#include "audio/android/AssetFd.h" - -namespace cocos2d { - -AssetFd::AssetFd(int assetFd) - : _assetFd(assetFd) -{ -} - -AssetFd::~AssetFd() -{ - ALOGV("~AssetFd: %d", _assetFd); - if (_assetFd > 0) - { - ::close(_assetFd); - _assetFd = 0; - } -}; - -} // namespace cocos2d { diff --git a/cocos/audio/android/AssetFd.h b/cocos/audio/android/AssetFd.h deleted file mode 100644 index d380f69..0000000 --- a/cocos/audio/android/AssetFd.h +++ /dev/null @@ -1,43 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ -#pragma once - -#include - -namespace cocos2d { - -class AssetFd -{ -public: - AssetFd(int assetFd); - ~AssetFd(); - - inline int getFd() const { return _assetFd; }; -private: - int _assetFd; -}; - -} // namespace cocos2d { - diff --git a/cocos/audio/android/AudioBufferProvider.h b/cocos/audio/android/AudioBufferProvider.h deleted file mode 100644 index 8efeea6..0000000 --- a/cocos/audio/android/AudioBufferProvider.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include "audio/android/utils/Errors.h" - -namespace cocos2d { -// ---------------------------------------------------------------------------- - -class AudioBufferProvider -{ -public: - - // FIXME merge with AudioTrackShared::Buffer, AudioTrack::Buffer, and AudioRecord::Buffer - // and rename getNextBuffer() to obtainBuffer() - struct Buffer { - Buffer() : raw(NULL), frameCount(0) { } - union { - void* raw; - short* i16; - int8_t* i8; - }; - size_t frameCount; - }; - - virtual ~AudioBufferProvider() {} - - // value representing an invalid presentation timestamp - static const int64_t kInvalidPTS = 0x7FFFFFFFFFFFFFFFLL; // is too painful - - // pts is the local time when the next sample yielded by getNextBuffer - // will be rendered. - // Pass kInvalidPTS if the PTS is unknown or not applicable. - // On entry: - // buffer != NULL - // buffer->raw unused - // buffer->frameCount maximum number of desired frames - // On successful return: - // status NO_ERROR - // buffer->raw non-NULL pointer to buffer->frameCount contiguous available frames - // buffer->frameCount number of contiguous available frames at buffer->raw, - // 0 < buffer->frameCount <= entry value - // On error return: - // status != NO_ERROR - // buffer->raw NULL - // buffer->frameCount 0 - virtual status_t getNextBuffer(Buffer* buffer, int64_t pts = kInvalidPTS) = 0; - - // Release (a portion of) the buffer previously obtained by getNextBuffer(). - // It is permissible to call releaseBuffer() multiple times per getNextBuffer(). - // On entry: - // buffer->frameCount number of frames to release, must be <= number of frames - // obtained but not yet released - // buffer->raw unused - // On return: - // buffer->frameCount 0; implementation MUST set to zero - // buffer->raw undefined; implementation is PERMITTED to set to any value, - // so if caller needs to continue using this buffer it must - // keep track of the pointer itself - virtual void releaseBuffer(Buffer* buffer) = 0; -}; - -// ---------------------------------------------------------------------------- -} // namespace cocos2d { diff --git a/cocos/audio/android/AudioDecoder.cpp b/cocos/audio/android/AudioDecoder.cpp deleted file mode 100644 index 78327e4..0000000 --- a/cocos/audio/android/AudioDecoder.cpp +++ /dev/null @@ -1,294 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ - -#define LOG_TAG "AudioDecoder" - -#include "audio/android/AudioDecoder.h" -#include "audio/android/AudioResampler.h" -#include "audio/android/PcmBufferProvider.h" -#include "audio/android/AudioResampler.h" - -#include -#include -#include - -namespace cocos2d { - -size_t AudioDecoder::fileRead(void* ptr, size_t size, size_t nmemb, void* datasource) -{ - AudioDecoder* thiz = (AudioDecoder*)datasource; - ssize_t toReadBytes = std::min((ssize_t)(thiz->_fileData.getSize() - thiz->_fileCurrPos), (ssize_t)(nmemb * size)); - if (toReadBytes > 0) - { - memcpy(ptr, (unsigned char*) thiz->_fileData.getBytes() + thiz->_fileCurrPos, toReadBytes); - thiz->_fileCurrPos += toReadBytes; - } - // ALOGD("File size: %d, After fileRead _fileCurrPos %d", (int)thiz->_fileData.getSize(), thiz->_fileCurrPos); - return toReadBytes; -} - -int AudioDecoder::fileSeek(void* datasource, int64_t offset, int whence) -{ - AudioDecoder* thiz = (AudioDecoder*)datasource; - if (whence == SEEK_SET) - thiz->_fileCurrPos = offset; - else if (whence == SEEK_CUR) - thiz->_fileCurrPos = thiz->_fileCurrPos + offset; - else if (whence == SEEK_END) - thiz->_fileCurrPos = thiz->_fileData.getSize(); - return 0; -} - -int AudioDecoder::fileClose(void* datasource) -{ - return 0; -} - -long AudioDecoder::fileTell(void* datasource) -{ - AudioDecoder* thiz = (AudioDecoder*)datasource; - return (long) thiz->_fileCurrPos; -} - -AudioDecoder::AudioDecoder() - : _fileCurrPos(0), _sampleRate(-1) -{ - auto pcmBuffer = std::make_shared>(); - pcmBuffer->reserve(4096); - _result.pcmBuffer = pcmBuffer; -} - -AudioDecoder::~AudioDecoder() -{ - ALOGV("~AudioDecoder() %p", this); -} - -bool AudioDecoder::init(const std::string &url, int sampleRate) -{ - _url = url; - _sampleRate = sampleRate; - return true; -} - -bool AudioDecoder::start() -{ - auto oldTime = clockNow(); - auto nowTime = oldTime; - bool ret; - do - { - ret = decodeToPcm(); - if (!ret) - { - ALOGE("decodeToPcm (%s) failed!", _url.c_str()); - break; - } - - nowTime = clockNow(); - ALOGD("Decoding (%s) to pcm data wasted %fms", _url.c_str(), intervalInMS(oldTime, nowTime)); - oldTime = nowTime; - - ret = resample(); - if (!ret) - { - ALOGE("resample (%s) failed!", _url.c_str()); - break; - } - - nowTime = clockNow(); - ALOGD("Resampling (%s) wasted %fms", _url.c_str(), intervalInMS(oldTime, nowTime)); - oldTime = nowTime; - - ret = interleave(); - if (!ret) - { - ALOGE("interleave (%s) failed!", _url.c_str()); - break; - } - - nowTime = clockNow(); - ALOGD("Interleave (%s) wasted %fms", _url.c_str(), intervalInMS(oldTime, nowTime)); - - } while(false); - - ALOGV_IF(!ret, "%s returns false, decode (%s)", __FUNCTION__, _url.c_str()); - return ret; -} - -bool AudioDecoder::resample() -{ - if (_result.sampleRate == _sampleRate) - { - ALOGI("No need to resample since the sample rate (%d) of the decoded pcm data is the same as the device output sample rate", - _sampleRate); - return true; - } - - ALOGV("Resample: %d --> %d", _result.sampleRate, _sampleRate); - - auto r = _result; - PcmBufferProvider provider; - provider.init(r.pcmBuffer->data(), r.numFrames, r.pcmBuffer->size() / r.numFrames); - - const int outFrameRate = _sampleRate; - int outputChannels = 2; - size_t outputFrameSize = outputChannels * sizeof(int32_t); - size_t outputFrames = ((int64_t) r.numFrames * outFrameRate) / r.sampleRate; - size_t outputSize = outputFrames * outputFrameSize; - void *outputVAddr = malloc(outputSize); - - auto resampler = AudioResampler::create(AUDIO_FORMAT_PCM_16_BIT, r.numChannels, outFrameRate, - AudioResampler::MED_QUALITY); - resampler->setSampleRate(r.sampleRate); - resampler->setVolume(AudioResampler::UNITY_GAIN_FLOAT, AudioResampler::UNITY_GAIN_FLOAT); - - memset(outputVAddr, 0, outputSize); - - ALOGV("resample() %zu output frames", outputFrames); - - std::vector Ovalues; - - if (Ovalues.empty()) - { - Ovalues.push_back(outputFrames); - } - for (size_t i = 0, j = 0; i < outputFrames;) - { - size_t thisFrames = Ovalues[j++]; - if (j >= Ovalues.size()) - { - j = 0; - } - if (thisFrames == 0 || thisFrames > outputFrames - i) - { - thisFrames = outputFrames - i; - } - int outFrames = resampler->resample((int *) outputVAddr + outputChannels * i, thisFrames, - &provider); - ALOGV("outFrames: %d", outFrames); - i += thisFrames; - } - - ALOGV("resample() complete"); - - resampler->reset(); - - ALOGV("reset() complete"); - - delete resampler; - resampler = nullptr; - - // mono takes left channel only (out of stereo output pair) - // stereo and multichannel preserve all channels. - - int channels = r.numChannels; - int32_t *out = (int32_t *) outputVAddr; - int16_t *convert = (int16_t *) malloc(outputFrames * channels * sizeof(int16_t)); - - const int volumeShift = 12; // shift requirement for Q4.27 to Q.15 - // round to half towards zero and saturate at int16 (non-dithered) - const int roundVal = (1 << (volumeShift - 1)) - 1; // volumePrecision > 0 - - for (size_t i = 0; i < outputFrames; i++) - { - for (int j = 0; j < channels; j++) - { - int32_t s = out[i * outputChannels + j] + roundVal; // add offset here - if (s < 0) - { - s = (s + 1) >> volumeShift; // round to 0 - if (s < -32768) - { - s = -32768; - } - } else - { - s = s >> volumeShift; - if (s > 32767) - { - s = 32767; - } - } - convert[i * channels + j] = int16_t(s); - } - } - - // Reset result - _result.numFrames = outputFrames; - _result.sampleRate = outFrameRate; - - auto buffer = std::make_shared>(); - buffer->reserve(_result.numFrames * _result.bitsPerSample / 8); - buffer->insert(buffer->end(), (char *) convert, - (char *) convert + outputFrames * channels * sizeof(int16_t)); - _result.pcmBuffer = buffer; - - ALOGV("pcm buffer size: %d", (int)_result.pcmBuffer->size()); - - free(convert); - free(outputVAddr); - return true; -} - -//----------------------------------------------------------------- -bool AudioDecoder::interleave() -{ - if (_result.numChannels == 2) - { - ALOGI("Audio channel count is 2, no need to interleave"); - return true; - } - else if (_result.numChannels == 1) - { - // If it's a mono audio, try to compose a fake stereo buffer - size_t newBufferSize = _result.pcmBuffer->size() * 2; - auto newBuffer = std::make_shared>(); - newBuffer->reserve(newBufferSize); - size_t totalFrameSizeInBytes = (size_t) (_result.numFrames * _result.bitsPerSample / 8); - - for (size_t i = 0; i < totalFrameSizeInBytes; i += 2) - { - // get one short value - char byte1 = _result.pcmBuffer->at(i); - char byte2 = _result.pcmBuffer->at(i + 1); - - // push two short value - for (int j = 0; j < 2; ++j) - { - newBuffer->push_back(byte1); - newBuffer->push_back(byte2); - } - } - _result.numChannels = 2; - _result.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; - _result.pcmBuffer = newBuffer; - return true; - } - - ALOGE("Audio channel count (%d) is wrong, interleave only supports converting mono to stereo!", _result.numChannels); - return false; -} - -} // namespace cocos2d { diff --git a/cocos/audio/android/AudioDecoder.h b/cocos/audio/android/AudioDecoder.h deleted file mode 100644 index 8ad1f2b..0000000 --- a/cocos/audio/android/AudioDecoder.h +++ /dev/null @@ -1,64 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ - -#pragma once - -#include "audio/android/OpenSLHelper.h" -#include "audio/android/PcmData.h" -#include "base/CCData.h" - -namespace cocos2d { - -class AudioDecoder -{ -public: - AudioDecoder(); - virtual ~AudioDecoder(); - - virtual bool init(const std::string &url, int sampleRate); - - bool start(); - - inline PcmData getResult() - { return _result; }; - -protected: - virtual bool decodeToPcm() = 0; - bool resample(); - bool interleave(); - - static size_t fileRead(void* ptr, size_t size, size_t nmemb, void* datasource); - static int fileSeek(void* datasource, int64_t offset, int whence); - static int fileClose(void* datasource); - static long fileTell(void* datasource); - - std::string _url; - PcmData _result; - int _sampleRate; - Data _fileData; - size_t _fileCurrPos; -}; - -} // namespace cocos2d { diff --git a/cocos/audio/android/AudioDecoderMp3.cpp b/cocos/audio/android/AudioDecoderMp3.cpp deleted file mode 100644 index a5ea481..0000000 --- a/cocos/audio/android/AudioDecoderMp3.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ - -#define LOG_TAG "AudioDecoderMp3" - -#include "audio/android/AudioDecoderMp3.h" -#include "audio/android/mp3reader.h" -#include "platform/CCFileUtils.h" - -namespace cocos2d { - -AudioDecoderMp3::AudioDecoderMp3() -{ - ALOGV("Create AudioDecoderMp3"); -} - -AudioDecoderMp3::~AudioDecoderMp3() -{ - -} - -bool AudioDecoderMp3::decodeToPcm() -{ - _fileData = FileUtils::getInstance()->getDataFromFile(_url); - if (_fileData.isNull()) - { - return false; - } - - mp3_callbacks callbacks; - callbacks.read = AudioDecoder::fileRead; - callbacks.seek = AudioDecoder::fileSeek; - callbacks.close = AudioDecoder::fileClose; - callbacks.tell = AudioDecoder::fileTell; - - int numChannels = 0; - int sampleRate = 0; - int numFrames = 0; - - if (EXIT_SUCCESS == decodeMP3(&callbacks, this, *_result.pcmBuffer, &numChannels, &sampleRate, &numFrames) - && numChannels > 0 && sampleRate > 0 && numFrames > 0) - { - _result.numChannels = numChannels; - _result.sampleRate = sampleRate; - _result.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16; - _result.containerSize = SL_PCMSAMPLEFORMAT_FIXED_16; - _result.channelMask = numChannels == 1 ? SL_SPEAKER_FRONT_CENTER : (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT); - _result.endianness = SL_BYTEORDER_LITTLEENDIAN; - _result.numFrames = numFrames; - _result.duration = 1.0f * numFrames / sampleRate; - - std::string info = _result.toString(); - ALOGI("Original audio info: %s, total size: %d", info.c_str(), (int)_result.pcmBuffer->size()); - return true; - } - - ALOGE("Decode MP3 (%s) failed, channels: %d, rate: %d, frames: %d", _url.c_str(), numChannels, sampleRate, numFrames); - return false; -} - -} // namespace cocos2d { \ No newline at end of file diff --git a/cocos/audio/android/AudioDecoderMp3.h b/cocos/audio/android/AudioDecoderMp3.h deleted file mode 100644 index 8531320..0000000 --- a/cocos/audio/android/AudioDecoderMp3.h +++ /dev/null @@ -1,43 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ - -#pragma once - -#include "audio/android/AudioDecoder.h" - -namespace cocos2d { - -class AudioDecoderMp3 : public AudioDecoder -{ -protected: - AudioDecoderMp3(); - virtual ~AudioDecoderMp3(); - - virtual bool decodeToPcm() override; - - friend class AudioDecoderProvider; -}; - -} // namespace cocos2d { \ No newline at end of file diff --git a/cocos/audio/android/AudioDecoderOgg.cpp b/cocos/audio/android/AudioDecoderOgg.cpp deleted file mode 100644 index a1efb56..0000000 --- a/cocos/audio/android/AudioDecoderOgg.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ - -#define LOG_TAG "AudioDecoderOgg" - -#include "audio/android/AudioDecoderOgg.h" -#include "platform/CCFileUtils.h" - -namespace cocos2d { - -AudioDecoderOgg::AudioDecoderOgg() -{ - ALOGV("Create AudioDecoderOgg"); -} - -AudioDecoderOgg::~AudioDecoderOgg() -{ - -} - -int AudioDecoderOgg::fseek64Wrap(void* datasource, ogg_int64_t off, int whence) -{ - return AudioDecoder::fileSeek(datasource, (long)off, whence); -} - -bool AudioDecoderOgg::decodeToPcm() -{ - _fileData = FileUtils::getInstance()->getDataFromFile(_url); - if (_fileData.isNull()) - { - return false; - } - - ov_callbacks callbacks; - callbacks.read_func = AudioDecoder::fileRead; - callbacks.seek_func = AudioDecoderOgg::fseek64Wrap; - callbacks.close_func = AudioDecoder::fileClose; - callbacks.tell_func = AudioDecoder::fileTell; - - _fileCurrPos = 0; - - OggVorbis_File vf; - int ret = ov_open_callbacks(this, &vf, NULL, 0, callbacks); - if (ret != 0) - { - ALOGE("Open file error, file: %s, ov_open_callbacks return %d", _url.c_str(), ret); - return false; - } - // header - auto vi = ov_info(&vf, -1); - - uint32_t pcmSamples = (uint32_t) ov_pcm_total(&vf, -1); - - uint32_t bufferSize = pcmSamples * vi->channels * sizeof(short); - char* pcmBuffer = (char*)malloc(bufferSize); - memset(pcmBuffer, 0, bufferSize); - - int currentSection = 0; - long curPos = 0; - long readBytes = 0; - - do - { - readBytes = ov_read(&vf, pcmBuffer + curPos, 4096, ¤tSection); - curPos += readBytes; - } while (readBytes > 0); - - if (curPos > 0) - { - _result.pcmBuffer->insert(_result.pcmBuffer->end(), pcmBuffer, pcmBuffer + bufferSize); - _result.numChannels = vi->channels; - _result.sampleRate = vi->rate; - _result.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16; - _result.containerSize = SL_PCMSAMPLEFORMAT_FIXED_16; - _result.channelMask = vi->channels == 1 ? SL_SPEAKER_FRONT_CENTER : (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT); - _result.endianness = SL_BYTEORDER_LITTLEENDIAN; - _result.numFrames = pcmSamples; - _result.duration = 1.0f * pcmSamples / vi->rate; - } - else - { - ALOGE("ov_read returns 0 byte!"); - } - - ov_clear(&vf); - free(pcmBuffer); - - return (curPos > 0); -} - -} // namespace cocos2d { \ No newline at end of file diff --git a/cocos/audio/android/AudioDecoderOgg.h b/cocos/audio/android/AudioDecoderOgg.h deleted file mode 100644 index e9eb6df..0000000 --- a/cocos/audio/android/AudioDecoderOgg.h +++ /dev/null @@ -1,46 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ - -#pragma once - -#include "audio/android/AudioDecoder.h" - -#include "Tremolo/ivorbisfile.h" - -namespace cocos2d { - -class AudioDecoderOgg : public AudioDecoder -{ -protected: - AudioDecoderOgg(); - virtual ~AudioDecoderOgg(); - - static int fseek64Wrap(void* datasource, ogg_int64_t off, int whence); - virtual bool decodeToPcm() override; - - friend class AudioDecoderProvider; -}; - -} // namespace cocos2d { \ No newline at end of file diff --git a/cocos/audio/android/AudioDecoderProvider.cpp b/cocos/audio/android/AudioDecoderProvider.cpp deleted file mode 100644 index 077d813..0000000 --- a/cocos/audio/android/AudioDecoderProvider.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/**************************************************************************** - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -#define LOG_TAG "AudioDecoderProvider" - -#include "audio/android/AudioDecoderProvider.h" -#include "audio/android/AudioDecoderSLES.h" -#include "audio/android/AudioDecoderOgg.h" -#include "audio/android/AudioDecoderMp3.h" -#include "audio/android/AudioDecoderWav.h" -#include "platform/CCFileUtils.h" - -namespace cocos2d { - -AudioDecoder* AudioDecoderProvider::createAudioDecoder(SLEngineItf engineItf, const std::string &url, int bufferSizeInFrames, int sampleRate, const FdGetterCallback &fdGetterCallback) -{ - AudioDecoder* decoder = nullptr; - std::string extension = FileUtils::getInstance()->getFileExtension(url); - ALOGV("url:%s, extension:%s", url.c_str(), extension.c_str()); - if (extension == ".ogg") - { - decoder = new AudioDecoderOgg(); - if (!decoder->init(url, sampleRate)) - { - delete decoder; - decoder = nullptr; - } - } - else if (extension == ".mp3") - { - decoder = new AudioDecoderMp3(); - if (!decoder->init(url, sampleRate)) - { - delete decoder; - decoder = nullptr; - } - } - else if (extension == ".wav") - { - decoder = new AudioDecoderWav(); - if (!decoder->init(url, sampleRate)) - { - delete decoder; - decoder = nullptr; - } - } - else - { - auto slesDecoder = new AudioDecoderSLES(); - if (slesDecoder->init(engineItf, url, bufferSizeInFrames, sampleRate, fdGetterCallback)) - { - decoder = slesDecoder; - } - else - { - delete slesDecoder; - } - } - - return decoder; -} - -void AudioDecoderProvider::destroyAudioDecoder(AudioDecoder** decoder) -{ - if (decoder != nullptr && *decoder != nullptr) - { - delete (*decoder); - (*decoder) = nullptr; - } -} - -} // namespace cocos2d { \ No newline at end of file diff --git a/cocos/audio/android/AudioDecoderProvider.h b/cocos/audio/android/AudioDecoderProvider.h deleted file mode 100644 index 8070af0..0000000 --- a/cocos/audio/android/AudioDecoderProvider.h +++ /dev/null @@ -1,41 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ - -#pragma once - -#include "audio/android/OpenSLHelper.h" - -namespace cocos2d { - -class AudioDecoder; - -class AudioDecoderProvider -{ -public: - static AudioDecoder* createAudioDecoder(SLEngineItf engineItf, const std::string &url, int bufferSizeInFrames, int sampleRate, const FdGetterCallback &fdGetterCallback); - static void destroyAudioDecoder(AudioDecoder** decoder); -}; - -} // namespace cocos2d { \ No newline at end of file diff --git a/cocos/audio/android/AudioDecoderSLES.cpp b/cocos/audio/android/AudioDecoderSLES.cpp deleted file mode 100644 index 8371263..0000000 --- a/cocos/audio/android/AudioDecoderSLES.cpp +++ /dev/null @@ -1,646 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ - -#define LOG_TAG "AudioDecoderSLES" - -#include "audio/android/AudioDecoderSLES.h" -#include "platform/CCFileUtils.h" - -namespace cocos2d { - -/* Explicitly requesting SL_IID_ANDROIDSIMPLEBUFFERQUEUE and SL_IID_PREFETCHSTATUS -* on the UrlAudioPlayer object for decoding, SL_IID_METADATAEXTRACTION for retrieving the -* format of the decoded audio */ -#define NUM_EXPLICIT_INTERFACES_FOR_PLAYER 3 - -/* Size of the decode buffer queue */ -#define NB_BUFFERS_IN_QUEUE 4 - -/* size of the struct to retrieve the PCM format metadata values: the values we're interested in - * are SLuint32, but it is saved in the data field of a SLMetadataInfo, hence the larger size. - * Nate that this size is queried and displayed at l.452 for demonstration/test purposes. - * */ -#define PCM_METADATA_VALUE_SIZE 32 - -/* used to detect errors likely to have occurred when the OpenSL ES framework fails to open - * a resource, for instance because a file URI is invalid, or an HTTP server doesn't respond. - */ -#define PREFETCHEVENT_ERROR_CANDIDATE (SL_PREFETCHEVENT_STATUSCHANGE | SL_PREFETCHEVENT_FILLLEVELCHANGE) - -//----------------------------------------------------------------- - -static std::mutex __SLPlayerMutex; - -static int toBufferSizeInBytes(int bufferSizeInFrames, int sampleSize, int channelCount) -{ - return bufferSizeInFrames * sampleSize * channelCount; -} - -static int BUFFER_SIZE_IN_BYTES = 0; - -static void checkMetaData(int index, const char *key) -{ - if (index != -1) - { - ALOGV("Key %s is at index %d", key, index); - } - else - { - ALOGE("Unable to find key %s", key); - } -} - -class SLAudioDecoderCallbackProxy -{ -public: - //----------------------------------------------------------------- - /* Callback for "prefetch" events, here used to detect audio resource opening errors */ - static void prefetchEventCallback(SLPrefetchStatusItf caller, void *context, SLuint32 event) - { - AudioDecoderSLES *thiz = reinterpret_cast(context); - thiz->prefetchCallback(caller, event); - } - - static void decPlayCallback(SLAndroidSimpleBufferQueueItf queueItf, void *context) - { - AudioDecoderSLES *thiz = reinterpret_cast(context); - thiz->decodeToPcmCallback(queueItf); - } - - static void decProgressCallback(SLPlayItf caller, void *context, SLuint32 event) - { - AudioDecoderSLES *thiz = reinterpret_cast(context); - thiz->decodeProgressCallback(caller, event); - } -}; - -AudioDecoderSLES::AudioDecoderSLES() - : _engineItf(nullptr), _playObj(nullptr), _formatQueried(false), - _prefetchError(false), _counter(0), _numChannelsKeyIndex(-1), _sampleRateKeyIndex(-1), - _bitsPerSampleKeyIndex(-1), _containerSizeKeyIndex(-1), _channelMaskKeyIndex(-1), - _endiannessKeyIndex(-1), _eos(false), _bufferSizeInFrames(-1), - _assetFd(0), _fdGetterCallback(nullptr), _isDecodingCallbackInvoked(false) -{ - ALOGV("Create AudioDecoderSLES"); -} - -AudioDecoderSLES::~AudioDecoderSLES() -{ - { - std::lock_guard lk(__SLPlayerMutex); - SL_DESTROY_OBJ(_playObj); - } - ALOGV("After destroying SL play object"); - if (_assetFd > 0) - { - ALOGV("Closing assetFd: %d", _assetFd); - ::close(_assetFd); - _assetFd = 0; - } - free(_pcmData); -} - -bool AudioDecoderSLES::init(SLEngineItf engineItf, const std::string &url, int bufferSizeInFrames, int sampleRate, const FdGetterCallback &fdGetterCallback) -{ - if (AudioDecoder::init(url, sampleRate)) - { - _engineItf = engineItf; - _bufferSizeInFrames = bufferSizeInFrames; - _fdGetterCallback = fdGetterCallback; - - BUFFER_SIZE_IN_BYTES = toBufferSizeInBytes(bufferSizeInFrames, 2, 2); - _pcmData = (char*) malloc(NB_BUFFERS_IN_QUEUE * BUFFER_SIZE_IN_BYTES); - memset(_pcmData, 0x00, NB_BUFFERS_IN_QUEUE * BUFFER_SIZE_IN_BYTES); - return true; - } - - return false; -} - -bool AudioDecoderSLES::decodeToPcm() -{ - SLresult result; - - /* Objects this application uses: one audio player */ - SLObjectItf player; - - /* Interfaces for the audio player */ - SLAndroidSimpleBufferQueueItf decBuffQueueItf; - SLPrefetchStatusItf prefetchItf; - SLPlayItf playItf; - SLMetadataExtractionItf mdExtrItf; - - /* Source of audio data for the decoding */ - SLDataSource decSource; - - // decUri & locFd should be defined here - SLDataLocator_URI decUri; - SLDataLocator_AndroidFD locFd; - - /* Data sink for decoded audio */ - SLDataSink decDest; - SLDataLocator_AndroidSimpleBufferQueue decBuffQueue; - SLDataFormat_PCM pcm; - - SLboolean required[NUM_EXPLICIT_INTERFACES_FOR_PLAYER]; - SLInterfaceID iidArray[NUM_EXPLICIT_INTERFACES_FOR_PLAYER]; - - /* Initialize arrays required[] and iidArray[] */ - for (int i = 0; i < NUM_EXPLICIT_INTERFACES_FOR_PLAYER; i++) - { - required[i] = SL_BOOLEAN_FALSE; - iidArray[i] = SL_IID_NULL; - } - - /* ------------------------------------------------------ */ - /* Configuration of the player */ - - /* Request the AndroidSimpleBufferQueue interface */ - required[0] = SL_BOOLEAN_TRUE; - iidArray[0] = SL_IID_ANDROIDSIMPLEBUFFERQUEUE; - /* Request the PrefetchStatus interface */ - required[1] = SL_BOOLEAN_TRUE; - iidArray[1] = SL_IID_PREFETCHSTATUS; - /* Request the PrefetchStatus interface */ - required[2] = SL_BOOLEAN_TRUE; - iidArray[2] = SL_IID_METADATAEXTRACTION; - - SLDataFormat_MIME formatMime = {SL_DATAFORMAT_MIME, nullptr, SL_CONTAINERTYPE_UNSPECIFIED}; - decSource.pFormat = &formatMime; - - if (_url[0] != '/') - { - off_t start = 0, length = 0; - std::string relativePath; - size_t position = _url.find("assets/"); - - if (0 == position) - { - // "assets/" is at the beginning of the path and we don't want it - relativePath = _url.substr(strlen("assets/")); - } else - { - relativePath = _url; - } - - _assetFd = _fdGetterCallback(relativePath, &start, &length); - - if (_assetFd <= 0) - { - ALOGE("Failed to open file descriptor for '%s'", _url.c_str()); - return false; - } - - // configure audio source - locFd = {SL_DATALOCATOR_ANDROIDFD, _assetFd, start, length}; - - decSource.pLocator = &locFd; - } - else - { - decUri = {SL_DATALOCATOR_URI, (SLchar *) _url.c_str()}; - decSource.pLocator = &decUri; - } - - /* Setup the data sink */ - decBuffQueue.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; - decBuffQueue.numBuffers = NB_BUFFERS_IN_QUEUE; - /* set up the format of the data in the buffer queue */ - pcm.formatType = SL_DATAFORMAT_PCM; - // FIXME valid value required but currently ignored - pcm.numChannels = 2; - pcm.samplesPerSec = SL_SAMPLINGRATE_44_1; - pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16; - pcm.containerSize = SL_PCMSAMPLEFORMAT_FIXED_16; - pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; - pcm.endianness = SL_BYTEORDER_LITTLEENDIAN; - - decDest.pLocator = (void *) &decBuffQueue; - decDest.pFormat = (void *) &pcm; - - { - std::lock_guard lk(__SLPlayerMutex); - /* Create the audio player */ - result = (*_engineItf)->CreateAudioPlayer(_engineItf, &player, &decSource, &decDest, - NUM_EXPLICIT_INTERFACES_FOR_PLAYER, iidArray, - required); - SL_RETURN_VAL_IF_FAILED(result, false, "CreateAudioPlayer failed"); - - _playObj = player; - /* Realize the player in synchronous mode. */ - result = (*player)->Realize(player, SL_BOOLEAN_FALSE); - SL_RETURN_VAL_IF_FAILED(result, false, "Realize failed"); - } - - /* Get the play interface which is implicit */ - result = (*player)->GetInterface(player, SL_IID_PLAY, (void *) &playItf); - SL_RETURN_VAL_IF_FAILED(result, false, "GetInterface SL_IID_PLAY failed"); - - /* Set up the player callback to get events during the decoding */ - // FIXME currently ignored - result = (*playItf)->SetMarkerPosition(playItf, 2000); - SL_RETURN_VAL_IF_FAILED(result, false, "SetMarkerPosition failed"); - - result = (*playItf)->SetPositionUpdatePeriod(playItf, 500); - SL_RETURN_VAL_IF_FAILED(result, false, "SetPositionUpdatePeriod failed"); - result = (*playItf)->SetCallbackEventsMask(playItf, - SL_PLAYEVENT_HEADATMARKER | - SL_PLAYEVENT_HEADATNEWPOS | SL_PLAYEVENT_HEADATEND); - SL_RETURN_VAL_IF_FAILED(result, false, "SetCallbackEventsMask failed"); - result = (*playItf)->RegisterCallback(playItf, SLAudioDecoderCallbackProxy::decProgressCallback, - this); - SL_RETURN_VAL_IF_FAILED(result, false, "RegisterCallback failed"); - ALOGV("Play callback registered"); - - - /* Get the buffer queue interface which was explicitly requested */ - result = (*player)->GetInterface(player, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, - (void *) &decBuffQueueItf); - SL_RETURN_VAL_IF_FAILED(result, false, "GetInterface SL_IID_ANDROIDSIMPLEBUFFERQUEUE failed"); - - /* Get the prefetch status interface which was explicitly requested */ - result = (*player)->GetInterface(player, SL_IID_PREFETCHSTATUS, (void *) &prefetchItf); - SL_RETURN_VAL_IF_FAILED(result, false, "GetInterface SL_IID_PREFETCHSTATUS failed"); - - /* Get the metadata extraction interface which was explicitly requested */ - result = (*player)->GetInterface(player, SL_IID_METADATAEXTRACTION, (void *) &mdExtrItf); - SL_RETURN_VAL_IF_FAILED(result, false, "GetInterface SL_IID_METADATAEXTRACTION failed"); - - /* ------------------------------------------------------ */ - /* Initialize the callback and its context for the decoding buffer queue */ - _decContext.playItf = playItf; - _decContext.metaItf = mdExtrItf; - _decContext.pDataBase = (int8_t *) _pcmData; - _decContext.pData = _decContext.pDataBase; - _decContext.size = NB_BUFFERS_IN_QUEUE * BUFFER_SIZE_IN_BYTES; - - result = (*decBuffQueueItf)->RegisterCallback(decBuffQueueItf, - SLAudioDecoderCallbackProxy::decPlayCallback, - this); - SL_RETURN_VAL_IF_FAILED(result, false, "decBuffQueueItf RegisterCallback failed"); - - /* Enqueue buffers to map the region of memory allocated to store the decoded data */ -// ALOGV("Enqueueing buffer "); - for (int i = 0; i < NB_BUFFERS_IN_QUEUE; i++) - { - result = (*decBuffQueueItf)->Enqueue(decBuffQueueItf, _decContext.pData, - BUFFER_SIZE_IN_BYTES); - SL_RETURN_VAL_IF_FAILED(result, false, "Enqueue failed"); - _decContext.pData += BUFFER_SIZE_IN_BYTES; - } - - _decContext.pData = _decContext.pDataBase; - - /* ------------------------------------------------------ */ - /* Initialize the callback for prefetch errors, if we can't open the resource to decode */ - result = (*prefetchItf)->RegisterCallback(prefetchItf, - SLAudioDecoderCallbackProxy::prefetchEventCallback, - this); - SL_RETURN_VAL_IF_FAILED(result, false, "prefetchItf RegisterCallback failed"); - - result = (*prefetchItf)->SetCallbackEventsMask(prefetchItf, PREFETCHEVENT_ERROR_CANDIDATE); - SL_RETURN_VAL_IF_FAILED(result, false, "prefetchItf SetCallbackEventsMask failed"); - - /* ------------------------------------------------------ */ - /* Prefetch the data so we can get information about the format before starting to decode */ - /* 1/ cause the player to prefetch the data */ - result = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PAUSED); - SL_RETURN_VAL_IF_FAILED(result, false, "SetPlayState SL_PLAYSTATE_PAUSED failed"); - - /* 2/ block until data has been prefetched */ - SLuint32 prefetchStatus = SL_PREFETCHSTATUS_UNDERFLOW; - SLuint32 timeOutIndex = 1000; //cjh time out prefetching after 2s - while ((prefetchStatus != SL_PREFETCHSTATUS_SUFFICIENTDATA) && (timeOutIndex > 0) && - !_prefetchError) - { - std::this_thread::sleep_for(std::chrono::milliseconds(2)); - (*prefetchItf)->GetPrefetchStatus(prefetchItf, &prefetchStatus); - timeOutIndex--; - } - if (timeOutIndex == 0 || _prefetchError) - { - ALOGE("Failure to prefetch data in time, exiting"); - SL_RETURN_VAL_IF_FAILED(SL_RESULT_CONTENT_NOT_FOUND, false, - "Failure to prefetch data in time"); - } - - /* ------------------------------------------------------ */ - /* Display duration */ - SLmillisecond durationInMsec = SL_TIME_UNKNOWN; - result = (*playItf)->GetDuration(playItf, &durationInMsec); - SL_RETURN_VAL_IF_FAILED(result, false, "GetDuration failed"); - - if (durationInMsec == SL_TIME_UNKNOWN) - { - ALOGV("Content duration is unknown"); - } else - { - ALOGV("Content duration is %dms", (int)durationInMsec); - } - - /* ------------------------------------------------------ */ - /* Display the metadata obtained from the decoder */ - // This is for test / demonstration purposes only where we discover the key and value sizes - // of a PCM decoder. An application that would want to directly get access to those values - // can make assumptions about the size of the keys and their matching values (all SLuint32) - SLuint32 itemCount; - result = (*mdExtrItf)->GetItemCount(mdExtrItf, &itemCount); - SLuint32 i, keySize, valueSize; - SLMetadataInfo *keyInfo, *value; - for (i = 0; i < itemCount; i++) - { - keyInfo = nullptr; - keySize = 0; - value = nullptr; - valueSize = 0; - result = (*mdExtrItf)->GetKeySize(mdExtrItf, i, &keySize); - SL_RETURN_VAL_IF_FAILED(result, false, "GetKeySize(%d) failed", (int)i); - - result = (*mdExtrItf)->GetValueSize(mdExtrItf, i, &valueSize); - SL_RETURN_VAL_IF_FAILED(result, false, "GetValueSize(%d) failed", (int)i); - - keyInfo = (SLMetadataInfo *) malloc(keySize); - if (nullptr != keyInfo) - { - result = (*mdExtrItf)->GetKey(mdExtrItf, i, keySize, keyInfo); - - SL_RETURN_VAL_IF_FAILED(result, false, "GetKey(%d) failed", (int)i); - - ALOGV("key[%d] size=%d, name=%s, value size=%d", - (int)i, (int)keyInfo->size, keyInfo->data, (int)valueSize); - /* find out the key index of the metadata we're interested in */ - if (!strcmp((char *) keyInfo->data, ANDROID_KEY_PCMFORMAT_NUMCHANNELS)) - { - _numChannelsKeyIndex = i; - } else if (!strcmp((char *) keyInfo->data, ANDROID_KEY_PCMFORMAT_SAMPLERATE)) - { - _sampleRateKeyIndex = i; - } else if (!strcmp((char *) keyInfo->data, ANDROID_KEY_PCMFORMAT_BITSPERSAMPLE)) - { - _bitsPerSampleKeyIndex = i; - } else if (!strcmp((char *) keyInfo->data, ANDROID_KEY_PCMFORMAT_CONTAINERSIZE)) - { - _containerSizeKeyIndex = i; - } else if (!strcmp((char *) keyInfo->data, ANDROID_KEY_PCMFORMAT_CHANNELMASK)) - { - _channelMaskKeyIndex = i; - } else if (!strcmp((char *) keyInfo->data, ANDROID_KEY_PCMFORMAT_ENDIANNESS)) - { - _endiannessKeyIndex = i; - } - free(keyInfo); - } - } - - checkMetaData(_numChannelsKeyIndex, ANDROID_KEY_PCMFORMAT_NUMCHANNELS); - checkMetaData(_sampleRateKeyIndex, ANDROID_KEY_PCMFORMAT_SAMPLERATE); - checkMetaData(_bitsPerSampleKeyIndex, ANDROID_KEY_PCMFORMAT_BITSPERSAMPLE); - checkMetaData(_containerSizeKeyIndex, ANDROID_KEY_PCMFORMAT_CONTAINERSIZE); - checkMetaData(_channelMaskKeyIndex, ANDROID_KEY_PCMFORMAT_CHANNELMASK); - checkMetaData(_endiannessKeyIndex, ANDROID_KEY_PCMFORMAT_ENDIANNESS); - - /* ------------------------------------------------------ */ - /* Start decoding */ - result = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PLAYING); - SL_RETURN_VAL_IF_FAILED(result, false, "SetPlayState SL_PLAYSTATE_PLAYING failed"); - - ALOGV("Starting to decode"); - - /* Decode until the end of the stream is reached */ - { - std::unique_lock autoLock(_eosLock); - while (!_eos) - { - _eosCondition.wait(autoLock); - } - } - ALOGV("EOS signaled"); - - /* ------------------------------------------------------ */ - /* End of decoding */ - - /* Stop decoding */ - result = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED); - SL_RETURN_VAL_IF_FAILED(result, false, "SetPlayState SL_PLAYSTATE_STOPPED failed"); - - ALOGV("Stopped decoding"); - - /* Destroy the UrlAudioPlayer object */ - { - std::lock_guard lk(__SLPlayerMutex); - SL_DESTROY_OBJ(_playObj); - } - - ALOGV("After destroy player ..."); - - _result.numFrames = - _result.pcmBuffer->size() / _result.numChannels / (_result.bitsPerSample / 8); - - std::string info = _result.toString(); - ALOGI("Original audio info: %s, total size: %d", info.c_str(), (int)_result.pcmBuffer->size()); - return true; -} - -//----------------------------------------------------------------- -void AudioDecoderSLES::signalEos() -{ - std::unique_lock autoLock(_eosLock); - _eos = true; - _eosCondition.notify_one(); -} - -void AudioDecoderSLES::queryAudioInfo() -{ - if (_formatQueried) - { - return; - } - - SLresult result; - /* Get duration in callback where we use the callback context for the SLPlayItf*/ - SLmillisecond durationInMsec = SL_TIME_UNKNOWN; - result = (*_decContext.playItf)->GetDuration(_decContext.playItf, &durationInMsec); - SL_RETURN_IF_FAILED(result, "decodeProgressCallback,GetDuration failed"); - - if (durationInMsec == SL_TIME_UNKNOWN) - { - ALOGV("Content duration is unknown (in dec callback)"); - } else - { - ALOGV("Content duration is %dms (in dec callback)", (int)durationInMsec); - _result.duration = durationInMsec / 1000.0f; - } - - /* used to query metadata values */ - SLMetadataInfo pcmMetaData; - - result = (*_decContext.metaItf)->GetValue(_decContext.metaItf, _sampleRateKeyIndex, - PCM_METADATA_VALUE_SIZE, &pcmMetaData); - - SL_RETURN_IF_FAILED(result, "%s GetValue _sampleRateKeyIndex failed", __FUNCTION__); - // Note: here we could verify the following: - // pcmMetaData->encoding == SL_CHARACTERENCODING_BINARY - // pcmMetaData->size == sizeof(SLuint32) - // but the call was successful for the PCM format keys, so those conditions are implied - - _result.sampleRate = *((SLuint32 *) pcmMetaData.data); - result = (*_decContext.metaItf)->GetValue(_decContext.metaItf, _numChannelsKeyIndex, - PCM_METADATA_VALUE_SIZE, &pcmMetaData); - SL_RETURN_IF_FAILED(result, "%s GetValue _numChannelsKeyIndex failed", __FUNCTION__); - - _result.numChannels = *((SLuint32 *) pcmMetaData.data); - - result = (*_decContext.metaItf)->GetValue(_decContext.metaItf, _bitsPerSampleKeyIndex, - PCM_METADATA_VALUE_SIZE, &pcmMetaData); - SL_RETURN_IF_FAILED(result, "%s GetValue _bitsPerSampleKeyIndex failed", __FUNCTION__) - _result.bitsPerSample = *((SLuint32 *) pcmMetaData.data); - - result = (*_decContext.metaItf)->GetValue(_decContext.metaItf, _containerSizeKeyIndex, - PCM_METADATA_VALUE_SIZE, &pcmMetaData); - SL_RETURN_IF_FAILED(result, "%s GetValue _containerSizeKeyIndex failed", __FUNCTION__) - _result.containerSize = *((SLuint32 *) pcmMetaData.data); - - result = (*_decContext.metaItf)->GetValue(_decContext.metaItf, _channelMaskKeyIndex, - PCM_METADATA_VALUE_SIZE, &pcmMetaData); - SL_RETURN_IF_FAILED(result, "%s GetValue _channelMaskKeyIndex failed", __FUNCTION__) - _result.channelMask = *((SLuint32 *) pcmMetaData.data); - - result = (*_decContext.metaItf)->GetValue(_decContext.metaItf, _endiannessKeyIndex, - PCM_METADATA_VALUE_SIZE, &pcmMetaData); - SL_RETURN_IF_FAILED(result, "%s GetValue _endiannessKeyIndex failed", __FUNCTION__) - _result.endianness = *((SLuint32 *) pcmMetaData.data); - - _formatQueried = true; -} - -void AudioDecoderSLES::prefetchCallback(SLPrefetchStatusItf caller, SLuint32 event) -{ - SLpermille level = 0; - SLresult result; - result = (*caller)->GetFillLevel(caller, &level); - SL_RETURN_IF_FAILED(result, "GetFillLevel failed"); - - SLuint32 status; - //ALOGV("PrefetchEventCallback: received event %u", event); - result = (*caller)->GetPrefetchStatus(caller, &status); - - SL_RETURN_IF_FAILED(result, "GetPrefetchStatus failed"); - - if ((PREFETCHEVENT_ERROR_CANDIDATE == (event & PREFETCHEVENT_ERROR_CANDIDATE)) - && (level == 0) && (status == SL_PREFETCHSTATUS_UNDERFLOW)) - { - ALOGV("PrefetchEventCallback: Error while prefetching data, exiting"); - _prefetchError = true; - signalEos(); - } -} - -/* Callback for "playback" events, i.e. event happening during decoding */ -void AudioDecoderSLES::decodeProgressCallback(SLPlayItf caller, SLuint32 event) -{ - if (SL_PLAYEVENT_HEADATEND & event) - { - ALOGV("SL_PLAYEVENT_HEADATEND"); - if (!_isDecodingCallbackInvoked) - { - queryAudioInfo(); - - for (int i = 0; i < NB_BUFFERS_IN_QUEUE; ++i) - { - _result.pcmBuffer->insert(_result.pcmBuffer->end(), _decContext.pData, - _decContext.pData + BUFFER_SIZE_IN_BYTES); - - /* Increase data pointer by buffer size */ - _decContext.pData += BUFFER_SIZE_IN_BYTES; - } - } - signalEos(); - } -} - -//----------------------------------------------------------------- -/* Callback for decoding buffer queue events */ -void AudioDecoderSLES::decodeToPcmCallback(SLAndroidSimpleBufferQueueItf queueItf) -{ - _isDecodingCallbackInvoked = true; - ALOGV("%s ...", __FUNCTION__); - _counter++; - SLresult result; - // FIXME: ?? - if (_counter % 1000 == 0) - { - SLmillisecond msec; - result = (*_decContext.playItf)->GetPosition(_decContext.playItf, &msec); - SL_RETURN_IF_FAILED(result, "%s, GetPosition failed", __FUNCTION__); - ALOGV("%s called (iteration %d): current position=%d ms", __FUNCTION__, _counter, (int)msec); - } - - _result.pcmBuffer->insert(_result.pcmBuffer->end(), _decContext.pData, - _decContext.pData + BUFFER_SIZE_IN_BYTES); - - result = (*queueItf)->Enqueue(queueItf, _decContext.pData, BUFFER_SIZE_IN_BYTES); - SL_RETURN_IF_FAILED(result, "%s, Enqueue failed", __FUNCTION__); - - /* Increase data pointer by buffer size */ - _decContext.pData += BUFFER_SIZE_IN_BYTES; - - if (_decContext.pData >= _decContext.pDataBase + (NB_BUFFERS_IN_QUEUE * BUFFER_SIZE_IN_BYTES)) - { - _decContext.pData = _decContext.pDataBase; - } - - // Note: adding a sleep here or any sync point is a way to slow down the decoding, or - // synchronize it with some other event, as the OpenSL ES framework will block until the - // buffer queue callback return to proceed with the decoding. - -#if 0 - /* Example: buffer queue state display */ - SLAndroidSimpleBufferQueueState decQueueState; - result =(*queueItf)->GetState(queueItf, &decQueueState); - SL_RETURN_IF_FAILED(result, "decQueueState.GetState failed"); - - ALOGV("DecBufferQueueCallback now has _decContext.pData=%p, _decContext.pDataBase=%p, queue: " - "count=%u playIndex=%u, count: %d", - _decContext.pData, _decContext.pDataBase, decQueueState.count, decQueueState.index, _counter); -#endif - -#if 0 - /* Example: display position in callback where we use the callback context for the SLPlayItf*/ - SLmillisecond posMsec = SL_TIME_UNKNOWN; - result = (*_decContext.playItf)->GetPosition(_decContext.playItf, &posMsec); - SL_RETURN_IF_FAILED(result, "decodeToPcmCallback,GetPosition2 failed"); - - if (posMsec == SL_TIME_UNKNOWN) { - ALOGV("Content position is unknown (in dec callback)"); - } else { - ALOGV("Content position is %ums (in dec callback)", - posMsec); - } -#endif - - queryAudioInfo(); -} - -} // namespace cocos2d { \ No newline at end of file diff --git a/cocos/audio/android/AudioDecoderSLES.h b/cocos/audio/android/AudioDecoderSLES.h deleted file mode 100644 index 4055b8e..0000000 --- a/cocos/audio/android/AudioDecoderSLES.h +++ /dev/null @@ -1,97 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ - -#pragma once - -#include "audio/android/AudioDecoder.h" -#include -#include - -namespace cocos2d { - -class AudioDecoderSLES : public AudioDecoder -{ -protected: - AudioDecoderSLES(); - virtual ~AudioDecoderSLES(); - - bool init(SLEngineItf engineItf, const std::string &url, int bufferSizeInFrames, int sampleRate, const FdGetterCallback &fdGetterCallback); - virtual bool decodeToPcm() override; - -private: - void queryAudioInfo(); - - void signalEos(); - void decodeToPcmCallback(SLAndroidSimpleBufferQueueItf queueItf); - void prefetchCallback(SLPrefetchStatusItf caller, SLuint32 event); - void decodeProgressCallback(SLPlayItf caller, SLuint32 event); - - SLEngineItf _engineItf; - SLObjectItf _playObj; - /* Local storage for decoded audio data */ - char* _pcmData; - - /* we only want to query / display the PCM format once */ - bool _formatQueried; - /* Used to signal prefetching failures */ - bool _prefetchError; - - /* to display the number of decode iterations */ - int _counter; - - /* metadata key index for the PCM format information we want to retrieve */ - int _numChannelsKeyIndex; - int _sampleRateKeyIndex; - int _bitsPerSampleKeyIndex; - int _containerSizeKeyIndex; - int _channelMaskKeyIndex; - int _endiannessKeyIndex; - - /* to signal to the test app the end of the stream to decode has been reached */ - bool _eos; - std::mutex _eosLock; - std::condition_variable _eosCondition; - - /* Structure for passing information to callback function */ - typedef struct CallbackCntxt_ - { - SLPlayItf playItf; - SLMetadataExtractionItf metaItf; - SLuint32 size; - SLint8 *pDataBase; // Base address of local audio data storage - SLint8 *pData; // Current address of local audio data storage - } CallbackCntxt; - - CallbackCntxt _decContext; - int _bufferSizeInFrames; - int _assetFd; - FdGetterCallback _fdGetterCallback; - bool _isDecodingCallbackInvoked; - - friend class SLAudioDecoderCallbackProxy; - friend class AudioDecoderProvider; -}; - -} // namespace cocos2d { \ No newline at end of file diff --git a/cocos/audio/android/AudioDecoderWav.cpp b/cocos/audio/android/AudioDecoderWav.cpp deleted file mode 100644 index b55dc0d..0000000 --- a/cocos/audio/android/AudioDecoderWav.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ - -#define LOG_TAG "AudioDecoderWav" - -#include "audio/android/AudioDecoderWav.h" -#include "audio/android/tinysndfile.h" -#include "platform/CCFileUtils.h" - -namespace cocos2d { - -AudioDecoderWav::AudioDecoderWav() -{ - ALOGV("Create AudioDecoderWav"); -} - -AudioDecoderWav::~AudioDecoderWav() -{ - -} - -void* AudioDecoderWav::onWavOpen(const char* path, void* user) -{ - return user; -} - -int AudioDecoderWav::onWavSeek(void* datasource, long offset, int whence) -{ - return AudioDecoder::fileSeek(datasource, (int64_t) offset, whence); -} - -int AudioDecoderWav::onWavClose(void* datasource) -{ - return 0; -} - -bool AudioDecoderWav::decodeToPcm() -{ - _fileData = FileUtils::getInstance()->getDataFromFile(_url); - if (_fileData.isNull()) - { - return false; - } - - SF_INFO info; - - snd_callbacks cb; - cb.open = onWavOpen; - cb.read = AudioDecoder::fileRead; - cb.seek = onWavSeek; - cb.close = onWavClose; - cb.tell = AudioDecoder::fileTell; - - SNDFILE* handle = NULL; - bool ret = false; - do - { - handle = sf_open_read(_url.c_str(), &info, &cb, this); - if (handle == nullptr) - break; - - if (info.frames == 0) - break; - - ALOGD("wav info: frames: %d, samplerate: %d, channels: %d, format: %d", info.frames, info.samplerate, info.channels, info.format); - size_t bufSize = sizeof(short) * info.frames * info.channels; - unsigned char* buf = (unsigned char*)malloc(bufSize); - sf_count_t readFrames = sf_readf_short(handle, (short*)buf, info.frames); - assert(readFrames == info.frames); - - _result.pcmBuffer->insert(_result.pcmBuffer->end(), buf, buf + bufSize); - _result.numChannels = info.channels; - _result.sampleRate = info.samplerate; - _result.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16; - _result.containerSize = SL_PCMSAMPLEFORMAT_FIXED_16; - _result.channelMask = _result.numChannels == 1 ? SL_SPEAKER_FRONT_CENTER : (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT); - _result.endianness = SL_BYTEORDER_LITTLEENDIAN; - _result.numFrames = info.frames; - _result.duration = 1.0f * info.frames / _result.sampleRate; - - free(buf); - ret = true; - } while (false); - - if (handle != NULL) - sf_close(handle); - - return ret; -} - -} // namespace cocos2d { \ No newline at end of file diff --git a/cocos/audio/android/AudioDecoderWav.h b/cocos/audio/android/AudioDecoderWav.h deleted file mode 100644 index 4234f04..0000000 --- a/cocos/audio/android/AudioDecoderWav.h +++ /dev/null @@ -1,47 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ - -#pragma once - -#include "audio/android/AudioDecoder.h" - -namespace cocos2d { - -class AudioDecoderWav : public AudioDecoder -{ -protected: - AudioDecoderWav(); - virtual ~AudioDecoderWav(); - - virtual bool decodeToPcm() override; - - static void* onWavOpen(const char* path, void* user); - static int onWavSeek(void* datasource, long offset, int whence); - static int onWavClose(void* datasource); - - friend class AudioDecoderProvider; -}; - -} // namespace cocos2d { \ No newline at end of file diff --git a/cocos/audio/android/AudioEngine-inl.cpp b/cocos/audio/android/AudioEngine-inl.cpp deleted file mode 100644 index 09bcd63..0000000 --- a/cocos/audio/android/AudioEngine-inl.cpp +++ /dev/null @@ -1,494 +0,0 @@ -/**************************************************************************** - Copyright (c) 2014-2016 Chukong Technologies Inc. - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ -#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID - -#define LOG_TAG "AudioEngineImpl" - -#include "audio/android/AudioEngine-inl.h" - -#include -// for native asset manager -#include -#include -#include - -#include -#include "platform/android/jni/JniHelper.h" -#include -#include -#include "audio/include/AudioEngine.h" -#include "base/CCDirector.h" -#include "base/CCScheduler.h" -#include "base/CCEventDispatcher.h" -#include "base/CCEventType.h" -#include "base/CCEventListenerCustom.h" -#include "base/ccUTF8.h" -#include "platform/android/CCFileUtils-android.h" -#include "platform/android/jni/Java_org_cocos2dx_lib_Cocos2dxHelper.h" - -#include "audio/android/IAudioPlayer.h" -#include "audio/android/ICallerThreadUtils.h" -#include "audio/android/AudioPlayerProvider.h" -#include "audio/android/cutils/log.h" -#include "audio/android/UrlAudioPlayer.h" - -using namespace cocos2d; - -// Audio focus values synchronized with which in cocos/platform/android/java/src/org/cocos2dx/lib/Cocos2dxActivity.java -static const int AUDIOFOCUS_GAIN = 0; -static const int AUDIOFOCUS_LOST = 1; -static const int AUDIOFOCUS_LOST_TRANSIENT = 2; -static const int AUDIOFOCUS_LOST_TRANSIENT_CAN_DUCK = 3; - -static int __currentAudioFocus = AUDIOFOCUS_GAIN; -static AudioEngineImpl* __impl = nullptr; - -class CallerThreadUtils : public ICallerThreadUtils -{ -public: - virtual void performFunctionInCallerThread(const std::function& func) - { - Director::getInstance()->getScheduler()->performFunctionInCocosThread(func); - }; - - virtual std::thread::id getCallerThreadId() - { - return _tid; - }; - - void setCallerThreadId(std::thread::id tid) - { - _tid = tid; - }; - -private: - std::thread::id _tid; -}; - -static CallerThreadUtils __callerThreadUtils; - -static int fdGetter(const std::string& url, off_t* start, off_t* length) -{ - int fd = -1; - if (cocos2d::FileUtilsAndroid::getObbFile() != nullptr) - { - fd = getObbAssetFileDescriptorJNI(url.c_str(), start, length); - } - else - { - auto asset = AAssetManager_open(cocos2d::FileUtilsAndroid::getAssetManager(), url.c_str(), AASSET_MODE_UNKNOWN); - // open asset as file descriptor - fd = AAsset_openFileDescriptor(asset, start, length); - AAsset_close(asset); - } - - if (fd <= 0) - { - ALOGE("Failed to open file descriptor for '%s'", url.c_str()); - } - - return fd; -}; - -//==================================================== -AudioEngineImpl::AudioEngineImpl() - : _engineObject(nullptr) - , _engineEngine(nullptr) - , _outputMixObject(nullptr) - , _audioPlayerProvider(nullptr) - , _onPauseListener(nullptr) - , _onResumeListener(nullptr) - , _audioIDIndex(0) - , _lazyInitLoop(true) -{ - __callerThreadUtils.setCallerThreadId(std::this_thread::get_id()); - __impl = this; -} - -AudioEngineImpl::~AudioEngineImpl() -{ - if (_audioPlayerProvider != nullptr) - { - delete _audioPlayerProvider; - _audioPlayerProvider = nullptr; - } - - if (_outputMixObject) - { - (*_outputMixObject)->Destroy(_outputMixObject); - } - if (_engineObject) - { - (*_engineObject)->Destroy(_engineObject); - } - - if (_onPauseListener != nullptr) - { - Director::getInstance()->getEventDispatcher()->removeEventListener(_onPauseListener); - } - - if (_onResumeListener != nullptr) - { - Director::getInstance()->getEventDispatcher()->removeEventListener(_onResumeListener); - } - - __impl = nullptr; -} - -bool AudioEngineImpl::init() -{ - bool ret = false; - do{ - - // create engine - auto result = slCreateEngine(&_engineObject, 0, nullptr, 0, nullptr, nullptr); - if(SL_RESULT_SUCCESS != result){ ERRORLOG("create opensl engine fail"); break; } - - // realize the engine - result = (*_engineObject)->Realize(_engineObject, SL_BOOLEAN_FALSE); - if(SL_RESULT_SUCCESS != result){ ERRORLOG("realize the engine fail"); break; } - - // get the engine interface, which is needed in order to create other objects - result = (*_engineObject)->GetInterface(_engineObject, SL_IID_ENGINE, &_engineEngine); - if(SL_RESULT_SUCCESS != result){ ERRORLOG("get the engine interface fail"); break; } - - // create output mix - const SLInterfaceID outputMixIIDs[] = {}; - const SLboolean outputMixReqs[] = {}; - result = (*_engineEngine)->CreateOutputMix(_engineEngine, &_outputMixObject, 0, outputMixIIDs, outputMixReqs); - if(SL_RESULT_SUCCESS != result){ ERRORLOG("create output mix fail"); break; } - - // realize the output mix - result = (*_outputMixObject)->Realize(_outputMixObject, SL_BOOLEAN_FALSE); - if(SL_RESULT_SUCCESS != result){ ERRORLOG("realize the output mix fail"); break; } - - _audioPlayerProvider = new AudioPlayerProvider(_engineEngine, _outputMixObject, getDeviceSampleRate(), getDeviceAudioBufferSizeInFrames(), fdGetter, &__callerThreadUtils); - - _onPauseListener = Director::getInstance()->getEventDispatcher()->addCustomEventListener(EVENT_COME_TO_BACKGROUND, CC_CALLBACK_1(AudioEngineImpl::onEnterBackground, this)); - - _onResumeListener = Director::getInstance()->getEventDispatcher()->addCustomEventListener(EVENT_COME_TO_FOREGROUND, CC_CALLBACK_1(AudioEngineImpl::onEnterForeground, this)); - - ret = true; - }while (false); - - return ret; -} - -void AudioEngineImpl::onEnterBackground(EventCustom* event) -{ - // _audioPlayerProvider->pause() pauses AudioMixer and PcmAudioService, - // but UrlAudioPlayers could not be paused. - if (_audioPlayerProvider != nullptr) - { - _audioPlayerProvider->pause(); - } - - // pause UrlAudioPlayers which are playing. - for (auto&& e : _audioPlayers) - { - auto player = e.second; - if (dynamic_cast(player) != nullptr - && player->getState() == IAudioPlayer::State::PLAYING) - { - _urlAudioPlayersNeedResume.emplace(e.first, player); - player->pause(); - } - } -} - -void AudioEngineImpl::onEnterForeground(EventCustom* event) -{ - // _audioPlayerProvider->resume() resumes AudioMixer and PcmAudioService, - // but UrlAudioPlayers could not be resumed. - if (_audioPlayerProvider != nullptr) - { - _audioPlayerProvider->resume(); - } - - // resume UrlAudioPlayers - for (auto&& iter : _urlAudioPlayersNeedResume) - { - iter.second->resume(); - } - _urlAudioPlayersNeedResume.clear(); -} - -void AudioEngineImpl::setAudioFocusForAllPlayers(bool isFocus) -{ - for (const auto& e : _audioPlayers) - { - e.second->setAudioFocus(isFocus); - } -} - -int AudioEngineImpl::play2d(const std::string &filePath ,bool loop ,float volume) -{ - ALOGV("play2d, _audioPlayers.size=%d", (int)_audioPlayers.size()); - auto audioId = AudioEngine::INVALID_AUDIO_ID; - - do - { - if (_engineEngine == nullptr || _audioPlayerProvider == nullptr) - break; - - auto fullPath = FileUtils::getInstance()->fullPathForFilename(filePath); - - audioId = _audioIDIndex++; - - auto player = _audioPlayerProvider->getAudioPlayer(fullPath); - if (player != nullptr) - { - player->setId(audioId); - _audioPlayers.insert(std::make_pair(audioId, player)); - - player->setPlayEventCallback([this, player, filePath](IAudioPlayer::State state){ - - if (state != IAudioPlayer::State::OVER && state != IAudioPlayer::State::STOPPED) - { - ALOGV("Ignore state: %d", static_cast(state)); - return; - } - - int id = player->getId(); - - ALOGV("Removing player id=%d, state:%d", id, (int)state); - - AudioEngine::remove(id); - if (_audioPlayers.find(id) != _audioPlayers.end()) - { - _audioPlayers.erase(id); - } - if (_urlAudioPlayersNeedResume.find(id) != _urlAudioPlayersNeedResume.end()) - { - _urlAudioPlayersNeedResume.erase(id); - } - - auto iter = _callbackMap.find(id); - if (iter != _callbackMap.end()) - { - if (state == IAudioPlayer::State::OVER) - { - iter->second(id, filePath); - } - _callbackMap.erase(iter); - } - }); - - player->setLoop(loop); - player->setVolume(volume); - player->setAudioFocus(__currentAudioFocus == AUDIOFOCUS_GAIN); - player->play(); - } - else - { - ALOGE("Oops, player is null ..."); - return AudioEngine::INVALID_AUDIO_ID; - } - - AudioEngine::_audioIDInfoMap[audioId].state = AudioEngine::AudioState::PLAYING; - - } while (0); - - return audioId; -} - -void AudioEngineImpl::setVolume(int audioID,float volume) -{ - auto iter = _audioPlayers.find(audioID); - if (iter != _audioPlayers.end()) - { - auto player = iter->second; - player->setVolume(volume); - } -} - -void AudioEngineImpl::setLoop(int audioID, bool loop) -{ - auto iter = _audioPlayers.find(audioID); - if (iter != _audioPlayers.end()) - { - auto player = iter->second; - player->setLoop(loop); - } -} - -void AudioEngineImpl::pause(int audioID) -{ - auto iter = _audioPlayers.find(audioID); - if (iter != _audioPlayers.end()) - { - auto player = iter->second; - player->pause(); - } -} - -void AudioEngineImpl::resume(int audioID) -{ - auto iter = _audioPlayers.find(audioID); - if (iter != _audioPlayers.end()) - { - auto player = iter->second; - player->resume(); - } -} - -void AudioEngineImpl::stop(int audioID) -{ - auto iter = _audioPlayers.find(audioID); - if (iter != _audioPlayers.end()) - { - auto player = iter->second; - player->stop(); - } -} - -void AudioEngineImpl::stopAll() -{ - if (_audioPlayers.empty()) - { - return; - } - - // Create a temporary vector for storing all players since - // p->stop() will trigger _audioPlayers.erase, - // and it will cause a crash as it's already in for loop - std::vector players; - players.reserve(_audioPlayers.size()); - - for (const auto& e : _audioPlayers) - { - players.push_back(e.second); - } - - for (auto p : players) - { - p->stop(); - } -} - -float AudioEngineImpl::getDuration(int audioID) -{ - auto iter = _audioPlayers.find(audioID); - if (iter != _audioPlayers.end()) - { - auto player = iter->second; - return player->getDuration(); - } - return 0.0f; -} - -float AudioEngineImpl::getCurrentTime(int audioID) -{ - auto iter = _audioPlayers.find(audioID); - if (iter != _audioPlayers.end()) - { - auto player = iter->second; - return player->getPosition(); - } - return 0.0f; -} - -bool AudioEngineImpl::setCurrentTime(int audioID, float time) -{ - auto iter = _audioPlayers.find(audioID); - if (iter != _audioPlayers.end()) - { - auto player = iter->second; - return player->setPosition(time); - } - return false; -} - -void AudioEngineImpl::setFinishCallback(int audioID, const std::function &callback) -{ - _callbackMap[audioID] = callback; -} - -void AudioEngineImpl::preload(const std::string& filePath, const std::function& callback) -{ - if (_audioPlayerProvider != nullptr) - { - std::string fullPath = FileUtils::getInstance()->fullPathForFilename(filePath); - _audioPlayerProvider->preloadEffect(fullPath, [callback](bool succeed, PcmData data){ - if (callback != nullptr) - { - callback(succeed); - } - }); - } - else - { - if (callback != nullptr) - { - callback(false); - } - } -} - -void AudioEngineImpl::uncache(const std::string& filePath) -{ - if (_audioPlayerProvider != nullptr) - { - std::string fullPath = FileUtils::getInstance()->fullPathForFilename(filePath); - _audioPlayerProvider->clearPcmCache(fullPath); - } -} - -void AudioEngineImpl::uncacheAll() -{ - if (_audioPlayerProvider != nullptr) - { - _audioPlayerProvider->clearAllPcmCaches(); - } -} - -// It's invoked from javaactivity-android.cpp -void cocos_audioengine_focus_change(int focusChange) -{ - if (focusChange < AUDIOFOCUS_GAIN || focusChange > AUDIOFOCUS_LOST_TRANSIENT_CAN_DUCK) - { - CCLOGERROR("cocos_audioengine_focus_change: unknown value: %d", focusChange); - return; - } - CCLOG("cocos_audioengine_focus_change: %d", focusChange); - __currentAudioFocus = focusChange; - - if (__impl == nullptr) - { - CCLOGWARN("cocos_audioengine_focus_change: AudioEngineImpl isn't ready!"); - return; - } - - if (__currentAudioFocus == AUDIOFOCUS_GAIN) - { - __impl->setAudioFocusForAllPlayers(true); - } - else - { - __impl->setAudioFocusForAllPlayers(false); - } -} - -#endif diff --git a/cocos/audio/android/AudioEngine-inl.h b/cocos/audio/android/AudioEngine-inl.h deleted file mode 100644 index cef13de..0000000 --- a/cocos/audio/android/AudioEngine-inl.h +++ /dev/null @@ -1,107 +0,0 @@ -/**************************************************************************** - Copyright (c) 2014-2016 Chukong Technologies Inc. - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ -#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID - -#ifndef __AUDIO_ENGINE_INL_H_ -#define __AUDIO_ENGINE_INL_H_ - -#include -#include -#include -#include -#include "base/CCRef.h" -#include "base/ccUtils.h" - -#define MAX_AUDIOINSTANCES 24 - -#define ERRORLOG(msg) log("fun:%s,line:%d,msg:%s",__func__,__LINE__,#msg) - -NS_CC_BEGIN - -class EventCustom; -class EventListener; - -class IAudioPlayer; -class AudioPlayerProvider; - -class AudioEngineImpl; - -class AudioEngineImpl : public cocos2d::Ref -{ -public: - AudioEngineImpl(); - ~AudioEngineImpl(); - - bool init(); - int play2d(const std::string &fileFullPath ,bool loop ,float volume); - void setVolume(int audioID,float volume); - void setLoop(int audioID, bool loop); - void pause(int audioID); - void resume(int audioID); - void stop(int audioID); - void stopAll(); - float getDuration(int audioID); - float getCurrentTime(int audioID); - bool setCurrentTime(int audioID, float time); - void setFinishCallback(int audioID, const std::function &callback); - - void uncache(const std::string& filePath); - void uncacheAll(); - void preload(const std::string& filePath, const std::function& callback); - - void setAudioFocusForAllPlayers(bool isFocus); -private: - - void onEnterBackground(EventCustom* event); - void onEnterForeground(EventCustom* event); - - // engine interfaces - SLObjectItf _engineObject; - SLEngineItf _engineEngine; - - // output mix interfaces - SLObjectItf _outputMixObject; - - //audioID,AudioInfo - std::unordered_map _audioPlayers; - std::unordered_map> _callbackMap; - - // UrlAudioPlayers which need to resumed while entering foreground - std::unordered_map _urlAudioPlayersNeedResume; - - AudioPlayerProvider* _audioPlayerProvider; - EventListener* _onPauseListener; - EventListener* _onResumeListener; - - int _audioIDIndex; - - bool _lazyInitLoop; -}; - -#endif // __AUDIO_ENGINE_INL_H_ - -NS_CC_END - -#endif diff --git a/cocos/audio/android/AudioMixer.cpp b/cocos/audio/android/AudioMixer.cpp deleted file mode 100644 index cfd665a..0000000 --- a/cocos/audio/android/AudioMixer.cpp +++ /dev/null @@ -1,2101 +0,0 @@ -/* -** -** Copyright 2007, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -#define LOG_TAG "AudioMixer" -#define LOG_NDEBUG 1 - -#include -#include -#include -#include -#include - -#include "audio/android/audio.h" -#include "audio/android/audio_utils/include/audio_utils/primitives.h" - -#include "audio/android/AudioMixerOps.h" -#include "audio/android/AudioMixer.h" - -// The FCC_2 macro refers to the Fixed Channel Count of 2 for the legacy integer mixer. -#ifndef FCC_2 -#define FCC_2 2 -#endif - -// Look for MONO_HACK for any Mono hack involving legacy mono channel to -// stereo channel conversion. - -/* VERY_VERY_VERBOSE_LOGGING will show exactly which process hook and track hook is - * being used. This is a considerable amount of log spam, so don't enable unless you - * are verifying the hook based code. - */ -//#define VERY_VERY_VERBOSE_LOGGING -#ifdef VERY_VERY_VERBOSE_LOGGING -#define ALOGVV ALOGV -//define ALOGVV printf // for test-mixer.cpp -#else -#define ALOGVV(a...) do { } while (0) -#endif - -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) -#endif - -// TODO: Move these macro/inlines to a header file. -template -static inline -T max(const T& x, const T& y) { - return x > y ? x : y; -} - -// Set kUseNewMixer to true to use the new mixer engine always. Otherwise the -// original code will be used for stereo sinks, the new mixer for multichannel. -static const bool kUseNewMixer = false; - -// Set kUseFloat to true to allow floating input into the mixer engine. -// If kUseNewMixer is false, this is ignored or may be overridden internally -// because of downmix/upmix support. -static const bool kUseFloat = false; - -// Set to default copy buffer size in frames for input processing. -static const size_t kCopyBufferFrameCount = 256; - -namespace cocos2d { - -// ---------------------------------------------------------------------------- - -template -T min(const T& a, const T& b) -{ - return a < b ? a : b; -} - -// ---------------------------------------------------------------------------- - -// Ensure mConfiguredNames bitmask is initialized properly on all architectures. -// The value of 1 << x is undefined in C when x >= 32. - -AudioMixer::AudioMixer(size_t frameCount, uint32_t sampleRate, uint32_t maxNumTracks) - : mTrackNames(0), mConfiguredNames((maxNumTracks >= 32 ? 0 : 1 << maxNumTracks) - 1), - mSampleRate(sampleRate) -{ - ALOGVV("AudioMixer constructed, frameCount: %d, sampleRate: %d", (int)frameCount, (int)sampleRate); - ALOG_ASSERT(maxNumTracks <= MAX_NUM_TRACKS, "maxNumTracks %u > MAX_NUM_TRACKS %u", - maxNumTracks, MAX_NUM_TRACKS); - - // AudioMixer is not yet capable of more than 32 active track inputs - ALOG_ASSERT(32 >= MAX_NUM_TRACKS, "bad MAX_NUM_TRACKS %d", MAX_NUM_TRACKS); - - pthread_once(&sOnceControl, &sInitRoutine); - - mState.enabledTracks= 0; - mState.needsChanged = 0; - mState.frameCount = frameCount; - mState.hook = process__nop; - mState.outputTemp = NULL; - mState.resampleTemp = NULL; -//cjh mState.mLog = &mDummyLog; - // mState.reserved - - // FIXME Most of the following initialization is probably redundant since - // tracks[i] should only be referenced if (mTrackNames & (1 << i)) != 0 - // and mTrackNames is initially 0. However, leave it here until that's verified. - track_t* t = mState.tracks; - for (unsigned i=0 ; i < MAX_NUM_TRACKS ; i++) { - t->resampler = NULL; -//cjh t->downmixerBufferProvider = NULL; -// t->mReformatBufferProvider = NULL; -// t->mTimestretchBufferProvider = NULL; - t++; - } - -} - -AudioMixer::~AudioMixer() -{ - track_t* t = mState.tracks; - for (unsigned i=0 ; i < MAX_NUM_TRACKS ; i++) { - delete t->resampler; -//cjh delete t->downmixerBufferProvider; -// delete t->mReformatBufferProvider; -// delete t->mTimestretchBufferProvider; - t++; - } - delete [] mState.outputTemp; - delete [] mState.resampleTemp; -} - -//cjh void AudioMixer::setLog(NBLog::Writer *log) -//{ -// mState.mLog = log; -//} - -static inline audio_format_t selectMixerInFormat(audio_format_t inputFormat __unused) { - return kUseFloat && kUseNewMixer ? AUDIO_FORMAT_PCM_FLOAT : AUDIO_FORMAT_PCM_16_BIT; -} - -int AudioMixer::getTrackName(audio_channel_mask_t channelMask, - audio_format_t format, int sessionId) -{ - if (!isValidPcmTrackFormat(format)) { - ALOGE("AudioMixer::getTrackName invalid format (%#x)", format); - return -1; - } - uint32_t names = (~mTrackNames) & mConfiguredNames; - if (names != 0) { - int n = __builtin_ctz(names); - ALOGV("add track (%d)", n); - // assume default parameters for the track, except where noted below - track_t* t = &mState.tracks[n]; - t->needs = 0; - - // Integer volume. - // Currently integer volume is kept for the legacy integer mixer. - // Will be removed when the legacy mixer path is removed. - t->volume[0] = UNITY_GAIN_INT; - t->volume[1] = UNITY_GAIN_INT; - t->prevVolume[0] = UNITY_GAIN_INT << 16; - t->prevVolume[1] = UNITY_GAIN_INT << 16; - t->volumeInc[0] = 0; - t->volumeInc[1] = 0; - t->auxLevel = 0; - t->auxInc = 0; - t->prevAuxLevel = 0; - - // Floating point volume. - t->mVolume[0] = UNITY_GAIN_FLOAT; - t->mVolume[1] = UNITY_GAIN_FLOAT; - t->mPrevVolume[0] = UNITY_GAIN_FLOAT; - t->mPrevVolume[1] = UNITY_GAIN_FLOAT; - t->mVolumeInc[0] = 0.; - t->mVolumeInc[1] = 0.; - t->mAuxLevel = 0.; - t->mAuxInc = 0.; - t->mPrevAuxLevel = 0.; - - // no initialization needed - // t->frameCount - t->channelCount = audio_channel_count_from_out_mask(channelMask); - t->enabled = false; - ALOGV_IF(audio_channel_mask_get_bits(channelMask) != AUDIO_CHANNEL_OUT_STEREO, - "Non-stereo channel mask: %d\n", channelMask); - t->channelMask = channelMask; - t->sessionId = sessionId; - // setBufferProvider(name, AudioBufferProvider *) is required before enable(name) - t->bufferProvider = NULL; - t->buffer.raw = NULL; - // no initialization needed - // t->buffer.frameCount - t->hook = NULL; - t->in = NULL; - t->resampler = NULL; - t->sampleRate = mSampleRate; - // setParameter(name, TRACK, MAIN_BUFFER, mixBuffer) is required before enable(name) - t->mainBuffer = NULL; - t->auxBuffer = NULL; - t->mInputBufferProvider = NULL; -//cjh t->mReformatBufferProvider = NULL; -// t->downmixerBufferProvider = NULL; -// t->mPostDownmixReformatBufferProvider = NULL; -// t->mTimestretchBufferProvider = NULL; - t->mMixerFormat = AUDIO_FORMAT_PCM_16_BIT; - t->mFormat = format; - t->mMixerInFormat = selectMixerInFormat(format); - t->mDownmixRequiresFormat = AUDIO_FORMAT_INVALID; // no format required - t->mMixerChannelMask = audio_channel_mask_from_representation_and_bits( - AUDIO_CHANNEL_REPRESENTATION_POSITION, AUDIO_CHANNEL_OUT_STEREO); - t->mMixerChannelCount = audio_channel_count_from_out_mask(t->mMixerChannelMask); - ALOGVV("t->mMixerChannelCount: %d", t->mMixerChannelCount); - t->mPlaybackRate = AUDIO_PLAYBACK_RATE_DEFAULT; - // Check the downmixing (or upmixing) requirements. - status_t status = t->prepareForDownmix(); - if (status != OK) { - ALOGE("AudioMixer::getTrackName invalid channelMask (%#x)", channelMask); - return -1; - } - // prepareForDownmix() may change mDownmixRequiresFormat - ALOGVV("mMixerFormat:%#x mMixerInFormat:%#x\n", t->mMixerFormat, t->mMixerInFormat); - t->prepareForReformat(); - mTrackNames |= 1 << n; - ALOGVV("getTrackName return: %d", TRACK0 + n); - return TRACK0 + n; - } - ALOGE("AudioMixer::getTrackName out of available tracks"); - return -1; -} - -void AudioMixer::invalidateState(uint32_t mask) -{ - if (mask != 0) { - mState.needsChanged |= mask; - mState.hook = process__validate; - } - } - -// Called when channel masks have changed for a track name -// TODO: Fix DownmixerBufferProvider not to (possibly) change mixer input format, -// which will simplify this logic. -bool AudioMixer::setChannelMasks(int name, - audio_channel_mask_t trackChannelMask, audio_channel_mask_t mixerChannelMask) { - track_t &track = mState.tracks[name]; - ALOGVV("AudioMixer::setChannelMask ..."); - if (trackChannelMask == track.channelMask - && mixerChannelMask == track.mMixerChannelMask) { - ALOGVV("No need to change channel mask ..."); - return false; // no need to change - } - // always recompute for both channel masks even if only one has changed. - const uint32_t trackChannelCount = audio_channel_count_from_out_mask(trackChannelMask); - const uint32_t mixerChannelCount = audio_channel_count_from_out_mask(mixerChannelMask); - const bool mixerChannelCountChanged = track.mMixerChannelCount != mixerChannelCount; - - ALOG_ASSERT((trackChannelCount <= MAX_NUM_CHANNELS_TO_DOWNMIX) - && trackChannelCount - && mixerChannelCount); - track.channelMask = trackChannelMask; - track.channelCount = trackChannelCount; - track.mMixerChannelMask = mixerChannelMask; - track.mMixerChannelCount = mixerChannelCount; - - // channel masks have changed, does this track need a downmixer? - // update to try using our desired format (if we aren't already using it) - const audio_format_t prevDownmixerFormat = track.mDownmixRequiresFormat; - const status_t status = mState.tracks[name].prepareForDownmix(); - ALOGE_IF(status != OK, - "prepareForDownmix error %d, track channel mask %#x, mixer channel mask %#x", - status, track.channelMask, track.mMixerChannelMask); - - if (prevDownmixerFormat != track.mDownmixRequiresFormat) { - track.prepareForReformat(); // because of downmixer, track format may change! - } - - if (track.resampler && mixerChannelCountChanged) { - // resampler channels may have changed. - const uint32_t resetToSampleRate = track.sampleRate; - delete track.resampler; - track.resampler = NULL; - track.sampleRate = mSampleRate; // without resampler, track rate is device sample rate. - // recreate the resampler with updated format, channels, saved sampleRate. - track.setResampler(resetToSampleRate /*trackSampleRate*/, mSampleRate /*devSampleRate*/); - } - return true; -} - -void AudioMixer::track_t::unprepareForDownmix() { - ALOGV("AudioMixer::unprepareForDownmix(%p)", this); - - mDownmixRequiresFormat = AUDIO_FORMAT_INVALID; -//cjh if (downmixerBufferProvider != NULL) { -// // this track had previously been configured with a downmixer, delete it -// ALOGV(" deleting old downmixer"); -// delete downmixerBufferProvider; -// downmixerBufferProvider = NULL; -// reconfigureBufferProviders(); -// } else - { - ALOGV(" nothing to do, no downmixer to delete"); - } -} - -status_t AudioMixer::track_t::prepareForDownmix() -{ - ALOGV("AudioMixer::prepareForDownmix(%p) with mask 0x%x", - this, channelMask); - - // discard the previous downmixer if there was one - unprepareForDownmix(); - // MONO_HACK Only remix (upmix or downmix) if the track and mixer/device channel masks - // are not the same and not handled internally, as mono -> stereo currently is. - if (channelMask == mMixerChannelMask - || (channelMask == AUDIO_CHANNEL_OUT_MONO - && mMixerChannelMask == AUDIO_CHANNEL_OUT_STEREO)) { - return NO_ERROR; - } - // DownmixerBufferProvider is only used for position masks. -//cjh if (audio_channel_mask_get_representation(channelMask) -// == AUDIO_CHANNEL_REPRESENTATION_POSITION -// && DownmixerBufferProvider::isMultichannelCapable()) { -// DownmixerBufferProvider* pDbp = new DownmixerBufferProvider(channelMask, -// mMixerChannelMask, -// AUDIO_FORMAT_PCM_16_BIT /* TODO: use mMixerInFormat, now only PCM 16 */, -// sampleRate, sessionId, kCopyBufferFrameCount); -// -// if (pDbp->isValid()) { // if constructor completed properly -// mDownmixRequiresFormat = AUDIO_FORMAT_PCM_16_BIT; // PCM 16 bit required for downmix -// downmixerBufferProvider = pDbp; -// reconfigureBufferProviders(); -// return NO_ERROR; -// } -// delete pDbp; -// } -// -// // Effect downmixer does not accept the channel conversion. Let's use our remixer. -// RemixBufferProvider* pRbp = new RemixBufferProvider(channelMask, -// mMixerChannelMask, mMixerInFormat, kCopyBufferFrameCount); -// // Remix always finds a conversion whereas Downmixer effect above may fail. -// downmixerBufferProvider = pRbp; -// reconfigureBufferProviders(); - return NO_ERROR; -} - -void AudioMixer::track_t::unprepareForReformat() { - ALOGV("AudioMixer::unprepareForReformat(%p)", this); - bool requiresReconfigure = false; -//cjh if (mReformatBufferProvider != NULL) { -// delete mReformatBufferProvider; -// mReformatBufferProvider = NULL; -// requiresReconfigure = true; -// } -// if (mPostDownmixReformatBufferProvider != NULL) { -// delete mPostDownmixReformatBufferProvider; -// mPostDownmixReformatBufferProvider = NULL; -// requiresReconfigure = true; -// } - if (requiresReconfigure) { - reconfigureBufferProviders(); - } -} - -status_t AudioMixer::track_t::prepareForReformat() -{ - ALOGV("AudioMixer::prepareForReformat(%p) with format %#x", this, mFormat); - // discard previous reformatters - unprepareForReformat(); - // only configure reformatters as needed - const audio_format_t targetFormat = mDownmixRequiresFormat != AUDIO_FORMAT_INVALID - ? mDownmixRequiresFormat : mMixerInFormat; - bool requiresReconfigure = false; -//cjh if (mFormat != targetFormat) { -// mReformatBufferProvider = new ReformatBufferProvider( -// audio_channel_count_from_out_mask(channelMask), -// mFormat, -// targetFormat, -// kCopyBufferFrameCount); -// requiresReconfigure = true; -// } -// if (targetFormat != mMixerInFormat) { -// mPostDownmixReformatBufferProvider = new ReformatBufferProvider( -// audio_channel_count_from_out_mask(mMixerChannelMask), -// targetFormat, -// mMixerInFormat, -// kCopyBufferFrameCount); -// requiresReconfigure = true; -// } - if (requiresReconfigure) { - reconfigureBufferProviders(); - } - ALOGVV("prepareForReformat return ..."); - return NO_ERROR; -} - -void AudioMixer::track_t::reconfigureBufferProviders() -{ - bufferProvider = mInputBufferProvider; -//cjh if (mReformatBufferProvider) { -// mReformatBufferProvider->setBufferProvider(bufferProvider); -// bufferProvider = mReformatBufferProvider; -// } -// if (downmixerBufferProvider) { -// downmixerBufferProvider->setBufferProvider(bufferProvider); -// bufferProvider = downmixerBufferProvider; -// } -// if (mPostDownmixReformatBufferProvider) { -// mPostDownmixReformatBufferProvider->setBufferProvider(bufferProvider); -// bufferProvider = mPostDownmixReformatBufferProvider; -// } -// if (mTimestretchBufferProvider) { -// mTimestretchBufferProvider->setBufferProvider(bufferProvider); -// bufferProvider = mTimestretchBufferProvider; -// } -} - -void AudioMixer::deleteTrackName(int name) -{ - ALOGV("AudioMixer::deleteTrackName(%d)", name); - name -= TRACK0; - ALOG_ASSERT(uint32_t(name) < MAX_NUM_TRACKS, "bad track name %d", name); - ALOGV("deleteTrackName(%d)", name); - track_t& track(mState.tracks[ name ]); - if (track.enabled) { - track.enabled = false; - invalidateState(1< AudioMixer::UNITY_GAIN_FLOAT) { - newVolume = AudioMixer::UNITY_GAIN_FLOAT; - } - break; - } - } - - // set floating point volume ramp - if (ramp != 0) { - // when the ramp completes, *pPrevVolume is set to *pSetVolume, so there - // is no computational mismatch; hence equality is checked here. - ALOGD_IF(*pPrevVolume != *pSetVolume, "previous float ramp hasn't finished," - " prev:%f set_to:%f", *pPrevVolume, *pSetVolume); - const float inc = (newVolume - *pPrevVolume) / ramp; // could be inf, nan, subnormal - const float maxv = max(newVolume, *pPrevVolume); // could be inf, cannot be nan, subnormal - - if (isnormal(inc) // inc must be a normal number (no subnormals, infinite, nan) - && maxv + inc != maxv) { // inc must make forward progress - *pVolumeInc = inc; - // ramp is set now. - // Note: if newVolume is 0, then near the end of the ramp, - // it may be possible that the ramped volume may be subnormal or - // temporarily negative by a small amount or subnormal due to floating - // point inaccuracies. - } else { - ramp = 0; // ramp not allowed - } - } - - // compute and check integer volume, no need to check negative values - // The integer volume is limited to "unity_gain" to avoid wrapping and other - // audio artifacts, so it never reaches the range limit of U4.28. - // We safely use signed 16 and 32 bit integers here. - const float scaledVolume = newVolume * AudioMixer::UNITY_GAIN_INT; // not neg, subnormal, nan - const int32_t intVolume = (scaledVolume >= (float)AudioMixer::UNITY_GAIN_INT) ? - AudioMixer::UNITY_GAIN_INT : (int32_t)scaledVolume; - - // set integer volume ramp - if (ramp != 0) { - // integer volume is U4.12 (to use 16 bit multiplies), but ramping uses U4.28. - // when the ramp completes, *pIntPrevVolume is set to *pIntSetVolume << 16, so there - // is no computational mismatch; hence equality is checked here. - ALOGD_IF(*pIntPrevVolume != *pIntSetVolume << 16, "previous int ramp hasn't finished," - " prev:%d set_to:%d", *pIntPrevVolume, *pIntSetVolume << 16); - const int32_t inc = ((intVolume << 16) - *pIntPrevVolume) / ramp; - - if (inc != 0) { // inc must make forward progress - *pIntVolumeInc = inc; - } else { - ramp = 0; // ramp not allowed - } - } - - // if no ramp, or ramp not allowed, then clear float and integer increments - if (ramp == 0) { - *pVolumeInc = 0; - *pPrevVolume = newVolume; - *pIntVolumeInc = 0; - *pIntPrevVolume = intVolume << 16; - } - *pSetVolume = newVolume; - *pIntSetVolume = intVolume; - return true; -} - -void AudioMixer::setParameter(int name, int target, int param, void *value) -{ - name -= TRACK0; - ALOG_ASSERT(uint32_t(name) < MAX_NUM_TRACKS, "bad track name %d", name); - track_t& track = mState.tracks[name]; - - int valueInt = static_cast(reinterpret_cast(value)); - int32_t *valueBuf = reinterpret_cast(value); - - switch (target) { - - case TRACK: - switch (param) { - case CHANNEL_MASK: { - const audio_channel_mask_t trackChannelMask = - static_cast(valueInt); - if (setChannelMasks(name, trackChannelMask, track.mMixerChannelMask)) { - ALOGV("setParameter(TRACK, CHANNEL_MASK, %x)", trackChannelMask); - invalidateState(1 << name); - } - } break; - case MAIN_BUFFER: - if (track.mainBuffer != valueBuf) { - track.mainBuffer = valueBuf; - ALOGV("setParameter(TRACK, MAIN_BUFFER, %p)", valueBuf); - invalidateState(1 << name); - } - break; - case AUX_BUFFER: - if (track.auxBuffer != valueBuf) { - track.auxBuffer = valueBuf; - ALOGV("setParameter(TRACK, AUX_BUFFER, %p)", valueBuf); - invalidateState(1 << name); - } - break; - case FORMAT: { - audio_format_t format = static_cast(valueInt); - if (track.mFormat != format) { - ALOG_ASSERT(audio_is_linear_pcm(format), "Invalid format %#x", format); - track.mFormat = format; - ALOGV("setParameter(TRACK, FORMAT, %#x)", format); - track.prepareForReformat(); - invalidateState(1 << name); - } - } break; - // FIXME do we want to support setting the downmix type from AudioMixerController? - // for a specific track? or per mixer? - /* case DOWNMIX_TYPE: - break */ - case MIXER_FORMAT: { - audio_format_t format = static_cast(valueInt); - if (track.mMixerFormat != format) { - track.mMixerFormat = format; - ALOGV("setParameter(TRACK, MIXER_FORMAT, %#x)", format); - } - } break; - case MIXER_CHANNEL_MASK: { - const audio_channel_mask_t mixerChannelMask = - static_cast(valueInt); - if (setChannelMasks(name, track.channelMask, mixerChannelMask)) { - ALOGV("setParameter(TRACK, MIXER_CHANNEL_MASK, %#x)", mixerChannelMask); - invalidateState(1 << name); - } - } break; - default: - LOG_ALWAYS_FATAL("setParameter track: bad param %d", param); - } - break; - - case RESAMPLE: - switch (param) { - case SAMPLE_RATE: - ALOG_ASSERT(valueInt > 0, "bad sample rate %d", valueInt); - if (track.setResampler(uint32_t(valueInt), mSampleRate)) { - ALOGV("setParameter(RESAMPLE, SAMPLE_RATE, %u)", - uint32_t(valueInt)); - invalidateState(1 << name); - } - break; - case RESET: - track.resetResampler(); - invalidateState(1 << name); - break; - case REMOVE: - delete track.resampler; - track.resampler = NULL; - track.sampleRate = mSampleRate; - invalidateState(1 << name); - break; - default: - LOG_ALWAYS_FATAL("setParameter resample: bad param %d", param); - } - break; - - case RAMP_VOLUME: - case VOLUME: - switch (param) { - case AUXLEVEL: - if (setVolumeRampVariables(*reinterpret_cast(value), - target == RAMP_VOLUME ? mState.frameCount : 0, - &track.auxLevel, &track.prevAuxLevel, &track.auxInc, - &track.mAuxLevel, &track.mPrevAuxLevel, &track.mAuxInc)) { - ALOGV("setParameter(%s, AUXLEVEL: %04x)", - target == VOLUME ? "VOLUME" : "RAMP_VOLUME", track.auxLevel); - invalidateState(1 << name); - } - break; - default: - if ((unsigned)param >= VOLUME0 && (unsigned)param < VOLUME0 + MAX_NUM_VOLUMES) { - if (setVolumeRampVariables(*reinterpret_cast(value), - target == RAMP_VOLUME ? mState.frameCount : 0, - &track.volume[param - VOLUME0], &track.prevVolume[param - VOLUME0], - &track.volumeInc[param - VOLUME0], - &track.mVolume[param - VOLUME0], &track.mPrevVolume[param - VOLUME0], - &track.mVolumeInc[param - VOLUME0])) { - ALOGV("setParameter(%s, VOLUME%d: %04x)", - target == VOLUME ? "VOLUME" : "RAMP_VOLUME", param - VOLUME0, - track.volume[param - VOLUME0]); - invalidateState(1 << name); - } - } else { - LOG_ALWAYS_FATAL("setParameter volume: bad param %d", param); - } - } - break; - case TIMESTRETCH: - switch (param) { - case PLAYBACK_RATE: { - const AudioPlaybackRate *playbackRate = - reinterpret_cast(value); - ALOGW_IF(!isAudioPlaybackRateValid(*playbackRate), - "bad parameters speed %f, pitch %f",playbackRate->mSpeed, - playbackRate->mPitch); - if (track.setPlaybackRate(*playbackRate)) { - ALOGV("setParameter(TIMESTRETCH, PLAYBACK_RATE, STRETCH_MODE, FALLBACK_MODE " - "%f %f %d %d", - playbackRate->mSpeed, - playbackRate->mPitch, - playbackRate->mStretchMode, - playbackRate->mFallbackMode); - // invalidateState(1 << name); - } - } break; - default: - LOG_ALWAYS_FATAL("setParameter timestretch: bad param %d", param); - } - break; - - default: - LOG_ALWAYS_FATAL("setParameter: bad target %d", target); - } -} - -bool AudioMixer::track_t::setResampler(uint32_t trackSampleRate, uint32_t devSampleRate) -{ - if (trackSampleRate != devSampleRate || resampler != NULL) { - if (sampleRate != trackSampleRate) { - sampleRate = trackSampleRate; - if (resampler == NULL) { - ALOGV("Creating resampler from track %d Hz to device %d Hz", - trackSampleRate, devSampleRate); - AudioResampler::src_quality quality; - // force lowest quality level resampler if use case isn't music or video - // FIXME this is flawed for dynamic sample rates, as we choose the resampler - // quality level based on the initial ratio, but that could change later. - // Should have a way to distinguish tracks with static ratios vs. dynamic ratios. -//cjh if (isMusicRate(trackSampleRate)) { - quality = AudioResampler::DEFAULT_QUALITY; -//cjh } else { -// quality = AudioResampler::DYN_LOW_QUALITY; -// } - - // TODO: Remove MONO_HACK. Resampler sees #channels after the downmixer - // but if none exists, it is the channel count (1 for mono). - const int resamplerChannelCount = false/*downmixerBufferProvider != NULL*/ - ? mMixerChannelCount : channelCount; - ALOGVV("Creating resampler:" - " format(%#x) channels(%d) devSampleRate(%u) quality(%d)\n", - mMixerInFormat, resamplerChannelCount, devSampleRate, quality); - resampler = AudioResampler::create( - mMixerInFormat, - resamplerChannelCount, - devSampleRate, quality); - resampler->setLocalTimeFreq(sLocalTimeFreq); - } - return true; - } - } - return false; -} - -bool AudioMixer::track_t::setPlaybackRate(const AudioPlaybackRate &playbackRate) -{ -//cjh if ((mTimestretchBufferProvider == NULL && -// fabs(playbackRate.mSpeed - mPlaybackRate.mSpeed) < AUDIO_TIMESTRETCH_SPEED_MIN_DELTA && -// fabs(playbackRate.mPitch - mPlaybackRate.mPitch) < AUDIO_TIMESTRETCH_PITCH_MIN_DELTA) || -// isAudioPlaybackRateEqual(playbackRate, mPlaybackRate)) { -// return false; -// } - mPlaybackRate = playbackRate; -// if (mTimestretchBufferProvider == NULL) { -// // TODO: Remove MONO_HACK. Resampler sees #channels after the downmixer -// // but if none exists, it is the channel count (1 for mono). -// const int timestretchChannelCount = downmixerBufferProvider != NULL -// ? mMixerChannelCount : channelCount; -// mTimestretchBufferProvider = new TimestretchBufferProvider(timestretchChannelCount, -// mMixerInFormat, sampleRate, playbackRate); -// reconfigureBufferProviders(); -// } else { -// reinterpret_cast(mTimestretchBufferProvider) -// ->setPlaybackRate(playbackRate); -// } - return true; -} - -/* Checks to see if the volume ramp has completed and clears the increment - * variables appropriately. - * - * FIXME: There is code to handle int/float ramp variable switchover should it not - * complete within a mixer buffer processing call, but it is preferred to avoid switchover - * due to precision issues. The switchover code is included for legacy code purposes - * and can be removed once the integer volume is removed. - * - * It is not sufficient to clear only the volumeInc integer variable because - * if one channel requires ramping, all channels are ramped. - * - * There is a bit of duplicated code here, but it keeps backward compatibility. - */ -inline void AudioMixer::track_t::adjustVolumeRamp(bool aux, bool useFloat) -{ - if (useFloat) { - for (uint32_t i = 0; i < MAX_NUM_VOLUMES; i++) { - if ((mVolumeInc[i] > 0 && mPrevVolume[i] + mVolumeInc[i] >= mVolume[i]) || - (mVolumeInc[i] < 0 && mPrevVolume[i] + mVolumeInc[i] <= mVolume[i])) { - volumeInc[i] = 0; - prevVolume[i] = volume[i] << 16; - mVolumeInc[i] = 0.; - mPrevVolume[i] = mVolume[i]; - } else { - //ALOGV("ramp: %f %f %f", mVolume[i], mPrevVolume[i], mVolumeInc[i]); - prevVolume[i] = u4_28_from_float(mPrevVolume[i]); - } - } - } else { - for (uint32_t i = 0; i < MAX_NUM_VOLUMES; i++) { - if (((volumeInc[i]>0) && (((prevVolume[i]+volumeInc[i])>>16) >= volume[i])) || - ((volumeInc[i]<0) && (((prevVolume[i]+volumeInc[i])>>16) <= volume[i]))) { - volumeInc[i] = 0; - prevVolume[i] = volume[i] << 16; - mVolumeInc[i] = 0.; - mPrevVolume[i] = mVolume[i]; - } else { - //ALOGV("ramp: %d %d %d", volume[i] << 16, prevVolume[i], volumeInc[i]); - mPrevVolume[i] = float_from_u4_28(prevVolume[i]); - } - } - } - /* TODO: aux is always integer regardless of output buffer type */ - if (aux) { - if (((auxInc>0) && (((prevAuxLevel+auxInc)>>16) >= auxLevel)) || - ((auxInc<0) && (((prevAuxLevel+auxInc)>>16) <= auxLevel))) { - auxInc = 0; - prevAuxLevel = auxLevel << 16; - mAuxInc = 0.; - mPrevAuxLevel = mAuxLevel; - } else { - //ALOGV("aux ramp: %d %d %d", auxLevel << 16, prevAuxLevel, auxInc); - } - } -} - -size_t AudioMixer::getUnreleasedFrames(int name) const -{ - name -= TRACK0; - if (uint32_t(name) < MAX_NUM_TRACKS) { - return mState.tracks[name].getUnreleasedFrames(); - } - return 0; -} - -void AudioMixer::setBufferProvider(int name, AudioBufferProvider* bufferProvider) -{ - name -= TRACK0; - ALOG_ASSERT(uint32_t(name) < MAX_NUM_TRACKS, "bad track name %d", name); - - if (mState.tracks[name].mInputBufferProvider == bufferProvider) { - return; // don't reset any buffer providers if identical. - } -//cjh if (mState.tracks[name].mReformatBufferProvider != NULL) { -// mState.tracks[name].mReformatBufferProvider->reset(); -// } else if (mState.tracks[name].downmixerBufferProvider != NULL) { -// mState.tracks[name].downmixerBufferProvider->reset(); -// } else if (mState.tracks[name].mPostDownmixReformatBufferProvider != NULL) { -// mState.tracks[name].mPostDownmixReformatBufferProvider->reset(); -// } else if (mState.tracks[name].mTimestretchBufferProvider != NULL) { -// mState.tracks[name].mTimestretchBufferProvider->reset(); -// } - - mState.tracks[name].mInputBufferProvider = bufferProvider; - mState.tracks[name].reconfigureBufferProviders(); -} - - -void AudioMixer::process(int64_t pts) -{ - mState.hook(&mState, pts); -} - - -void AudioMixer::process__validate(state_t* state, int64_t pts) -{ - ALOGW_IF(!state->needsChanged, - "in process__validate() but nothing's invalid"); - - uint32_t changed = state->needsChanged; - state->needsChanged = 0; // clear the validation flag - - // recompute which tracks are enabled / disabled - uint32_t enabled = 0; - uint32_t disabled = 0; - while (changed) { - const int i = 31 - __builtin_clz(changed); - const uint32_t mask = 1<tracks[i]; - (t.enabled ? enabled : disabled) |= mask; - } - state->enabledTracks &= ~disabled; - state->enabledTracks |= enabled; - - // compute everything we need... - int countActiveTracks = 0; - // TODO: fix all16BitsStereNoResample logic to - // either properly handle muted tracks (it should ignore them) - // or remove altogether as an obsolete optimization. - bool all16BitsStereoNoResample = true; - bool resampling = false; - bool volumeRamp = false; - uint32_t en = state->enabledTracks; - while (en) { - const int i = 31 - __builtin_clz(en); - en &= ~(1<tracks[i]; - uint32_t n = 0; - // FIXME can overflow (mask is only 3 bits) - n |= NEEDS_CHANNEL_1 + t.channelCount - 1; - if (t.doesResample()) { - n |= NEEDS_RESAMPLE; - } - if (t.auxLevel != 0 && t.auxBuffer != NULL) { - n |= NEEDS_AUX; - } - - if (t.volumeInc[0]|t.volumeInc[1]) { - volumeRamp = true; - } else if (!t.doesResample() && t.volumeRL == 0) { - n |= NEEDS_MUTE; - } - t.needs = n; - - if (n & NEEDS_MUTE) { - t.hook = track__nop; - } else { - if (n & NEEDS_AUX) { - all16BitsStereoNoResample = false; - } - if (n & NEEDS_RESAMPLE) { - all16BitsStereoNoResample = false; - resampling = true; - t.hook = getTrackHook(TRACKTYPE_RESAMPLE, t.mMixerChannelCount, - t.mMixerInFormat, t.mMixerFormat); - ALOGV_IF((n & NEEDS_CHANNEL_COUNT__MASK) > NEEDS_CHANNEL_2, - "Track %d needs downmix + resample", i); - } else { - if ((n & NEEDS_CHANNEL_COUNT__MASK) == NEEDS_CHANNEL_1){ - t.hook = getTrackHook( - (t.mMixerChannelMask == AUDIO_CHANNEL_OUT_STEREO // TODO: MONO_HACK - && t.channelMask == AUDIO_CHANNEL_OUT_MONO) - ? TRACKTYPE_NORESAMPLEMONO : TRACKTYPE_NORESAMPLE, - t.mMixerChannelCount, - t.mMixerInFormat, t.mMixerFormat); - all16BitsStereoNoResample = false; - } - if ((n & NEEDS_CHANNEL_COUNT__MASK) >= NEEDS_CHANNEL_2){ - t.hook = getTrackHook(TRACKTYPE_NORESAMPLE, t.mMixerChannelCount, - t.mMixerInFormat, t.mMixerFormat); - ALOGV_IF((n & NEEDS_CHANNEL_COUNT__MASK) > NEEDS_CHANNEL_2, - "Track %d needs downmix", i); - } - } - } - } - - // select the processing hooks - state->hook = process__nop; - if (countActiveTracks > 0) { - if (resampling) { - if (!state->outputTemp) { - state->outputTemp = new int32_t[MAX_NUM_CHANNELS * state->frameCount]; - } - if (!state->resampleTemp) { - state->resampleTemp = new int32_t[MAX_NUM_CHANNELS * state->frameCount]; - } - state->hook = process__genericResampling; - } else { - if (state->outputTemp) { - delete [] state->outputTemp; - state->outputTemp = NULL; - } - if (state->resampleTemp) { - delete [] state->resampleTemp; - state->resampleTemp = NULL; - } - state->hook = process__genericNoResampling; - if (all16BitsStereoNoResample && !volumeRamp) { - if (countActiveTracks == 1) { - const int i = 31 - __builtin_clz(state->enabledTracks); - track_t& t = state->tracks[i]; - if ((t.needs & NEEDS_MUTE) == 0) { - // The check prevents a muted track from acquiring a process hook. - // - // This is dangerous if the track is MONO as that requires - // special case handling due to implicit channel duplication. - // Stereo or Multichannel should actually be fine here. - state->hook = getProcessHook(PROCESSTYPE_NORESAMPLEONETRACK, - t.mMixerChannelCount, t.mMixerInFormat, t.mMixerFormat); - } - } - } - } - } - - ALOGV("mixer configuration change: %d activeTracks (%08x) " - "all16BitsStereoNoResample=%d, resampling=%d, volumeRamp=%d", - countActiveTracks, state->enabledTracks, - all16BitsStereoNoResample, resampling, volumeRamp); - - state->hook(state, pts); - - // Now that the volume ramp has been done, set optimal state and - // track hooks for subsequent mixer process - if (countActiveTracks > 0) { - bool allMuted = true; - uint32_t en = state->enabledTracks; - while (en) { - const int i = 31 - __builtin_clz(en); - en &= ~(1<tracks[i]; - if (!t.doesResample() && t.volumeRL == 0) { - t.needs |= NEEDS_MUTE; - t.hook = track__nop; - } else { - allMuted = false; - } - } - if (allMuted) { - state->hook = process__nop; - } else if (all16BitsStereoNoResample) { - if (countActiveTracks == 1) { - const int i = 31 - __builtin_clz(state->enabledTracks); - track_t& t = state->tracks[i]; - // Muted single tracks handled by allMuted above. - state->hook = getProcessHook(PROCESSTYPE_NORESAMPLEONETRACK, - t.mMixerChannelCount, t.mMixerInFormat, t.mMixerFormat); - } - } - } -} - - -void AudioMixer::track__genericResample(track_t* t, int32_t* out, size_t outFrameCount, - int32_t* temp, int32_t* aux) -{ - ALOGVV("track__genericResample\n"); - t->resampler->setSampleRate(t->sampleRate); - - // ramp gain - resample to temp buffer and scale/mix in 2nd step - if (aux != NULL) { - // always resample with unity gain when sending to auxiliary buffer to be able - // to apply send level after resampling - t->resampler->setVolume(UNITY_GAIN_FLOAT, UNITY_GAIN_FLOAT); - memset(temp, 0, outFrameCount * t->mMixerChannelCount * sizeof(int32_t)); - t->resampler->resample(temp, outFrameCount, t->bufferProvider); - if (CC_UNLIKELY(t->volumeInc[0]|t->volumeInc[1]|t->auxInc)) { - volumeRampStereo(t, out, outFrameCount, temp, aux); - } else { - volumeStereo(t, out, outFrameCount, temp, aux); - } - } else { - if (CC_UNLIKELY(t->volumeInc[0]|t->volumeInc[1])) { - t->resampler->setVolume(UNITY_GAIN_FLOAT, UNITY_GAIN_FLOAT); - memset(temp, 0, outFrameCount * MAX_NUM_CHANNELS * sizeof(int32_t)); - t->resampler->resample(temp, outFrameCount, t->bufferProvider); - volumeRampStereo(t, out, outFrameCount, temp, aux); - } - - // constant gain - else { - t->resampler->setVolume(t->mVolume[0], t->mVolume[1]); - t->resampler->resample(out, outFrameCount, t->bufferProvider); - } - } -} - -void AudioMixer::track__nop(track_t* t __unused, int32_t* out __unused, - size_t outFrameCount __unused, int32_t* temp __unused, int32_t* aux __unused) -{ -} - -void AudioMixer::volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, - int32_t* aux) -{ - int32_t vl = t->prevVolume[0]; - int32_t vr = t->prevVolume[1]; - const int32_t vlInc = t->volumeInc[0]; - const int32_t vrInc = t->volumeInc[1]; - - //ALOGD("[0] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d", - // t, vlInc/65536.0f, vl/65536.0f, t->volume[0], - // (vl + vlInc*frameCount)/65536.0f, frameCount); - - // ramp volume - if (CC_UNLIKELY(aux != NULL)) { - int32_t va = t->prevAuxLevel; - const int32_t vaInc = t->auxInc; - int32_t l; - int32_t r; - - do { - l = (*temp++ >> 12); - r = (*temp++ >> 12); - *out++ += (vl >> 16) * l; - *out++ += (vr >> 16) * r; - *aux++ += (va >> 17) * (l + r); - vl += vlInc; - vr += vrInc; - va += vaInc; - } while (--frameCount); - t->prevAuxLevel = va; - } else { - do { - *out++ += (vl >> 16) * (*temp++ >> 12); - *out++ += (vr >> 16) * (*temp++ >> 12); - vl += vlInc; - vr += vrInc; - } while (--frameCount); - } - t->prevVolume[0] = vl; - t->prevVolume[1] = vr; - t->adjustVolumeRamp(aux != NULL); -} - -void AudioMixer::volumeStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, - int32_t* aux) -{ - const int16_t vl = t->volume[0]; - const int16_t vr = t->volume[1]; - - if (CC_UNLIKELY(aux != NULL)) { - const int16_t va = t->auxLevel; - do { - int16_t l = (int16_t)(*temp++ >> 12); - int16_t r = (int16_t)(*temp++ >> 12); - out[0] = mulAdd(l, vl, out[0]); - int16_t a = (int16_t)(((int32_t)l + r) >> 1); - out[1] = mulAdd(r, vr, out[1]); - out += 2; - aux[0] = mulAdd(a, va, aux[0]); - aux++; - } while (--frameCount); - } else { - do { - int16_t l = (int16_t)(*temp++ >> 12); - int16_t r = (int16_t)(*temp++ >> 12); - out[0] = mulAdd(l, vl, out[0]); - out[1] = mulAdd(r, vr, out[1]); - out += 2; - } while (--frameCount); - } -} - -void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount, - int32_t* temp __unused, int32_t* aux) -{ - ALOGVV("track__16BitsStereo\n"); - const int16_t *in = static_cast(t->in); - - if (CC_UNLIKELY(aux != NULL)) { - int32_t l; - int32_t r; - // ramp gain - if (CC_UNLIKELY(t->volumeInc[0]|t->volumeInc[1]|t->auxInc)) { - int32_t vl = t->prevVolume[0]; - int32_t vr = t->prevVolume[1]; - int32_t va = t->prevAuxLevel; - const int32_t vlInc = t->volumeInc[0]; - const int32_t vrInc = t->volumeInc[1]; - const int32_t vaInc = t->auxInc; - // ALOGD("[1] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d", - // t, vlInc/65536.0f, vl/65536.0f, t->volume[0], - // (vl + vlInc*frameCount)/65536.0f, frameCount); - - do { - l = (int32_t)*in++; - r = (int32_t)*in++; - *out++ += (vl >> 16) * l; - *out++ += (vr >> 16) * r; - *aux++ += (va >> 17) * (l + r); - vl += vlInc; - vr += vrInc; - va += vaInc; - } while (--frameCount); - - t->prevVolume[0] = vl; - t->prevVolume[1] = vr; - t->prevAuxLevel = va; - t->adjustVolumeRamp(true); - } - - // constant gain - else { - const uint32_t vrl = t->volumeRL; - const int16_t va = (int16_t)t->auxLevel; - do { - uint32_t rl = *reinterpret_cast(in); - int16_t a = (int16_t)(((int32_t)in[0] + in[1]) >> 1); - in += 2; - out[0] = mulAddRL(1, rl, vrl, out[0]); - out[1] = mulAddRL(0, rl, vrl, out[1]); - out += 2; - aux[0] = mulAdd(a, va, aux[0]); - aux++; - } while (--frameCount); - } - } else { - // ramp gain - if (CC_UNLIKELY(t->volumeInc[0]|t->volumeInc[1])) { - int32_t vl = t->prevVolume[0]; - int32_t vr = t->prevVolume[1]; - const int32_t vlInc = t->volumeInc[0]; - const int32_t vrInc = t->volumeInc[1]; - - // ALOGD("[1] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d", - // t, vlInc/65536.0f, vl/65536.0f, t->volume[0], - // (vl + vlInc*frameCount)/65536.0f, frameCount); - - do { - *out++ += (vl >> 16) * (int32_t) *in++; - *out++ += (vr >> 16) * (int32_t) *in++; - vl += vlInc; - vr += vrInc; - } while (--frameCount); - - t->prevVolume[0] = vl; - t->prevVolume[1] = vr; - t->adjustVolumeRamp(false); - } - - // constant gain - else { - const uint32_t vrl = t->volumeRL; - do { - uint32_t rl = *reinterpret_cast(in); - in += 2; - out[0] = mulAddRL(1, rl, vrl, out[0]); - out[1] = mulAddRL(0, rl, vrl, out[1]); - out += 2; - } while (--frameCount); - } - } - t->in = in; -} - -void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount, - int32_t* temp __unused, int32_t* aux) -{ - ALOGVV("track__16BitsMono\n"); - const int16_t *in = static_cast(t->in); - - if (CC_UNLIKELY(aux != NULL)) { - // ramp gain - if (CC_UNLIKELY(t->volumeInc[0]|t->volumeInc[1]|t->auxInc)) { - int32_t vl = t->prevVolume[0]; - int32_t vr = t->prevVolume[1]; - int32_t va = t->prevAuxLevel; - const int32_t vlInc = t->volumeInc[0]; - const int32_t vrInc = t->volumeInc[1]; - const int32_t vaInc = t->auxInc; - - // ALOGD("[2] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d", - // t, vlInc/65536.0f, vl/65536.0f, t->volume[0], - // (vl + vlInc*frameCount)/65536.0f, frameCount); - - do { - int32_t l = *in++; - *out++ += (vl >> 16) * l; - *out++ += (vr >> 16) * l; - *aux++ += (va >> 16) * l; - vl += vlInc; - vr += vrInc; - va += vaInc; - } while (--frameCount); - - t->prevVolume[0] = vl; - t->prevVolume[1] = vr; - t->prevAuxLevel = va; - t->adjustVolumeRamp(true); - } - // constant gain - else { - const int16_t vl = t->volume[0]; - const int16_t vr = t->volume[1]; - const int16_t va = (int16_t)t->auxLevel; - do { - int16_t l = *in++; - out[0] = mulAdd(l, vl, out[0]); - out[1] = mulAdd(l, vr, out[1]); - out += 2; - aux[0] = mulAdd(l, va, aux[0]); - aux++; - } while (--frameCount); - } - } else { - // ramp gain - if (CC_UNLIKELY(t->volumeInc[0]|t->volumeInc[1])) { - int32_t vl = t->prevVolume[0]; - int32_t vr = t->prevVolume[1]; - const int32_t vlInc = t->volumeInc[0]; - const int32_t vrInc = t->volumeInc[1]; - - // ALOGD("[2] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d", - // t, vlInc/65536.0f, vl/65536.0f, t->volume[0], - // (vl + vlInc*frameCount)/65536.0f, frameCount); - - do { - int32_t l = *in++; - *out++ += (vl >> 16) * l; - *out++ += (vr >> 16) * l; - vl += vlInc; - vr += vrInc; - } while (--frameCount); - - t->prevVolume[0] = vl; - t->prevVolume[1] = vr; - t->adjustVolumeRamp(false); - } - // constant gain - else { - const int16_t vl = t->volume[0]; - const int16_t vr = t->volume[1]; - do { - int16_t l = *in++; - out[0] = mulAdd(l, vl, out[0]); - out[1] = mulAdd(l, vr, out[1]); - out += 2; - } while (--frameCount); - } - } - t->in = in; -} - -// no-op case -void AudioMixer::process__nop(state_t* state, int64_t pts) -{ - ALOGVV("process__nop\n"); - uint32_t e0 = state->enabledTracks; - while (e0) { - // process by group of tracks with same output buffer to - // avoid multiple memset() on same buffer - uint32_t e1 = e0, e2 = e0; - int i = 31 - __builtin_clz(e1); - { - track_t& t1 = state->tracks[i]; - e2 &= ~(1<tracks[i]; - if (CC_UNLIKELY(t2.mainBuffer != t1.mainBuffer)) { - e1 &= ~(1<frameCount * t1.mMixerChannelCount - * audio_bytes_per_sample(t1.mMixerFormat)); - } - - while (e1) { - i = 31 - __builtin_clz(e1); - e1 &= ~(1<tracks[i]; - size_t outFrames = state->frameCount; - while (outFrames) { - t3.buffer.frameCount = outFrames; - int64_t outputPTS = calculateOutputPTS( - t3, pts, state->frameCount - outFrames); - t3.bufferProvider->getNextBuffer(&t3.buffer, outputPTS); - if (t3.buffer.raw == NULL) break; - outFrames -= t3.buffer.frameCount; - t3.bufferProvider->releaseBuffer(&t3.buffer); - } - } - } - } -} - -// generic code without resampling -void AudioMixer::process__genericNoResampling(state_t* state, int64_t pts) -{ - ALOGVV("process__genericNoResampling\n"); - int32_t outTemp[BLOCKSIZE * MAX_NUM_CHANNELS] __attribute__((aligned(32))); - - // acquire each track's buffer - uint32_t enabledTracks = state->enabledTracks; - uint32_t e0 = enabledTracks; - while (e0) { - const int i = 31 - __builtin_clz(e0); - e0 &= ~(1<tracks[i]; - t.buffer.frameCount = state->frameCount; - t.bufferProvider->getNextBuffer(&t.buffer, pts); - t.frameCount = t.buffer.frameCount; - t.in = t.buffer.raw; - } - - e0 = enabledTracks; - while (e0) { - // process by group of tracks with same output buffer to - // optimize cache use - uint32_t e1 = e0, e2 = e0; - int j = 31 - __builtin_clz(e1); - track_t& t1 = state->tracks[j]; - e2 &= ~(1<tracks[j]; - if (CC_UNLIKELY(t2.mainBuffer != t1.mainBuffer)) { - e1 &= ~(1<tracks[i]; - size_t outFrames = BLOCKSIZE; - int32_t *aux = NULL; - if (CC_UNLIKELY(t.needs & NEEDS_AUX)) { - aux = t.auxBuffer + numFrames; - } - while (outFrames) { - // t.in == NULL can happen if the track was flushed just after having - // been enabled for mixing. - if (t.in == NULL) { - enabledTracks &= ~(1< outFrames)?outFrames:t.frameCount; - if (inFrames > 0) { - t.hook(&t, outTemp + (BLOCKSIZE - outFrames) * t.mMixerChannelCount, - inFrames, state->resampleTemp, aux); - t.frameCount -= inFrames; - outFrames -= inFrames; - if (CC_UNLIKELY(aux != NULL)) { - aux += inFrames; - } - } - if (t.frameCount == 0 && outFrames) { - t.bufferProvider->releaseBuffer(&t.buffer); - t.buffer.frameCount = (state->frameCount - numFrames) - - (BLOCKSIZE - outFrames); - int64_t outputPTS = calculateOutputPTS( - t, pts, numFrames + (BLOCKSIZE - outFrames)); - t.bufferProvider->getNextBuffer(&t.buffer, outputPTS); - t.in = t.buffer.raw; - if (t.in == NULL) { - enabledTracks &= ~(1<((uint8_t*)out - + BLOCKSIZE * t1.mMixerChannelCount - * audio_bytes_per_sample(t1.mMixerFormat)); - numFrames += BLOCKSIZE; - } while (numFrames < state->frameCount); - } - - // release each track's buffer - e0 = enabledTracks; - while (e0) { - const int i = 31 - __builtin_clz(e0); - e0 &= ~(1<tracks[i]; - t.bufferProvider->releaseBuffer(&t.buffer); - } -} - - -// generic code with resampling -void AudioMixer::process__genericResampling(state_t* state, int64_t pts) -{ - ALOGVV("process__genericResampling\n"); - // this const just means that local variable outTemp doesn't change - int32_t* const outTemp = state->outputTemp; - size_t numFrames = state->frameCount; - - uint32_t e0 = state->enabledTracks; - while (e0) { - // process by group of tracks with same output buffer - // to optimize cache use - uint32_t e1 = e0, e2 = e0; - int j = 31 - __builtin_clz(e1); - track_t& t1 = state->tracks[j]; - e2 &= ~(1<tracks[j]; - if (CC_UNLIKELY(t2.mainBuffer != t1.mainBuffer)) { - e1 &= ~(1<frameCount); - while (e1) { - const int i = 31 - __builtin_clz(e1); - e1 &= ~(1<tracks[i]; - int32_t *aux = NULL; - if (CC_UNLIKELY(t.needs & NEEDS_AUX)) { - aux = t.auxBuffer; - } - - // this is a little goofy, on the resampling case we don't - // acquire/release the buffers because it's done by - // the resampler. - if (t.needs & NEEDS_RESAMPLE) { - t.resampler->setPTS(pts); - t.hook(&t, outTemp, numFrames, state->resampleTemp, aux); - } else { - - size_t outFrames = 0; - - while (outFrames < numFrames) { - t.buffer.frameCount = numFrames - outFrames; - int64_t outputPTS = calculateOutputPTS(t, pts, outFrames); - t.bufferProvider->getNextBuffer(&t.buffer, outputPTS); - t.in = t.buffer.raw; - // t.in == NULL can happen if the track was flushed just after having - // been enabled for mixing. - if (t.in == NULL) break; - - if (CC_UNLIKELY(aux != NULL)) { - aux += outFrames; - } - t.hook(&t, outTemp + outFrames * t.mMixerChannelCount, t.buffer.frameCount, - state->resampleTemp, aux); - outFrames += t.buffer.frameCount; - t.bufferProvider->releaseBuffer(&t.buffer); - } - } - } - convertMixerFormat(out, t1.mMixerFormat, - outTemp, t1.mMixerInFormat, numFrames * t1.mMixerChannelCount); - } -} - -// one track, 16 bits stereo without resampling is the most common case -void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state, - int64_t pts) -{ - ALOGVV("process__OneTrack16BitsStereoNoResampling\n"); - // This method is only called when state->enabledTracks has exactly - // one bit set. The asserts below would verify this, but are commented out - // since the whole point of this method is to optimize performance. - //ALOG_ASSERT(0 != state->enabledTracks, "no tracks enabled"); - const int i = 31 - __builtin_clz(state->enabledTracks); - //ALOG_ASSERT((1 << i) == state->enabledTracks, "more than 1 track enabled"); - const track_t& t = state->tracks[i]; - - AudioBufferProvider::Buffer& b(t.buffer); - - int32_t* out = t.mainBuffer; - float *fout = reinterpret_cast(out); - size_t numFrames = state->frameCount; - - const int16_t vl = t.volume[0]; - const int16_t vr = t.volume[1]; - const uint32_t vrl = t.volumeRL; - while (numFrames) { - b.frameCount = numFrames; - int64_t outputPTS = calculateOutputPTS(t, pts, out - t.mainBuffer); - t.bufferProvider->getNextBuffer(&b, outputPTS); - const int16_t *in = b.i16; - - // in == NULL can happen if the track was flushed just after having - // been enabled for mixing. - if (in == NULL || (((uintptr_t)in) & 3)) { - memset(out, 0, numFrames - * t.mMixerChannelCount * audio_bytes_per_sample(t.mMixerFormat)); - ALOGE_IF((((uintptr_t)in) & 3), - "process__OneTrack16BitsStereoNoResampling: misaligned buffer" - " %p track %d, channels %d, needs %08x, volume %08x vfl %f vfr %f", - in, i, t.channelCount, t.needs, vrl, t.mVolume[0], t.mVolume[1]); - return; - } - size_t outFrames = b.frameCount; - - switch (t.mMixerFormat) { - case AUDIO_FORMAT_PCM_FLOAT: - do { - uint32_t rl = *reinterpret_cast(in); - in += 2; - int32_t l = mulRL(1, rl, vrl); - int32_t r = mulRL(0, rl, vrl); - *fout++ = float_from_q4_27(l); - *fout++ = float_from_q4_27(r); - // Note: In case of later int16_t sink output, - // conversion and clamping is done by memcpy_to_i16_from_float(). - } while (--outFrames); - break; - case AUDIO_FORMAT_PCM_16_BIT: - if (CC_UNLIKELY(uint32_t(vl) > UNITY_GAIN_INT || uint32_t(vr) > UNITY_GAIN_INT)) { - // volume is boosted, so we might need to clamp even though - // we process only one track. - do { - uint32_t rl = *reinterpret_cast(in); - in += 2; - int32_t l = mulRL(1, rl, vrl) >> 12; - int32_t r = mulRL(0, rl, vrl) >> 12; - // clamping... - l = clamp16(l); - r = clamp16(r); - *out++ = (r<<16) | (l & 0xFFFF); - } while (--outFrames); - } else { - do { - uint32_t rl = *reinterpret_cast(in); - in += 2; - int32_t l = mulRL(1, rl, vrl) >> 12; - int32_t r = mulRL(0, rl, vrl) >> 12; - *out++ = (r<<16) | (l & 0xFFFF); - } while (--outFrames); - } - break; - default: - LOG_ALWAYS_FATAL("bad mixer format: %d", t.mMixerFormat); - } - numFrames -= b.frameCount; - t.bufferProvider->releaseBuffer(&b); - } -} - -int64_t AudioMixer::calculateOutputPTS(const track_t& t, int64_t basePTS, - int outputFrameIndex) -{ - if (AudioBufferProvider::kInvalidPTS == basePTS) { - return AudioBufferProvider::kInvalidPTS; - } - - return basePTS + ((outputFrameIndex * sLocalTimeFreq) / t.sampleRate); -} - -/*static*/ uint64_t AudioMixer::sLocalTimeFreq; -/*static*/ pthread_once_t AudioMixer::sOnceControl = PTHREAD_ONCE_INIT; - -/*static*/ void AudioMixer::sInitRoutine() -{ -//cjh LocalClock lc; -// sLocalTimeFreq = lc.getLocalFreq(); // for the resampler -// -// DownmixerBufferProvider::init(); // for the downmixer -} - -/* TODO: consider whether this level of optimization is necessary. - * Perhaps just stick with a single for loop. - */ - -// Needs to derive a compile time constant (constexpr). Could be targeted to go -// to a MONOVOL mixtype based on MAX_NUM_VOLUMES, but that's an unnecessary complication. -#define MIXTYPE_MONOVOL(mixtype) (mixtype == MIXTYPE_MULTI ? MIXTYPE_MULTI_MONOVOL : \ - mixtype == MIXTYPE_MULTI_SAVEONLY ? MIXTYPE_MULTI_SAVEONLY_MONOVOL : mixtype) - -/* MIXTYPE (see AudioMixerOps.h MIXTYPE_* enumeration) - * TO: int32_t (Q4.27) or float - * TI: int32_t (Q4.27) or int16_t (Q0.15) or float - * TA: int32_t (Q4.27) - */ -template -static void volumeRampMulti(uint32_t channels, TO* out, size_t frameCount, - const TI* in, TA* aux, TV *vol, const TV *volinc, TAV *vola, TAV volainc) -{ - switch (channels) { - case 1: - volumeRampMulti(out, frameCount, in, aux, vol, volinc, vola, volainc); - break; - case 2: - volumeRampMulti(out, frameCount, in, aux, vol, volinc, vola, volainc); - break; - case 3: - volumeRampMulti(out, - frameCount, in, aux, vol, volinc, vola, volainc); - break; - case 4: - volumeRampMulti(out, - frameCount, in, aux, vol, volinc, vola, volainc); - break; - case 5: - volumeRampMulti(out, - frameCount, in, aux, vol, volinc, vola, volainc); - break; - case 6: - volumeRampMulti(out, - frameCount, in, aux, vol, volinc, vola, volainc); - break; - case 7: - volumeRampMulti(out, - frameCount, in, aux, vol, volinc, vola, volainc); - break; - case 8: - volumeRampMulti(out, - frameCount, in, aux, vol, volinc, vola, volainc); - break; - } -} - -/* MIXTYPE (see AudioMixerOps.h MIXTYPE_* enumeration) - * TO: int32_t (Q4.27) or float - * TI: int32_t (Q4.27) or int16_t (Q0.15) or float - * TA: int32_t (Q4.27) - */ -template -static void volumeMulti(uint32_t channels, TO* out, size_t frameCount, - const TI* in, TA* aux, const TV *vol, TAV vola) -{ - switch (channels) { - case 1: - volumeMulti(out, frameCount, in, aux, vol, vola); - break; - case 2: - volumeMulti(out, frameCount, in, aux, vol, vola); - break; - case 3: - volumeMulti(out, frameCount, in, aux, vol, vola); - break; - case 4: - volumeMulti(out, frameCount, in, aux, vol, vola); - break; - case 5: - volumeMulti(out, frameCount, in, aux, vol, vola); - break; - case 6: - volumeMulti(out, frameCount, in, aux, vol, vola); - break; - case 7: - volumeMulti(out, frameCount, in, aux, vol, vola); - break; - case 8: - volumeMulti(out, frameCount, in, aux, vol, vola); - break; - } -} - -/* MIXTYPE (see AudioMixerOps.h MIXTYPE_* enumeration) - * USEFLOATVOL (set to true if float volume is used) - * ADJUSTVOL (set to true if volume ramp parameters needs adjustment afterwards) - * TO: int32_t (Q4.27) or float - * TI: int32_t (Q4.27) or int16_t (Q0.15) or float - * TA: int32_t (Q4.27) - */ -template -void AudioMixer::volumeMix(TO *out, size_t outFrames, - const TI *in, TA *aux, bool ramp, AudioMixer::track_t *t) -{ - if (USEFLOATVOL) { - if (ramp) { - volumeRampMulti(t->mMixerChannelCount, out, outFrames, in, aux, - t->mPrevVolume, t->mVolumeInc, &t->prevAuxLevel, t->auxInc); - if (ADJUSTVOL) { - t->adjustVolumeRamp(aux != NULL, true); - } - } else { - volumeMulti(t->mMixerChannelCount, out, outFrames, in, aux, - t->mVolume, t->auxLevel); - } - } else { - if (ramp) { - volumeRampMulti(t->mMixerChannelCount, out, outFrames, in, aux, - t->prevVolume, t->volumeInc, &t->prevAuxLevel, t->auxInc); - if (ADJUSTVOL) { - t->adjustVolumeRamp(aux != NULL); - } - } else { - volumeMulti(t->mMixerChannelCount, out, outFrames, in, aux, - t->volume, t->auxLevel); - } - } -} - -/* This process hook is called when there is a single track without - * aux buffer, volume ramp, or resampling. - * TODO: Update the hook selection: this can properly handle aux and ramp. - * - * MIXTYPE (see AudioMixerOps.h MIXTYPE_* enumeration) - * TO: int32_t (Q4.27) or float - * TI: int32_t (Q4.27) or int16_t (Q0.15) or float - * TA: int32_t (Q4.27) - */ -template -void AudioMixer::process_NoResampleOneTrack(state_t* state, int64_t pts) -{ - ALOGVV("process_NoResampleOneTrack\n"); - // CLZ is faster than CTZ on ARM, though really not sure if true after 31 - clz. - const int i = 31 - __builtin_clz(state->enabledTracks); - ALOG_ASSERT((1 << i) == state->enabledTracks, "more than 1 track enabled"); - track_t *t = &state->tracks[i]; - const uint32_t channels = t->mMixerChannelCount; - TO* out = reinterpret_cast(t->mainBuffer); - TA* aux = reinterpret_cast(t->auxBuffer); - const bool ramp = t->needsRamp(); - - for (size_t numFrames = state->frameCount; numFrames; ) { - AudioBufferProvider::Buffer& b(t->buffer); - // get input buffer - b.frameCount = numFrames; - const int64_t outputPTS = calculateOutputPTS(*t, pts, state->frameCount - numFrames); - t->bufferProvider->getNextBuffer(&b, outputPTS); - const TI *in = reinterpret_cast(b.raw); - - // in == NULL can happen if the track was flushed just after having - // been enabled for mixing. - if (in == NULL || (((uintptr_t)in) & 3)) { - memset(out, 0, numFrames - * channels * audio_bytes_per_sample(t->mMixerFormat)); - ALOGE_IF((((uintptr_t)in) & 3), "process_NoResampleOneTrack: bus error: " - "buffer %p track %p, channels %d, needs %#x", - in, t, t->channelCount, t->needs); - return; - } - - const size_t outFrames = b.frameCount; - volumeMix::value, false> ( - out, outFrames, in, aux, ramp, t); - - out += outFrames * channels; - if (aux != NULL) { - aux += channels; - } - numFrames -= b.frameCount; - - // release buffer - t->bufferProvider->releaseBuffer(&b); - } - if (ramp) { - t->adjustVolumeRamp(aux != NULL, is_same::value); - } -} - -/* This track hook is called to do resampling then mixing, - * pulling from the track's upstream AudioBufferProvider. - * - * MIXTYPE (see AudioMixerOps.h MIXTYPE_* enumeration) - * TO: int32_t (Q4.27) or float - * TI: int32_t (Q4.27) or int16_t (Q0.15) or float - * TA: int32_t (Q4.27) - */ -template -void AudioMixer::track__Resample(track_t* t, TO* out, size_t outFrameCount, TO* temp, TA* aux) -{ - ALOGVV("track__Resample\n"); - t->resampler->setSampleRate(t->sampleRate); - const bool ramp = t->needsRamp(); - if (ramp || aux != NULL) { - // if ramp: resample with unity gain to temp buffer and scale/mix in 2nd step. - // if aux != NULL: resample with unity gain to temp buffer then apply send level. - - t->resampler->setVolume(UNITY_GAIN_FLOAT, UNITY_GAIN_FLOAT); - memset(temp, 0, outFrameCount * t->mMixerChannelCount * sizeof(TO)); - t->resampler->resample((int32_t*)temp, outFrameCount, t->bufferProvider); - - volumeMix::value, true>( - out, outFrameCount, temp, aux, ramp, t); - - } else { // constant volume gain - t->resampler->setVolume(t->mVolume[0], t->mVolume[1]); - t->resampler->resample((int32_t*)out, outFrameCount, t->bufferProvider); - } -} - -/* This track hook is called to mix a track, when no resampling is required. - * The input buffer should be present in t->in. - * - * MIXTYPE (see AudioMixerOps.h MIXTYPE_* enumeration) - * TO: int32_t (Q4.27) or float - * TI: int32_t (Q4.27) or int16_t (Q0.15) or float - * TA: int32_t (Q4.27) - */ -template -void AudioMixer::track__NoResample(track_t* t, TO* out, size_t frameCount, - TO* temp __unused, TA* aux) -{ - ALOGVV("track__NoResample\n"); - const TI *in = static_cast(t->in); - - volumeMix::value, true>( - out, frameCount, in, aux, t->needsRamp(), t); - - // MIXTYPE_MONOEXPAND reads a single input channel and expands to NCHAN output channels. - // MIXTYPE_MULTI reads NCHAN input channels and places to NCHAN output channels. - in += (MIXTYPE == MIXTYPE_MONOEXPAND) ? frameCount : frameCount * t->mMixerChannelCount; - t->in = in; -} - -/* The Mixer engine generates either int32_t (Q4_27) or float data. - * We use this function to convert the engine buffers - * to the desired mixer output format, either int16_t (Q.15) or float. - */ -void AudioMixer::convertMixerFormat(void *out, audio_format_t mixerOutFormat, - void *in, audio_format_t mixerInFormat, size_t sampleCount) -{ - switch (mixerInFormat) { - case AUDIO_FORMAT_PCM_FLOAT: - switch (mixerOutFormat) { - case AUDIO_FORMAT_PCM_FLOAT: - memcpy(out, in, sampleCount * sizeof(float)); // MEMCPY. TODO optimize out - break; - case AUDIO_FORMAT_PCM_16_BIT: - memcpy_to_i16_from_float((int16_t*)out, (float*)in, sampleCount); - break; - default: - LOG_ALWAYS_FATAL("bad mixerOutFormat: %#x", mixerOutFormat); - break; - } - break; - case AUDIO_FORMAT_PCM_16_BIT: - switch (mixerOutFormat) { - case AUDIO_FORMAT_PCM_FLOAT: - memcpy_to_float_from_q4_27((float*)out, (int32_t*)in, sampleCount); - break; - case AUDIO_FORMAT_PCM_16_BIT: - // two int16_t are produced per iteration - ditherAndClamp((int32_t*)out, (int32_t*)in, sampleCount >> 1); - break; - default: - LOG_ALWAYS_FATAL("bad mixerOutFormat: %#x", mixerOutFormat); - break; - } - break; - default: - LOG_ALWAYS_FATAL("bad mixerInFormat: %#x", mixerInFormat); - break; - } -} - -/* Returns the proper track hook to use for mixing the track into the output buffer. - */ -AudioMixer::hook_t AudioMixer::getTrackHook(int trackType, uint32_t channelCount, - audio_format_t mixerInFormat, audio_format_t mixerOutFormat __unused) -{ - if (!kUseNewMixer && channelCount == FCC_2 && mixerInFormat == AUDIO_FORMAT_PCM_16_BIT) { - switch (trackType) { - case TRACKTYPE_NOP: - return track__nop; - case TRACKTYPE_RESAMPLE: - return track__genericResample; - case TRACKTYPE_NORESAMPLEMONO: - return track__16BitsMono; - case TRACKTYPE_NORESAMPLE: - return track__16BitsStereo; - default: - LOG_ALWAYS_FATAL("bad trackType: %d", trackType); - break; - } - } - LOG_ALWAYS_FATAL_IF(channelCount > MAX_NUM_CHANNELS); - switch (trackType) { - case TRACKTYPE_NOP: - return track__nop; - case TRACKTYPE_RESAMPLE: - switch (mixerInFormat) { - case AUDIO_FORMAT_PCM_FLOAT: - return (AudioMixer::hook_t) - track__Resample; - case AUDIO_FORMAT_PCM_16_BIT: - return (AudioMixer::hook_t)\ - track__Resample; - default: - LOG_ALWAYS_FATAL("bad mixerInFormat: %#x", mixerInFormat); - break; - } - break; - case TRACKTYPE_NORESAMPLEMONO: - switch (mixerInFormat) { - case AUDIO_FORMAT_PCM_FLOAT: - return (AudioMixer::hook_t) - track__NoResample; - case AUDIO_FORMAT_PCM_16_BIT: - return (AudioMixer::hook_t) - track__NoResample; - default: - LOG_ALWAYS_FATAL("bad mixerInFormat: %#x", mixerInFormat); - break; - } - break; - case TRACKTYPE_NORESAMPLE: - switch (mixerInFormat) { - case AUDIO_FORMAT_PCM_FLOAT: - return (AudioMixer::hook_t) - track__NoResample; - case AUDIO_FORMAT_PCM_16_BIT: - return (AudioMixer::hook_t) - track__NoResample; - default: - LOG_ALWAYS_FATAL("bad mixerInFormat: %#x", mixerInFormat); - break; - } - break; - default: - LOG_ALWAYS_FATAL("bad trackType: %d", trackType); - break; - } - return NULL; -} - -/* Returns the proper process hook for mixing tracks. Currently works only for - * PROCESSTYPE_NORESAMPLEONETRACK, a mix involving one track, no resampling. - * - * TODO: Due to the special mixing considerations of duplicating to - * a stereo output track, the input track cannot be MONO. This should be - * prevented by the caller. - */ -AudioMixer::process_hook_t AudioMixer::getProcessHook(int processType, uint32_t channelCount, - audio_format_t mixerInFormat, audio_format_t mixerOutFormat) -{ - if (processType != PROCESSTYPE_NORESAMPLEONETRACK) { // Only NORESAMPLEONETRACK - LOG_ALWAYS_FATAL("bad processType: %d", processType); - return NULL; - } - if (!kUseNewMixer && channelCount == FCC_2 && mixerInFormat == AUDIO_FORMAT_PCM_16_BIT) { - return process__OneTrack16BitsStereoNoResampling; - } - LOG_ALWAYS_FATAL_IF(channelCount > MAX_NUM_CHANNELS); - switch (mixerInFormat) { - case AUDIO_FORMAT_PCM_FLOAT: - switch (mixerOutFormat) { - case AUDIO_FORMAT_PCM_FLOAT: - return process_NoResampleOneTrack; - case AUDIO_FORMAT_PCM_16_BIT: - return process_NoResampleOneTrack; - default: - LOG_ALWAYS_FATAL("bad mixerOutFormat: %#x", mixerOutFormat); - break; - } - break; - case AUDIO_FORMAT_PCM_16_BIT: - switch (mixerOutFormat) { - case AUDIO_FORMAT_PCM_FLOAT: - return process_NoResampleOneTrack; - case AUDIO_FORMAT_PCM_16_BIT: - return process_NoResampleOneTrack; - default: - LOG_ALWAYS_FATAL("bad mixerOutFormat: %#x", mixerOutFormat); - break; - } - break; - default: - LOG_ALWAYS_FATAL("bad mixerInFormat: %#x", mixerInFormat); - break; - } - return NULL; -} - -// ---------------------------------------------------------------------------- -} // namespace cocos2d { diff --git a/cocos/audio/android/AudioMixer.h b/cocos/audio/android/AudioMixer.h deleted file mode 100644 index dd90ab4..0000000 --- a/cocos/audio/android/AudioMixer.h +++ /dev/null @@ -1,389 +0,0 @@ -/* -** -** Copyright 2007, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -#pragma once - -#include -#include -#include - -#include "audio/android/AudioBufferProvider.h" -#include "audio/android/AudioResamplerPublic.h" - -#include "audio/android/AudioResampler.h" -#include "audio/android/audio.h" - -// FIXME This is actually unity gain, which might not be max in future, expressed in U.12 -#define MAX_GAIN_INT AudioMixer::UNITY_GAIN_INT - -namespace cocos2d { - -// ---------------------------------------------------------------------------- - -class AudioMixer -{ -public: - AudioMixer(size_t frameCount, uint32_t sampleRate, - uint32_t maxNumTracks = MAX_NUM_TRACKS); - - /*virtual*/ ~AudioMixer(); // non-virtual saves a v-table, restore if sub-classed - - - // This mixer has a hard-coded upper limit of 32 active track inputs. - // Adding support for > 32 tracks would require more than simply changing this value. - static const uint32_t MAX_NUM_TRACKS = 32; - // maximum number of channels supported by the mixer - - // This mixer has a hard-coded upper limit of 8 channels for output. - static const uint32_t MAX_NUM_CHANNELS = 8; - static const uint32_t MAX_NUM_VOLUMES = 2; // stereo volume only - // maximum number of channels supported for the content - static const uint32_t MAX_NUM_CHANNELS_TO_DOWNMIX = AUDIO_CHANNEL_COUNT_MAX; - - static const uint16_t UNITY_GAIN_INT = 0x1000; - static const CONSTEXPR float UNITY_GAIN_FLOAT = 1.0f; - - enum { // names - - // track names (MAX_NUM_TRACKS units) - TRACK0 = 0x1000, - - // 0x2000 is unused - - // setParameter targets - TRACK = 0x3000, - RESAMPLE = 0x3001, - RAMP_VOLUME = 0x3002, // ramp to new volume - VOLUME = 0x3003, // don't ramp - TIMESTRETCH = 0x3004, - - // set Parameter names - // for target TRACK - CHANNEL_MASK = 0x4000, - FORMAT = 0x4001, - MAIN_BUFFER = 0x4002, - AUX_BUFFER = 0x4003, - DOWNMIX_TYPE = 0X4004, - MIXER_FORMAT = 0x4005, // AUDIO_FORMAT_PCM_(FLOAT|16_BIT) - MIXER_CHANNEL_MASK = 0x4006, // Channel mask for mixer output - // for target RESAMPLE - SAMPLE_RATE = 0x4100, // Configure sample rate conversion on this track name; - // parameter 'value' is the new sample rate in Hz. - // Only creates a sample rate converter the first time that - // the track sample rate is different from the mix sample rate. - // If the new sample rate is the same as the mix sample rate, - // and a sample rate converter already exists, - // then the sample rate converter remains present but is a no-op. - RESET = 0x4101, // Reset sample rate converter without changing sample rate. - // This clears out the resampler's input buffer. - REMOVE = 0x4102, // Remove the sample rate converter on this track name; - // the track is restored to the mix sample rate. - // for target RAMP_VOLUME and VOLUME (8 channels max) - // FIXME use float for these 3 to improve the dynamic range - VOLUME0 = 0x4200, - VOLUME1 = 0x4201, - AUXLEVEL = 0x4210, - // for target TIMESTRETCH - PLAYBACK_RATE = 0x4300, // Configure timestretch on this track name; - // parameter 'value' is a pointer to the new playback rate. - }; - - - // For all APIs with "name": TRACK0 <= name < TRACK0 + MAX_NUM_TRACKS - - // Allocate a track name. Returns new track name if successful, -1 on failure. - // The failure could be because of an invalid channelMask or format, or that - // the track capacity of the mixer is exceeded. - int getTrackName(audio_channel_mask_t channelMask, - audio_format_t format, int sessionId); - - // Free an allocated track by name - void deleteTrackName(int name); - - // Enable or disable an allocated track by name - void enable(int name); - void disable(int name); - - void setParameter(int name, int target, int param, void *value); - - void setBufferProvider(int name, AudioBufferProvider* bufferProvider); - void process(int64_t pts); - - uint32_t trackNames() const { return mTrackNames; } - - size_t getUnreleasedFrames(int name) const; - - static inline bool isValidPcmTrackFormat(audio_format_t format) { - switch (format) { - case AUDIO_FORMAT_PCM_8_BIT: - case AUDIO_FORMAT_PCM_16_BIT: - case AUDIO_FORMAT_PCM_24_BIT_PACKED: - case AUDIO_FORMAT_PCM_32_BIT: - case AUDIO_FORMAT_PCM_FLOAT: - return true; - default: - return false; - } - } - -private: - - enum { - // FIXME this representation permits up to 8 channels - NEEDS_CHANNEL_COUNT__MASK = 0x00000007, - }; - - enum { - NEEDS_CHANNEL_1 = 0x00000000, // mono - NEEDS_CHANNEL_2 = 0x00000001, // stereo - - // sample format is not explicitly specified, and is assumed to be AUDIO_FORMAT_PCM_16_BIT - - NEEDS_MUTE = 0x00000100, - NEEDS_RESAMPLE = 0x00001000, - NEEDS_AUX = 0x00010000, - }; - - struct state_t; - struct track_t; - - typedef void (*hook_t)(track_t* t, int32_t* output, size_t numOutFrames, int32_t* temp, - int32_t* aux); - static const int BLOCKSIZE = 16; // 4 cache lines - - struct track_t { - uint32_t needs; - - // TODO: Eventually remove legacy integer volume settings - union { - int16_t volume[MAX_NUM_VOLUMES]; // U4.12 fixed point (top bit should be zero) - int32_t volumeRL; - }; - - int32_t prevVolume[MAX_NUM_VOLUMES]; - - // 16-byte boundary - - int32_t volumeInc[MAX_NUM_VOLUMES]; - int32_t auxInc; - int32_t prevAuxLevel; - - // 16-byte boundary - - int16_t auxLevel; // 0 <= auxLevel <= MAX_GAIN_INT, but signed for mul performance - uint16_t frameCount; - - uint8_t channelCount; // 1 or 2, redundant with (needs & NEEDS_CHANNEL_COUNT__MASK) - uint8_t unused_padding; // formerly format, was always 16 - uint16_t enabled; // actually bool - audio_channel_mask_t channelMask; - - // actual buffer provider used by the track hooks, see DownmixerBufferProvider below - // for how the Track buffer provider is wrapped by another one when dowmixing is required - AudioBufferProvider* bufferProvider; - - // 16-byte boundary - - mutable AudioBufferProvider::Buffer buffer; // 8 bytes - - hook_t hook; - const void* in; // current location in buffer - - // 16-byte boundary - - AudioResampler* resampler; - uint32_t sampleRate; - int32_t* mainBuffer; - int32_t* auxBuffer; - - // 16-byte boundary - - /* Buffer providers are constructed to translate the track input data as needed. - * - * TODO: perhaps make a single PlaybackConverterProvider class to move - * all pre-mixer track buffer conversions outside the AudioMixer class. - * - * 1) mInputBufferProvider: The AudioTrack buffer provider. - * 2) mReformatBufferProvider: If not NULL, performs the audio reformat to - * match either mMixerInFormat or mDownmixRequiresFormat, if the downmixer - * requires reformat. For example, it may convert floating point input to - * PCM_16_bit if that's required by the downmixer. - * 3) downmixerBufferProvider: If not NULL, performs the channel remixing to match - * the number of channels required by the mixer sink. - * 4) mPostDownmixReformatBufferProvider: If not NULL, performs reformatting from - * the downmixer requirements to the mixer engine input requirements. - * 5) mTimestretchBufferProvider: Adds timestretching for playback rate - */ - AudioBufferProvider* mInputBufferProvider; // externally provided buffer provider. -//cjh PassthruBufferProvider* mReformatBufferProvider; // provider wrapper for reformatting. -// PassthruBufferProvider* downmixerBufferProvider; // wrapper for channel conversion. -// PassthruBufferProvider* mPostDownmixReformatBufferProvider; -// PassthruBufferProvider* mTimestretchBufferProvider; - - int32_t sessionId; - - audio_format_t mMixerFormat; // output mix format: AUDIO_FORMAT_PCM_(FLOAT|16_BIT) - audio_format_t mFormat; // input track format - audio_format_t mMixerInFormat; // mix internal format AUDIO_FORMAT_PCM_(FLOAT|16_BIT) - // each track must be converted to this format. - audio_format_t mDownmixRequiresFormat; // required downmixer format - // AUDIO_FORMAT_PCM_16_BIT if 16 bit necessary - // AUDIO_FORMAT_INVALID if no required format - - float mVolume[MAX_NUM_VOLUMES]; // floating point set volume - float mPrevVolume[MAX_NUM_VOLUMES]; // floating point previous volume - float mVolumeInc[MAX_NUM_VOLUMES]; // floating point volume increment - - float mAuxLevel; // floating point set aux level - float mPrevAuxLevel; // floating point prev aux level - float mAuxInc; // floating point aux increment - - audio_channel_mask_t mMixerChannelMask; - uint32_t mMixerChannelCount; - - AudioPlaybackRate mPlaybackRate; - - bool needsRamp() { return (volumeInc[0] | volumeInc[1] | auxInc) != 0; } - bool setResampler(uint32_t trackSampleRate, uint32_t devSampleRate); - bool doesResample() const { return resampler != NULL; } - void resetResampler() { if (resampler != NULL) resampler->reset(); } - void adjustVolumeRamp(bool aux, bool useFloat = false); - size_t getUnreleasedFrames() const { return resampler != NULL ? - resampler->getUnreleasedFrames() : 0; }; - - status_t prepareForDownmix(); - void unprepareForDownmix(); - status_t prepareForReformat(); - void unprepareForReformat(); - bool setPlaybackRate(const AudioPlaybackRate &playbackRate); - void reconfigureBufferProviders(); - }; - - typedef void (*process_hook_t)(state_t* state, int64_t pts); - - // pad to 32-bytes to fill cache line - struct state_t { - uint32_t enabledTracks; - uint32_t needsChanged; - size_t frameCount; - process_hook_t hook; // one of process__*, never NULL - int32_t *outputTemp; - int32_t *resampleTemp; -//cjh NBLog::Writer* mLog; - int32_t reserved[1]; - // FIXME allocate dynamically to save some memory when maxNumTracks < MAX_NUM_TRACKS - track_t tracks[MAX_NUM_TRACKS] __attribute__((aligned(32))); - }; - - // bitmask of allocated track names, where bit 0 corresponds to TRACK0 etc. - uint32_t mTrackNames; - - // bitmask of configured track names; ~0 if maxNumTracks == MAX_NUM_TRACKS, - // but will have fewer bits set if maxNumTracks < MAX_NUM_TRACKS - const uint32_t mConfiguredNames; - - const uint32_t mSampleRate; - -//cjh NBLog::Writer mDummyLog; -public: -//cjh void setLog(NBLog::Writer* log); -private: - state_t mState __attribute__((aligned(32))); - - // Call after changing either the enabled status of a track, or parameters of an enabled track. - // OK to call more often than that, but unnecessary. - void invalidateState(uint32_t mask); - - bool setChannelMasks(int name, - audio_channel_mask_t trackChannelMask, audio_channel_mask_t mixerChannelMask); - - static void track__genericResample(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, - int32_t* aux); - static void track__nop(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux); - static void track__16BitsStereo(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, - int32_t* aux); - static void track__16BitsMono(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, - int32_t* aux); - static void volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, - int32_t* aux); - static void volumeStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, - int32_t* aux); - - static void process__validate(state_t* state, int64_t pts); - static void process__nop(state_t* state, int64_t pts); - static void process__genericNoResampling(state_t* state, int64_t pts); - static void process__genericResampling(state_t* state, int64_t pts); - static void process__OneTrack16BitsStereoNoResampling(state_t* state, - int64_t pts); - - static int64_t calculateOutputPTS(const track_t& t, int64_t basePTS, - int outputFrameIndex); - - static uint64_t sLocalTimeFreq; - static pthread_once_t sOnceControl; - static void sInitRoutine(); - - /* multi-format volume mixing function (calls template functions - * in AudioMixerOps.h). The template parameters are as follows: - * - * MIXTYPE (see AudioMixerOps.h MIXTYPE_* enumeration) - * USEFLOATVOL (set to true if float volume is used) - * ADJUSTVOL (set to true if volume ramp parameters needs adjustment afterwards) - * TO: int32_t (Q4.27) or float - * TI: int32_t (Q4.27) or int16_t (Q0.15) or float - * TA: int32_t (Q4.27) - */ - template - static void volumeMix(TO *out, size_t outFrames, - const TI *in, TA *aux, bool ramp, AudioMixer::track_t *t); - - // multi-format process hooks - template - static void process_NoResampleOneTrack(state_t* state, int64_t pts); - - // multi-format track hooks - template - static void track__Resample(track_t* t, TO* out, size_t frameCount, - TO* temp __unused, TA* aux); - template - static void track__NoResample(track_t* t, TO* out, size_t frameCount, - TO* temp __unused, TA* aux); - - static void convertMixerFormat(void *out, audio_format_t mixerOutFormat, - void *in, audio_format_t mixerInFormat, size_t sampleCount); - - // hook types - enum { - PROCESSTYPE_NORESAMPLEONETRACK, - }; - enum { - TRACKTYPE_NOP, - TRACKTYPE_RESAMPLE, - TRACKTYPE_NORESAMPLE, - TRACKTYPE_NORESAMPLEMONO, - }; - - // functions for determining the proper process and track hooks. - static process_hook_t getProcessHook(int processType, uint32_t channelCount, - audio_format_t mixerInFormat, audio_format_t mixerOutFormat); - static hook_t getTrackHook(int trackType, uint32_t channelCount, - audio_format_t mixerInFormat, audio_format_t mixerOutFormat); -}; - -// ---------------------------------------------------------------------------- -} // namespace cocos2d { diff --git a/cocos/audio/android/AudioMixerController.cpp b/cocos/audio/android/AudioMixerController.cpp deleted file mode 100644 index 4a92029..0000000 --- a/cocos/audio/android/AudioMixerController.cpp +++ /dev/null @@ -1,351 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ - -#define LOG_TAG "AudioMixerController" - -#include "audio/android/AudioMixerController.h" -#include "audio/android/AudioMixer.h" -#include "audio/android/Track.h" -#include "audio/android/OpenSLHelper.h" - -#include -#include - -namespace cocos2d { - -AudioMixerController::AudioMixerController(int bufferSizeInFrames, int sampleRate, int channelCount) - : _bufferSizeInFrames(bufferSizeInFrames) - , _sampleRate(sampleRate) - , _channelCount(channelCount) - , _mixer(nullptr) - , _isPaused(false) - , _isMixingFrame(false) -{ - ALOGV("In the constructor of AudioMixerController!"); - - _mixingBuffer.size = (size_t) bufferSizeInFrames * 2 * channelCount; - // Don't use posix_memalign since it was added from API 16, it will crash on Android 2.3 - // Therefore, for a workaround, we uses memalign here. - _mixingBuffer.buf = memalign(32, _mixingBuffer.size); - memset(_mixingBuffer.buf, 0, _mixingBuffer.size); -} - -AudioMixerController::~AudioMixerController() -{ - destroy(); - - if (_mixer != nullptr) - { - delete _mixer; - _mixer = nullptr; - } - - free(_mixingBuffer.buf); -} - -bool AudioMixerController::init() -{ - _mixer = new (std::nothrow) AudioMixer(_bufferSizeInFrames, _sampleRate); - return _mixer != nullptr; -} - -bool AudioMixerController::addTrack(Track* track) -{ - ALOG_ASSERT(track != nullptr, "Shouldn't pass nullptr to addTrack"); - bool ret = false; - - std::lock_guard lk(_activeTracksMutex); - - auto iter = std::find(_activeTracks.begin(), _activeTracks.end(), track); - if (iter == _activeTracks.end()) - { - _activeTracks.push_back(track); - ret = true; - } - - return ret; -} - -template -static void removeItemFromVector(std::vector& v, T item) -{ - auto iter = std::find(v.begin(), v.end(), item); - if (iter != v.end()) - { - v.erase(iter); - } -} - -void AudioMixerController::initTrack(Track* track, std::vector& tracksToRemove) -{ - if (track->isInitialized()) - return; - - uint32_t channelMask = audio_channel_out_mask_from_count(2); - int32_t name = _mixer->getTrackName(channelMask, AUDIO_FORMAT_PCM_16_BIT, - AUDIO_SESSION_OUTPUT_MIX); - if (name < 0) - { - // If we could not get the track name, it means that there're MAX_NUM_TRACKS tracks - // So ignore the new track. - tracksToRemove.push_back(track); - } - else - { - _mixer->setBufferProvider(name, track); - _mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER, - _mixingBuffer.buf); - _mixer->setParameter( - name, - AudioMixer::TRACK, - AudioMixer::MIXER_FORMAT, - (void *) (uintptr_t) AUDIO_FORMAT_PCM_16_BIT); - _mixer->setParameter( - name, - AudioMixer::TRACK, - AudioMixer::FORMAT, - (void *) (uintptr_t) AUDIO_FORMAT_PCM_16_BIT); - _mixer->setParameter( - name, - AudioMixer::TRACK, - AudioMixer::MIXER_CHANNEL_MASK, - (void *) (uintptr_t) channelMask); - _mixer->setParameter( - name, - AudioMixer::TRACK, - AudioMixer::CHANNEL_MASK, - (void *) (uintptr_t) channelMask); - - track->setName(name); - _mixer->enable(name); - - std::lock_guard lk(track->_volumeDirtyMutex); - gain_minifloat_packed_t volume = track->getVolumeLR(); - float lVolume = float_from_gain(gain_minifloat_unpack_left(volume)); - float rVolume = float_from_gain(gain_minifloat_unpack_right(volume)); - - _mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, &lVolume); - _mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, &rVolume); - - track->setVolumeDirty(false); - track->setInitialized(true); - } -} - -void AudioMixerController::mixOneFrame() -{ - _isMixingFrame = true; - _activeTracksMutex.lock(); - - auto mixStart = clockNow(); - - std::vector tracksToRemove; - tracksToRemove.reserve(_activeTracks.size()); - - // FOR TESTING BEGIN -// Track* track = _activeTracks[0]; -// -// AudioBufferProvider::Buffer buffer; -// buffer.frameCount = _bufferSizeInFrames; -// status_t r = track->getNextBuffer(&buffer); -//// ALOG_ASSERT(buffer.frameCount == _mixing->size / 2, "buffer.frameCount:%d, _mixing->size/2:%d", buffer.frameCount, _mixing->size/2); -// if (r == NO_ERROR) -// { -// ALOGV("getNextBuffer succeed ..."); -// memcpy(_mixing->buf, buffer.raw, _mixing->size); -// } -// if (buffer.raw == nullptr) -// { -// ALOGV("Play over ..."); -// tracksToRemove.push_back(track); -// } -// else -// { -// track->releaseBuffer(&buffer); -// } -// -// _mixing->state = BufferState::FULL; -// _activeTracksMutex.unlock(); - // FOR TESTING END - - Track::State state; - // set up the tracks. - for (auto&& track : _activeTracks) - { - state = track->getState(); - - if (state == Track::State::PLAYING) - { - initTrack(track, tracksToRemove); - - int name = track->getName(); - ALOG_ASSERT(name >= 0); - - std::lock_guard lk(track->_volumeDirtyMutex); - - if (track->isVolumeDirty()) - { - gain_minifloat_packed_t volume = track->getVolumeLR(); - float lVolume = float_from_gain(gain_minifloat_unpack_left(volume)); - float rVolume = float_from_gain(gain_minifloat_unpack_right(volume)); - - ALOGV("Track (name: %d)'s volume is dirty, update volume to L: %f, R: %f", name, lVolume, rVolume); - - _mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, &lVolume); - _mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, &rVolume); - - track->setVolumeDirty(false); - } - } - else if (state == Track::State::RESUMED) - { - initTrack(track, tracksToRemove); - - if (track->getPrevState() == Track::State::PAUSED) - { - _mixer->enable(track->getName()); - track->setState(Track::State::PLAYING); - } - else - { - ALOGW("Previous state (%d) isn't PAUSED, couldn't resume!", static_cast(track->getPrevState())); - } - } - else if (state == Track::State::PAUSED) - { - initTrack(track, tracksToRemove); - - if (track->getPrevState() == Track::State::PLAYING || track->getPrevState() == Track::State::RESUMED) - { - _mixer->disable(track->getName()); - } - else - { - ALOGW("Previous state (%d) isn't PLAYING, couldn't pause!", static_cast(track->getPrevState())); - } - } - else if (state == Track::State::STOPPED) - { - if (track->isInitialized()) - { - _mixer->deleteTrackName(track->getName()); - } - else - { - ALOGV("Track (%p) hasn't been initialized yet!", track); - } - tracksToRemove.push_back(track); - } - - if (track->isPlayOver()) - { - if (track->isLoop()) - { - track->reset(); - } - else - { - ALOGV("Play over ..."); - _mixer->deleteTrackName(track->getName()); - tracksToRemove.push_back(track); - track->setState(Track::State::OVER); - } - } - } - - bool hasAvailableTracks = _activeTracks.size() - tracksToRemove.size() > 0; - - if (hasAvailableTracks) - { - ALOGV_IF(_activeTracks.size() > 8, "More than 8 active tracks: %d", (int) _activeTracks.size()); - _mixer->process(AudioBufferProvider::kInvalidPTS); - } - else - { - ALOGV("Doesn't have enough tracks: %d, %d", (int) _activeTracks.size(), (int) tracksToRemove.size()); - } - - // Remove stopped or playover tracks for active tracks container - for (auto&& track : tracksToRemove) - { - removeItemFromVector(_activeTracks, track); - - if (track != nullptr && track->onStateChanged != nullptr) - { - track->onStateChanged(Track::State::DESTROYED); - } - else - { - ALOGE("track (%p) was released ...", track); - } - } - - _activeTracksMutex.unlock(); - - auto mixEnd = clockNow(); - float mixInterval = intervalInMS(mixStart, mixEnd); - ALOGV_IF(mixInterval > 1.0f, "Mix a frame waste: %fms", mixInterval); - - _isMixingFrame = false; -} - -void AudioMixerController::destroy() -{ - while (_isMixingFrame) - { - usleep(10); - } - usleep(2000); // Wait for more 2ms -} - -void AudioMixerController::pause() -{ - _isPaused = true; -} - -void AudioMixerController::resume() -{ - _isPaused = false; -} - -bool AudioMixerController::hasPlayingTacks() -{ - std::lock_guard lk (_activeTracksMutex); - if (_activeTracks.empty()) - return false; - - for (auto&& track : _activeTracks) - { - Track::State state = track->getState(); - if (state == Track::State::IDLE || state == Track::State::PLAYING || state == Track::State::RESUMED) - { - return true; - } - } - - return false; -} - -} // namespace cocos2d { diff --git a/cocos/audio/android/AudioMixerController.h b/cocos/audio/android/AudioMixerController.h deleted file mode 100644 index d8c08f3..0000000 --- a/cocos/audio/android/AudioMixerController.h +++ /dev/null @@ -1,88 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ - -#pragma once - -#include "audio/android/utils/Errors.h" - -#include -#include -#include -#include -#include - -namespace cocos2d { - -class Track; -class AudioMixer; - -class AudioMixerController -{ -public: - - struct OutputBuffer - { - void* buf; - size_t size; - }; - - AudioMixerController(int bufferSizeInFrames, int sampleRate, int channelCount); - - ~AudioMixerController(); - - bool init(); - - bool addTrack(Track* track); - bool hasPlayingTacks(); - - void pause(); - void resume(); - inline bool isPaused() const { return _isPaused; }; - - void mixOneFrame(); - - inline OutputBuffer* current() { return &_mixingBuffer; } - -private: - void destroy(); - void initTrack(Track* track, std::vector& tracksToRemove); - -private: - int _bufferSizeInFrames; - int _sampleRate; - int _channelCount; - - AudioMixer* _mixer; - - std::mutex _activeTracksMutex; - std::vector _activeTracks; - - OutputBuffer _mixingBuffer; - - std::atomic_bool _isPaused; - std::atomic_bool _isMixingFrame; -}; - -} // namespace cocos2d { diff --git a/cocos/audio/android/AudioMixerOps.h b/cocos/audio/android/AudioMixerOps.h deleted file mode 100644 index 4a37aab..0000000 --- a/cocos/audio/android/AudioMixerOps.h +++ /dev/null @@ -1,450 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "audio/android/cutils/log.h" - -namespace cocos2d { - -/* Behavior of is_same<>::value is true if the types are identical, - * false otherwise. Identical to the STL std::is_same. - */ -template -struct is_same -{ - static const bool value = false; -}; - -template -struct is_same // partial specialization -{ - static const bool value = true; -}; - - -/* MixMul is a multiplication operator to scale an audio input signal - * by a volume gain, with the formula: - * - * O(utput) = I(nput) * V(olume) - * - * The output, input, and volume may have different types. - * There are 27 variants, of which 14 are actually defined in an - * explicitly templated class. - * - * The following type variables and the underlying meaning: - * - * Output type TO: int32_t (Q4.27) or int16_t (Q.15) or float [-1,1] - * Input signal type TI: int32_t (Q4.27) or int16_t (Q.15) or float [-1,1] - * Volume type TV: int32_t (U4.28) or int16_t (U4.12) or float [-1,1] - * - * For high precision audio, only the = - * needs to be accelerated. This is perhaps the easiest form to do quickly as well. - * - * A generic version is NOT defined to catch any mistake of using it. - */ - -template -TO MixMul(TI value, TV volume); - -template <> -inline int32_t MixMul(int16_t value, int16_t volume) { - return value * volume; -} - -template <> -inline int32_t MixMul(int32_t value, int16_t volume) { - return (value >> 12) * volume; -} - -template <> -inline int32_t MixMul(int16_t value, int32_t volume) { - return value * (volume >> 16); -} - -template <> -inline int32_t MixMul(int32_t value, int32_t volume) { - return (value >> 12) * (volume >> 16); -} - -template <> -inline float MixMul(float value, int16_t volume) { - static const float norm = 1. / (1 << 12); - return value * volume * norm; -} - -template <> -inline float MixMul(float value, int32_t volume) { - static const float norm = 1. / (1 << 28); - return value * volume * norm; -} - -template <> -inline int16_t MixMul(float value, int16_t volume) { - return clamp16_from_float(MixMul(value, volume)); -} - -template <> -inline int16_t MixMul(float value, int32_t volume) { - return clamp16_from_float(MixMul(value, volume)); -} - -template <> -inline float MixMul(int16_t value, int16_t volume) { - static const float norm = 1. / (1 << (15 + 12)); - return static_cast(value) * static_cast(volume) * norm; -} - -template <> -inline float MixMul(int16_t value, int32_t volume) { - static const float norm = 1. / (1ULL << (15 + 28)); - return static_cast(value) * static_cast(volume) * norm; -} - -template <> -inline int16_t MixMul(int16_t value, int16_t volume) { - return clamp16(MixMul(value, volume) >> 12); -} - -template <> -inline int16_t MixMul(int32_t value, int16_t volume) { - return clamp16(MixMul(value, volume) >> 12); -} - -template <> -inline int16_t MixMul(int16_t value, int32_t volume) { - return clamp16(MixMul(value, volume) >> 12); -} - -template <> -inline int16_t MixMul(int32_t value, int32_t volume) { - return clamp16(MixMul(value, volume) >> 12); -} - -/* Required for floating point volume. Some are needed for compilation but - * are not needed in execution and should be removed from the final build by - * an optimizing compiler. - */ -template <> -inline float MixMul(float value, float volume) { - return value * volume; -} - -template <> -inline float MixMul(int16_t value, float volume) { - static const float float_from_q_15 = 1. / (1 << 15); - return value * volume * float_from_q_15; -} - -template <> -inline int32_t MixMul(int32_t value, float volume) { - LOG_ALWAYS_FATAL("MixMul Runtime Should not be here"); - return value * volume; -} - -template <> -inline int32_t MixMul(int16_t value, float volume) { - LOG_ALWAYS_FATAL("MixMul Runtime Should not be here"); - static const float u4_12_from_float = (1 << 12); - return value * volume * u4_12_from_float; -} - -template <> -inline int16_t MixMul(int16_t value, float volume) { - LOG_ALWAYS_FATAL("MixMul Runtime Should not be here"); - return clamp16_from_float(MixMul(value, volume)); -} - -template <> -inline int16_t MixMul(float value, float volume) { - return clamp16_from_float(value * volume); -} - -/* - * MixAccum is used to add into an accumulator register of a possibly different - * type. The TO and TI types are the same as MixMul. - */ - -template -inline void MixAccum(TO *auxaccum, TI value) { - if (!is_same::value) { - LOG_ALWAYS_FATAL("MixAccum type not properly specialized: %zu %zu\n", - sizeof(TO), sizeof(TI)); - } - *auxaccum += value; -} - -template<> -inline void MixAccum(float *auxaccum, int16_t value) { - static const float norm = 1. / (1 << 15); - *auxaccum += norm * value; -} - -template<> -inline void MixAccum(float *auxaccum, int32_t value) { - static const float norm = 1. / (1 << 27); - *auxaccum += norm * value; -} - -template<> -inline void MixAccum(int32_t *auxaccum, int16_t value) { - *auxaccum += value << 12; -} - -template<> -inline void MixAccum(int32_t *auxaccum, float value) { - *auxaccum += clampq4_27_from_float(value); -} - -/* MixMulAux is just like MixMul except it combines with - * an accumulator operation MixAccum. - */ - -template -inline TO MixMulAux(TI value, TV volume, TA *auxaccum) { - MixAccum(auxaccum, value); - return MixMul(value, volume); -} - -/* MIXTYPE is used to determine how the samples in the input frame - * are mixed with volume gain into the output frame. - * See the volumeRampMulti functions below for more details. - */ -enum { - MIXTYPE_MULTI, - MIXTYPE_MONOEXPAND, - MIXTYPE_MULTI_SAVEONLY, - MIXTYPE_MULTI_MONOVOL, - MIXTYPE_MULTI_SAVEONLY_MONOVOL, -}; - -/* - * The volumeRampMulti and volumeRamp functions take a MIXTYPE - * which indicates the per-frame mixing and accumulation strategy. - * - * MIXTYPE_MULTI: - * NCHAN represents number of input and output channels. - * TO: int32_t (Q4.27) or float - * TI: int32_t (Q4.27) or int16_t (Q0.15) or float - * TV: int32_t (U4.28) or int16_t (U4.12) or float - * vol: represents a volume array. - * - * This accumulates into the out pointer. - * - * MIXTYPE_MONOEXPAND: - * Single input channel. NCHAN represents number of output channels. - * TO: int32_t (Q4.27) or float - * TI: int32_t (Q4.27) or int16_t (Q0.15) or float - * TV: int32_t (U4.28) or int16_t (U4.12) or float - * Input channel count is 1. - * vol: represents volume array. - * - * This accumulates into the out pointer. - * - * MIXTYPE_MULTI_SAVEONLY: - * NCHAN represents number of input and output channels. - * TO: int16_t (Q.15) or float - * TI: int32_t (Q4.27) or int16_t (Q0.15) or float - * TV: int32_t (U4.28) or int16_t (U4.12) or float - * vol: represents a volume array. - * - * MIXTYPE_MULTI_SAVEONLY does not accumulate into the out pointer. - * - * MIXTYPE_MULTI_MONOVOL: - * Same as MIXTYPE_MULTI, but uses only volume[0]. - * - * MIXTYPE_MULTI_SAVEONLY_MONOVOL: - * Same as MIXTYPE_MULTI_SAVEONLY, but uses only volume[0]. - * - */ - -template -inline void volumeRampMulti(TO* out, size_t frameCount, - const TI* in, TA* aux, TV *vol, const TV *volinc, TAV *vola, TAV volainc) -{ -#ifdef ALOGVV - ALOGVV("volumeRampMulti, MIXTYPE:%d\n", MIXTYPE); -#endif - if (aux != NULL) { - do { - TA auxaccum = 0; - switch (MIXTYPE) { - case MIXTYPE_MULTI: - for (int i = 0; i < NCHAN; ++i) { - *out++ += MixMulAux(*in++, vol[i], &auxaccum); - vol[i] += volinc[i]; - } - break; - case MIXTYPE_MONOEXPAND: - for (int i = 0; i < NCHAN; ++i) { - *out++ += MixMulAux(*in, vol[i], &auxaccum); - vol[i] += volinc[i]; - } - in++; - break; - case MIXTYPE_MULTI_SAVEONLY: - for (int i = 0; i < NCHAN; ++i) { - *out++ = MixMulAux(*in++, vol[i], &auxaccum); - vol[i] += volinc[i]; - } - break; - case MIXTYPE_MULTI_MONOVOL: - for (int i = 0; i < NCHAN; ++i) { - *out++ += MixMulAux(*in++, vol[0], &auxaccum); - } - vol[0] += volinc[0]; - break; - case MIXTYPE_MULTI_SAVEONLY_MONOVOL: - for (int i = 0; i < NCHAN; ++i) { - *out++ = MixMulAux(*in++, vol[0], &auxaccum); - } - vol[0] += volinc[0]; - break; - default: - LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE); - break; - } - auxaccum /= NCHAN; - *aux++ += MixMul(auxaccum, *vola); - vola[0] += volainc; - } while (--frameCount); - } else { - do { - switch (MIXTYPE) { - case MIXTYPE_MULTI: - for (int i = 0; i < NCHAN; ++i) { - *out++ += MixMul(*in++, vol[i]); - vol[i] += volinc[i]; - } - break; - case MIXTYPE_MONOEXPAND: - for (int i = 0; i < NCHAN; ++i) { - *out++ += MixMul(*in, vol[i]); - vol[i] += volinc[i]; - } - in++; - break; - case MIXTYPE_MULTI_SAVEONLY: - for (int i = 0; i < NCHAN; ++i) { - *out++ = MixMul(*in++, vol[i]); - vol[i] += volinc[i]; - } - break; - case MIXTYPE_MULTI_MONOVOL: - for (int i = 0; i < NCHAN; ++i) { - *out++ += MixMul(*in++, vol[0]); - } - vol[0] += volinc[0]; - break; - case MIXTYPE_MULTI_SAVEONLY_MONOVOL: - for (int i = 0; i < NCHAN; ++i) { - *out++ = MixMul(*in++, vol[0]); - } - vol[0] += volinc[0]; - break; - default: - LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE); - break; - } - } while (--frameCount); - } -} - -template -inline void volumeMulti(TO* out, size_t frameCount, - const TI* in, TA* aux, const TV *vol, TAV vola) -{ -#ifdef ALOGVV - ALOGVV("volumeMulti MIXTYPE:%d\n", MIXTYPE); -#endif - if (aux != NULL) { - do { - TA auxaccum = 0; - switch (MIXTYPE) { - case MIXTYPE_MULTI: - for (int i = 0; i < NCHAN; ++i) { - *out++ += MixMulAux(*in++, vol[i], &auxaccum); - } - break; - case MIXTYPE_MONOEXPAND: - for (int i = 0; i < NCHAN; ++i) { - *out++ += MixMulAux(*in, vol[i], &auxaccum); - } - in++; - break; - case MIXTYPE_MULTI_SAVEONLY: - for (int i = 0; i < NCHAN; ++i) { - *out++ = MixMulAux(*in++, vol[i], &auxaccum); - } - break; - case MIXTYPE_MULTI_MONOVOL: - for (int i = 0; i < NCHAN; ++i) { - *out++ += MixMulAux(*in++, vol[0], &auxaccum); - } - break; - case MIXTYPE_MULTI_SAVEONLY_MONOVOL: - for (int i = 0; i < NCHAN; ++i) { - *out++ = MixMulAux(*in++, vol[0], &auxaccum); - } - break; - default: - LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE); - break; - } - auxaccum /= NCHAN; - *aux++ += MixMul(auxaccum, vola); - } while (--frameCount); - } else { - do { - switch (MIXTYPE) { - case MIXTYPE_MULTI: - for (int i = 0; i < NCHAN; ++i) { - *out++ += MixMul(*in++, vol[i]); - } - break; - case MIXTYPE_MONOEXPAND: - for (int i = 0; i < NCHAN; ++i) { - *out++ += MixMul(*in, vol[i]); - } - in++; - break; - case MIXTYPE_MULTI_SAVEONLY: - for (int i = 0; i < NCHAN; ++i) { - *out++ = MixMul(*in++, vol[i]); - } - break; - case MIXTYPE_MULTI_MONOVOL: - for (int i = 0; i < NCHAN; ++i) { - *out++ += MixMul(*in++, vol[0]); - } - break; - case MIXTYPE_MULTI_SAVEONLY_MONOVOL: - for (int i = 0; i < NCHAN; ++i) { - *out++ = MixMul(*in++, vol[0]); - } - break; - default: - LOG_ALWAYS_FATAL("invalid mixtype %d", MIXTYPE); - break; - } - } while (--frameCount); - } -} - -} // namespace cocos2d { - diff --git a/cocos/audio/android/AudioPlayerProvider.cpp b/cocos/audio/android/AudioPlayerProvider.cpp deleted file mode 100644 index 12c5565..0000000 --- a/cocos/audio/android/AudioPlayerProvider.cpp +++ /dev/null @@ -1,519 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ - -#define LOG_TAG "AudioPlayerProvider" - -#include "audio/android/AudioPlayerProvider.h" -#include "audio/android/UrlAudioPlayer.h" -#include "audio/android/PcmAudioPlayer.h" -#include "audio/android/AudioDecoder.h" -#include "audio/android/AudioDecoderProvider.h" -#include "audio/android/AudioMixerController.h" -#include "audio/android/PcmAudioService.h" -#include "audio/android/CCThreadPool.h" -#include "audio/android/ICallerThreadUtils.h" -#include "audio/android/utils/Utils.h" - -#include -#include -#include // for std::find_if - -namespace cocos2d { - -static int getSystemAPILevel() -{ - static int __systemApiLevel = -1; - if (__systemApiLevel > 0) - { - return __systemApiLevel; - } - - int apiLevel = getSDKVersion(); - if (apiLevel > 0) - { - ALOGD("Android API level: %d", apiLevel); - } - else - { - ALOGE("Fail to get Android API level!"); - } - __systemApiLevel = apiLevel; - return apiLevel; -} - -struct AudioFileIndicator -{ - std::string extension; - int smallSizeIndicator; -}; - -static AudioFileIndicator __audioFileIndicator[] = { - {"default", 128000}, // If we could not handle the audio format, return default value, the position should be first. - {".wav", 1024000}, - {".ogg", 128000}, - {".mp3", 160000} -}; - -AudioPlayerProvider::AudioPlayerProvider(SLEngineItf engineItf, SLObjectItf outputMixObject, - int deviceSampleRate, int bufferSizeInFrames, - const FdGetterCallback &fdGetterCallback, - ICallerThreadUtils* callerThreadUtils) - : _engineItf(engineItf), _outputMixObject(outputMixObject), - _deviceSampleRate(deviceSampleRate), _bufferSizeInFrames(bufferSizeInFrames), - _fdGetterCallback(fdGetterCallback), _callerThreadUtils(callerThreadUtils), - _pcmAudioService(nullptr), _mixController(nullptr), - _threadPool(ThreadPool::newCachedThreadPool(1, 8, 5, 2, 2)) -{ - ALOGI("deviceSampleRate: %d, bufferSizeInFrames: %d", _deviceSampleRate, _bufferSizeInFrames); - if (getSystemAPILevel() >= 17) - { - _mixController = new (std::nothrow) AudioMixerController(_bufferSizeInFrames, _deviceSampleRate, 2); - _mixController->init(); - _pcmAudioService = new (std::nothrow) PcmAudioService(engineItf, outputMixObject); - _pcmAudioService->init(_mixController, 2, deviceSampleRate, bufferSizeInFrames * 2); - } - - ALOG_ASSERT(callerThreadUtils != nullptr, "Caller thread utils parameter should not be nullptr!"); -} - -AudioPlayerProvider::~AudioPlayerProvider() -{ - ALOGV("~AudioPlayerProvider()"); - UrlAudioPlayer::stopAll(); - - SL_SAFE_DELETE(_pcmAudioService); - SL_SAFE_DELETE(_mixController); - SL_SAFE_DELETE(_threadPool); -} - -IAudioPlayer *AudioPlayerProvider::getAudioPlayer(const std::string &audioFilePath) -{ - // Pcm data decoding by OpenSLES API only supports in API level 17 and later. - if (getSystemAPILevel() < 17) - { - AudioFileInfo info = getFileInfo(audioFilePath); - if (info.isValid()) - { - return createUrlAudioPlayer(info); - } - - return nullptr; - } - - IAudioPlayer *player = nullptr; - - _pcmCacheMutex.lock(); - auto iter = _pcmCache.find(audioFilePath); - if (iter != _pcmCache.end()) - {// Found pcm cache means it was used to be a PcmAudioService - PcmData pcmData = iter->second; - _pcmCacheMutex.unlock(); - player = obtainPcmAudioPlayer(audioFilePath, pcmData); - ALOGV_IF(player == nullptr, "%s, %d: player is nullptr, path: %s", __FUNCTION__, __LINE__, audioFilePath.c_str()); - } - else - { - _pcmCacheMutex.unlock(); - // Check audio file size to determine to use a PcmAudioService or UrlAudioPlayer, - // generally PcmAudioService is used for playing short audio like game effects while - // playing background music uses UrlAudioPlayer - AudioFileInfo info = getFileInfo(audioFilePath); - if (info.isValid()) - { - if (isSmallFile(info)) - { - // Put an empty lambda to preloadEffect since we only want the future object to get PcmData - auto pcmData = std::make_shared(); - auto isSucceed = std::make_shared(false); - auto isReturnFromCache = std::make_shared(false); - auto isPreloadFinished = std::make_shared(false); - - std::thread::id threadId = std::this_thread::get_id(); - - void* infoPtr = &info; - std::string url = info.url; - preloadEffect(info, [infoPtr, url, threadId, pcmData, isSucceed, isReturnFromCache, isPreloadFinished](bool succeed, PcmData data){ - // If the callback is in the same thread as caller's, it means that we found it - // in the cache - *isReturnFromCache = std::this_thread::get_id() == threadId; - *pcmData = data; - *isSucceed = succeed; - *isPreloadFinished = true; - ALOGV("FileInfo (%p), Set isSucceed flag: %d, path: %s", infoPtr, succeed, url.c_str()); - }, true); - - if (!*isReturnFromCache && !*isPreloadFinished) - { - std::unique_lock lk(_preloadWaitMutex); - // Wait for 2 seconds for the decoding in sub thread finishes. - ALOGV("FileInfo (%p), Waiting preload (%s) to finish ...", &info, audioFilePath.c_str()); - _preloadWaitCond.wait_for(lk, std::chrono::seconds(2)); - ALOGV("FileInfo (%p), Waitup preload (%s) ...", &info, audioFilePath.c_str()); - } - - if (*isSucceed) - { - if (pcmData->isValid()) - { - player = obtainPcmAudioPlayer(info.url, *pcmData); - ALOGV_IF(player == nullptr, "%s, %d: player is nullptr, path: %s", __FUNCTION__, __LINE__, audioFilePath.c_str()); - } - else - { - ALOGE("pcm data is invalid, path: %s", audioFilePath.c_str()); - } - } - else - { - ALOGE("FileInfo (%p), preloadEffect (%s) failed", &info, audioFilePath.c_str()); - } - } - else - { - player = createUrlAudioPlayer(info); - ALOGV_IF(player == nullptr, "%s, %d: player is nullptr, path: %s", __FUNCTION__, __LINE__, audioFilePath.c_str()); - } - } - else - { - ALOGE("File info is invalid, path: %s", audioFilePath.c_str()); - } - } - - ALOGV_IF(player == nullptr, "%s, %d return nullptr", __FUNCTION__, __LINE__); - return player; -} - -void AudioPlayerProvider::preloadEffect(const std::string &audioFilePath, const PreloadCallback& cb) -{ - // Pcm data decoding by OpenSLES API only supports in API level 17 and later. - if (getSystemAPILevel() < 17) - { - PcmData data; - cb(true, data); - return; - } - - _pcmCacheMutex.lock(); - auto&& iter = _pcmCache.find(audioFilePath); - if (iter != _pcmCache.end()) - { - ALOGV("preload return from cache: (%s)", audioFilePath.c_str()); - _pcmCacheMutex.unlock(); - cb(true, iter->second); - return; - } - _pcmCacheMutex.unlock(); - - auto info = getFileInfo(audioFilePath); - preloadEffect(info, [this, cb, audioFilePath](bool succeed, PcmData data){ - - _callerThreadUtils->performFunctionInCallerThread([this, succeed, data, cb](){ - cb(succeed, data); - }); - - }, false); -} - -// Used internally -void AudioPlayerProvider::preloadEffect(const AudioFileInfo &info, const PreloadCallback& cb, bool isPreloadInPlay2d) -{ - PcmData pcmData; - - if (!info.isValid()) - { - cb(false, pcmData); - return; - } - - if (isSmallFile(info)) - { - std::string audioFilePath = info.url; - - // 1. First time check, if it wasn't in the cache, goto 2 step - _pcmCacheMutex.lock(); - auto&& iter = _pcmCache.find(audioFilePath); - if (iter != _pcmCache.end()) - { - ALOGV("1. Return pcm data from cache, url: %s", info.url.c_str()); - _pcmCacheMutex.unlock(); - cb(true, iter->second); - return; - } - _pcmCacheMutex.unlock(); - - { - // 2. Check whether the audio file is being preloaded, if it has been removed from map just now, - // goto step 3 - std::lock_guard lk(_preloadCallbackMutex); - - auto&& preloadIter = _preloadCallbackMap.find(audioFilePath); - if (preloadIter != _preloadCallbackMap.end()) - { - ALOGV("audio (%s) is being preloaded, add to callback vector!", audioFilePath.c_str()); - PreloadCallbackParam param; - param.callback = cb; - param.isPreloadInPlay2d = isPreloadInPlay2d; - preloadIter->second.push_back(std::move(param)); - return; - } - - // 3. Check it in cache again. If it has been removed from map just now, the file is in - // the cache absolutely. - _pcmCacheMutex.lock(); - auto&& iter = _pcmCache.find(audioFilePath); - if (iter != _pcmCache.end()) - { - ALOGV("2. Return pcm data from cache, url: %s", info.url.c_str()); - _pcmCacheMutex.unlock(); - cb(true, iter->second); - return; - } - _pcmCacheMutex.unlock(); - - PreloadCallbackParam param; - param.callback = cb; - param.isPreloadInPlay2d = isPreloadInPlay2d; - std::vector callbacks; - callbacks.push_back(std::move(param)); - _preloadCallbackMap.insert(std::make_pair(audioFilePath, std::move(callbacks))); - } - - _threadPool->pushTask([this, audioFilePath](int tid) { - ALOGV("AudioPlayerProvider::preloadEffect: (%s)", audioFilePath.c_str()); - PcmData d; - AudioDecoder* decoder = AudioDecoderProvider::createAudioDecoder(_engineItf, audioFilePath, _bufferSizeInFrames, _deviceSampleRate, _fdGetterCallback); - bool ret = decoder != nullptr && decoder->start(); - if (ret) - { - d = decoder->getResult(); - std::lock_guard lk(_pcmCacheMutex); - _pcmCache.insert(std::make_pair(audioFilePath, d)); - } - else - { - ALOGE("decode (%s) failed!", audioFilePath.c_str()); - } - - ALOGV("decode %s", (ret ? "succeed" : "failed")); - - std::lock_guard lk(_preloadCallbackMutex); - auto&& preloadIter = _preloadCallbackMap.find(audioFilePath); - if (preloadIter != _preloadCallbackMap.end()) - { - auto&& params = preloadIter->second; - ALOGV("preload (%s) callback count: %d", audioFilePath.c_str(), (int)params.size()); - PcmData result = decoder->getResult(); - for (auto&& param : params) - { - param.callback(ret, result); - if (param.isPreloadInPlay2d) - { - _preloadWaitCond.notify_one(); - } - } - _preloadCallbackMap.erase(preloadIter); - } - - AudioDecoderProvider::destroyAudioDecoder(&decoder); - }); - } - else - { - ALOGV("File (%s) is too large, ignore preload!", info.url.c_str()); - cb(true, pcmData); - } -} - -AudioPlayerProvider::AudioFileInfo AudioPlayerProvider::getFileInfo( - const std::string &audioFilePath) -{ - AudioFileInfo info; - long fileSize = 0; - off_t start = 0, length = 0; - int assetFd = -1; - - if (audioFilePath[0] != '/') - { - std::string relativePath; - size_t position = audioFilePath.find("assets/"); - - if (0 == position) - { - // "assets/" is at the beginning of the path and we don't want it - relativePath = audioFilePath.substr(strlen("assets/")); - } - else - { - relativePath = audioFilePath; - } - - assetFd = _fdGetterCallback(relativePath, &start, &length); - - if (assetFd <= 0) - { - ALOGE("Failed to open file descriptor for '%s'", audioFilePath.c_str()); - return info; - } - - fileSize = length; - } - else - { - FILE *fp = fopen(audioFilePath.c_str(), "rb"); - if (fp != nullptr) - { - fseek(fp, 0, SEEK_END); - fileSize = ftell(fp); - fclose(fp); - } - else - { - return info; - } - } - - info.url = audioFilePath; - info.assetFd = std::make_shared(assetFd); - info.start = start; - info.length = fileSize; - - ALOGV("(%s) file size: %ld", audioFilePath.c_str(), fileSize); - - return info; -} - -bool AudioPlayerProvider::isSmallFile(const AudioFileInfo &info) -{ - //TODO: If file size is smaller than 100k, we think it's a small file. This value should be set by developers. - AudioFileInfo &audioFileInfo = const_cast(info); - size_t judgeCount = sizeof(__audioFileIndicator) / sizeof(__audioFileIndicator[0]); - size_t pos = audioFileInfo.url.rfind("."); - std::string extension; - if (pos != std::string::npos) - { - extension = audioFileInfo.url.substr(pos); - } - auto iter = std::find_if(std::begin(__audioFileIndicator), std::end(__audioFileIndicator), - [&extension](const AudioFileIndicator &judge) -> bool { - return judge.extension == extension; - }); - - if (iter != std::end(__audioFileIndicator)) - { -// ALOGV("isSmallFile: found: %s: ", iter->extension.c_str()); - return info.length < iter->smallSizeIndicator; - } - -// ALOGV("isSmallFile: not found return default value"); - return info.length < __audioFileIndicator[0].smallSizeIndicator; -} - -void AudioPlayerProvider::clearPcmCache(const std::string &audioFilePath) -{ - std::lock_guard lk(_pcmCacheMutex); - auto iter = _pcmCache.find(audioFilePath); - if (iter != _pcmCache.end()) - { - ALOGV("clear pcm cache: (%s)", audioFilePath.c_str()); - _pcmCache.erase(iter); - } - else - { - ALOGW("Couldn't find the pcm cache: (%s)", audioFilePath.c_str()); - } -} - -void AudioPlayerProvider::clearAllPcmCaches() -{ - std::lock_guard lk(_pcmCacheMutex); - _pcmCache.clear(); -} - -PcmAudioPlayer *AudioPlayerProvider::obtainPcmAudioPlayer(const std::string &url, - const PcmData &pcmData) -{ - PcmAudioPlayer *pcmPlayer = nullptr; - if (pcmData.isValid()) - { - pcmPlayer = new(std::nothrow) PcmAudioPlayer(_mixController, _callerThreadUtils); - if (pcmPlayer != nullptr) - { - pcmPlayer->prepare(url, pcmData); - } - } - else - { - ALOGE("obtainPcmAudioPlayer failed, pcmData isn't valid!"); - } - return pcmPlayer; -} - -UrlAudioPlayer *AudioPlayerProvider::createUrlAudioPlayer( - const AudioPlayerProvider::AudioFileInfo &info) -{ - if (info.url.empty()) - { - ALOGE("createUrlAudioPlayer failed, url is empty!"); - return nullptr; - } - - SLuint32 locatorType = info.assetFd->getFd() > 0 ? SL_DATALOCATOR_ANDROIDFD : SL_DATALOCATOR_URI; - auto urlPlayer = new (std::nothrow) UrlAudioPlayer(_engineItf, _outputMixObject, _callerThreadUtils); - bool ret = urlPlayer->prepare(info.url, locatorType, info.assetFd, info.start, info.length); - if (!ret) - { - SL_SAFE_DELETE(urlPlayer); - } - return urlPlayer; -} - -void AudioPlayerProvider::pause() -{ - if (_mixController != nullptr) - { - _mixController->pause(); - } - - if (_pcmAudioService != nullptr) - { - _pcmAudioService->pause(); - } -} - -void AudioPlayerProvider::resume() -{ - if (_mixController != nullptr) - { - _mixController->resume(); - } - - if (_pcmAudioService != nullptr) - { - _pcmAudioService->resume(); - } -} - -} // namespace cocos2d { diff --git a/cocos/audio/android/AudioPlayerProvider.h b/cocos/audio/android/AudioPlayerProvider.h deleted file mode 100644 index 3f72a39..0000000 --- a/cocos/audio/android/AudioPlayerProvider.h +++ /dev/null @@ -1,128 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ - -#pragma once - -#include "audio/android/IAudioPlayer.h" -#include "audio/android/OpenSLHelper.h" -#include "audio/android/PcmData.h" - -#include -#include -#include - -namespace cocos2d { -// Manage PcmAudioPlayer& UrlAudioPlayer - -class PcmAudioPlayer; -class PcmAudioService; -class UrlAudioPlayer; -class AudioMixerController; -class ICallerThreadUtils; -class AssetFd; -class ThreadPool; - -class AudioPlayerProvider -{ -public: - AudioPlayerProvider(SLEngineItf engineItf, SLObjectItf outputMixObject, int deviceSampleRate, - int bufferSizeInFrames, const FdGetterCallback &fdGetterCallback, - ICallerThreadUtils* callerThreadUtils); - - virtual ~AudioPlayerProvider(); - - IAudioPlayer *getAudioPlayer(const std::string &audioFilePath); - - typedef std::function PreloadCallback; - void preloadEffect(const std::string &audioFilePath, const PreloadCallback& cb); - - void clearPcmCache(const std::string &audioFilePath); - - void clearAllPcmCaches(); - - void pause(); - - void resume(); - -private: - - struct AudioFileInfo - { - std::string url; - std::shared_ptr assetFd; - off_t start; - off_t length; - - AudioFileInfo() - : assetFd(nullptr), start(0), length(0) - { }; - - inline bool isValid() const - { - return !url.empty() && length > 0; - } - }; - - PcmAudioPlayer *obtainPcmAudioPlayer(const std::string &url, const PcmData &pcmData); - - UrlAudioPlayer *createUrlAudioPlayer(const AudioFileInfo &info); - - void preloadEffect(const AudioFileInfo &info, const PreloadCallback& cb, bool isPreloadInPlay2d); - - AudioFileInfo getFileInfo(const std::string &audioFilePath); - - bool isSmallFile(const AudioFileInfo &info); - -private: - SLEngineItf _engineItf; - SLObjectItf _outputMixObject; - int _deviceSampleRate; - int _bufferSizeInFrames; - FdGetterCallback _fdGetterCallback; - ICallerThreadUtils* _callerThreadUtils; - - std::unordered_map _pcmCache; - std::mutex _pcmCacheMutex; - - struct PreloadCallbackParam - { - PreloadCallback callback; - bool isPreloadInPlay2d; - }; - - std::unordered_map> _preloadCallbackMap; - std::mutex _preloadCallbackMutex; - - std::mutex _preloadWaitMutex; - std::condition_variable _preloadWaitCond; - - PcmAudioService* _pcmAudioService; - AudioMixerController *_mixController; - - ThreadPool* _threadPool; -}; - -} // namespace cocos2d { - diff --git a/cocos/audio/android/AudioResampler.cpp b/cocos/audio/android/AudioResampler.cpp deleted file mode 100644 index 134821b..0000000 --- a/cocos/audio/android/AudioResampler.cpp +++ /dev/null @@ -1,788 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "AudioResampler" -//#define LOG_NDEBUG 0 - -#include -#include -#include -#include -#include -#include "audio/android/cutils/log.h" -#include "audio/android/utils/Utils.h" -//#include -#include "audio/android/audio_utils/include/audio_utils/primitives.h" -#include "audio/android/AudioResampler.h" -//#include "audio/android/AudioResamplerSinc.h" -#include "audio/android/AudioResamplerCubic.h" - - -//#include "AudioResamplerDyn.h" - -//cjh #ifdef __arm__ -// #define ASM_ARM_RESAMP1 // enable asm optimisation for ResamplerOrder1 -//#endif - - - -namespace cocos2d { - -// ---------------------------------------------------------------------------- - -class AudioResamplerOrder1 : public AudioResampler { -public: - AudioResamplerOrder1(int inChannelCount, int32_t sampleRate) : - AudioResampler(inChannelCount, sampleRate, LOW_QUALITY), mX0L(0), mX0R(0) { - } - virtual size_t resample(int32_t* out, size_t outFrameCount, - AudioBufferProvider* provider); -private: - // number of bits used in interpolation multiply - 15 bits avoids overflow - static const int kNumInterpBits = 15; - - // bits to shift the phase fraction down to avoid overflow - static const int kPreInterpShift = kNumPhaseBits - kNumInterpBits; - - void init() {} - size_t resampleMono16(int32_t* out, size_t outFrameCount, - AudioBufferProvider* provider); - size_t resampleStereo16(int32_t* out, size_t outFrameCount, - AudioBufferProvider* provider); -#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1 - void AsmMono16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx, - size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr, - uint32_t &phaseFraction, uint32_t phaseIncrement); - void AsmStereo16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx, - size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr, - uint32_t &phaseFraction, uint32_t phaseIncrement); -#endif // ASM_ARM_RESAMP1 - - static inline int32_t Interp(int32_t x0, int32_t x1, uint32_t f) { - return x0 + (((x1 - x0) * (int32_t)(f >> kPreInterpShift)) >> kNumInterpBits); - } - static inline void Advance(size_t* index, uint32_t* frac, uint32_t inc) { - *frac += inc; - *index += (size_t)(*frac >> kNumPhaseBits); - *frac &= kPhaseMask; - } - int mX0L; - int mX0R; -}; - -/*static*/ -const double AudioResampler::kPhaseMultiplier = 1L << AudioResampler::kNumPhaseBits; - -bool AudioResampler::qualityIsSupported(src_quality quality) -{ - switch (quality) { - case DEFAULT_QUALITY: - case LOW_QUALITY: - case MED_QUALITY: - case HIGH_QUALITY: - case VERY_HIGH_QUALITY: - return true; - default: - return false; - } -} - -// ---------------------------------------------------------------------------- - -static pthread_once_t once_control = PTHREAD_ONCE_INIT; -static AudioResampler::src_quality defaultQuality = AudioResampler::DEFAULT_QUALITY; - -void AudioResampler::init_routine() -{ - // int resamplerQuality = getSystemProperty("af.resampler.quality"); - // if (resamplerQuality > 0) { - // defaultQuality = (src_quality) resamplerQuality; - // ALOGD("forcing AudioResampler quality to %d", defaultQuality); - // if (defaultQuality < DEFAULT_QUALITY || defaultQuality > VERY_HIGH_QUALITY) { - // defaultQuality = DEFAULT_QUALITY; - // } - // } -} - -uint32_t AudioResampler::qualityMHz(src_quality quality) -{ - switch (quality) { - default: - case DEFAULT_QUALITY: - case LOW_QUALITY: - return 3; - case MED_QUALITY: - return 6; - case HIGH_QUALITY: - return 20; - case VERY_HIGH_QUALITY: - return 34; -// case DYN_LOW_QUALITY: -// return 4; -// case DYN_MED_QUALITY: -// return 6; -// case DYN_HIGH_QUALITY: -// return 12; - } -} - -static const uint32_t maxMHz = 130; // an arbitrary number that permits 3 VHQ, should be tunable -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; -static uint32_t currentMHz = 0; - -AudioResampler* AudioResampler::create(audio_format_t format, int inChannelCount, - int32_t sampleRate, src_quality quality) { - - bool atFinalQuality; - if (quality == DEFAULT_QUALITY) { - // read the resampler default quality property the first time it is needed - int ok = pthread_once(&once_control, init_routine); - if (ok != 0) { - ALOGE("%s pthread_once failed: %d", __func__, ok); - } - quality = defaultQuality; - atFinalQuality = false; - } else { - atFinalQuality = true; - } - - /* if the caller requests DEFAULT_QUALITY and af.resampler.property - * has not been set, the target resampler quality is set to DYN_MED_QUALITY, - * and allowed to "throttle" down to DYN_LOW_QUALITY if necessary - * due to estimated CPU load of having too many active resamplers - * (the code below the if). - */ - if (quality == DEFAULT_QUALITY) { -//cjh quality = DYN_MED_QUALITY; - } - - // naive implementation of CPU load throttling doesn't account for whether resampler is active - pthread_mutex_lock(&mutex); - for (;;) { - uint32_t deltaMHz = qualityMHz(quality); - uint32_t newMHz = currentMHz + deltaMHz; - if ((qualityIsSupported(quality) && newMHz <= maxMHz) || atFinalQuality) { - ALOGV("resampler load %u -> %u MHz due to delta +%u MHz from quality %d", - currentMHz, newMHz, deltaMHz, quality); - currentMHz = newMHz; - break; - } - // not enough CPU available for proposed quality level, so try next lowest level - switch (quality) { - default: - case LOW_QUALITY: - atFinalQuality = true; - break; - case MED_QUALITY: - quality = LOW_QUALITY; - break; - case HIGH_QUALITY: - quality = MED_QUALITY; - break; - case VERY_HIGH_QUALITY: - quality = HIGH_QUALITY; - break; -// case DYN_LOW_QUALITY: -// atFinalQuality = true; -// break; -// case DYN_MED_QUALITY: -// quality = DYN_LOW_QUALITY; -// break; -// case DYN_HIGH_QUALITY: -// quality = DYN_MED_QUALITY; -// break; - } - } - pthread_mutex_unlock(&mutex); - - AudioResampler* resampler; - - switch (quality) { - default: - case LOW_QUALITY: - ALOGV("Create linear Resampler"); - LOG_ALWAYS_FATAL_IF(format != AUDIO_FORMAT_PCM_16_BIT, "invalid pcm format"); - resampler = new (std::nothrow) AudioResamplerOrder1(inChannelCount, sampleRate); - break; - case MED_QUALITY: - ALOGV("Create cubic Resampler"); - LOG_ALWAYS_FATAL_IF(format != AUDIO_FORMAT_PCM_16_BIT, "invalid pcm format"); - resampler = new (std::nothrow) AudioResamplerCubic(inChannelCount, sampleRate); - break; - case HIGH_QUALITY: - ALOGV("Create HIGH_QUALITY sinc Resampler"); - LOG_ALWAYS_FATAL_IF(format != AUDIO_FORMAT_PCM_16_BIT, "invalid pcm format"); - ALOG_ASSERT(false, "HIGH_QUALITY isn't supported"); - // Cocos2d-x only uses MED_QUALITY, so we could remove Sinc relative files -// resampler = new (std::nothrow) AudioResamplerSinc(inChannelCount, sampleRate); - break; - case VERY_HIGH_QUALITY: - ALOGV("Create VERY_HIGH_QUALITY sinc Resampler = %d", quality); - LOG_ALWAYS_FATAL_IF(format != AUDIO_FORMAT_PCM_16_BIT, "invalid pcm format"); - // Cocos2d-x only uses MED_QUALITY, so we could remove Sinc relative files -// resampler = new (std::nothrow) AudioResamplerSinc(inChannelCount, sampleRate, quality); - ALOG_ASSERT(false, "VERY_HIGH_QUALITY isn't supported"); - break; - } - - // initialize resampler - resampler->init(); - return resampler; -} - -AudioResampler::AudioResampler(int inChannelCount, - int32_t sampleRate, src_quality quality) : - mChannelCount(inChannelCount), - mSampleRate(sampleRate), mInSampleRate(sampleRate), mInputIndex(0), - mPhaseFraction(0), mLocalTimeFreq(0), - mPTS(AudioBufferProvider::kInvalidPTS), mQuality(quality) { - - const int maxChannels = 2;//cjh quality < DYN_LOW_QUALITY ? 2 : 8; - if (inChannelCount < 1 - || inChannelCount > maxChannels) { - LOG_ALWAYS_FATAL("Unsupported sample format %d quality %d channels", - quality, inChannelCount); - } - if (sampleRate <= 0) { - LOG_ALWAYS_FATAL("Unsupported sample rate %d Hz", sampleRate); - } - - // initialize common members - mVolume[0] = mVolume[1] = 0; - mBuffer.frameCount = 0; -} - -AudioResampler::~AudioResampler() { - pthread_mutex_lock(&mutex); - src_quality quality = getQuality(); - uint32_t deltaMHz = qualityMHz(quality); - int32_t newMHz = currentMHz - deltaMHz; - ALOGV("resampler load %u -> %d MHz due to delta -%u MHz from quality %d", - currentMHz, newMHz, deltaMHz, quality); - LOG_ALWAYS_FATAL_IF(newMHz < 0, "negative resampler load %d MHz", newMHz); - currentMHz = newMHz; - pthread_mutex_unlock(&mutex); -} - -void AudioResampler::setSampleRate(int32_t inSampleRate) { - mInSampleRate = inSampleRate; - mPhaseIncrement = (uint32_t)((kPhaseMultiplier * inSampleRate) / mSampleRate); -} - -void AudioResampler::setVolume(float left, float right) { - // TODO: Implement anti-zipper filter - // convert to U4.12 for internal integer use (round down) - // integer volume values are clamped to 0 to UNITY_GAIN. - mVolume[0] = u4_12_from_float(clampFloatVol(left)); - mVolume[1] = u4_12_from_float(clampFloatVol(right)); -} - -void AudioResampler::setLocalTimeFreq(uint64_t freq) { - mLocalTimeFreq = freq; -} - -void AudioResampler::setPTS(int64_t pts) { - mPTS = pts; -} - -int64_t AudioResampler::calculateOutputPTS(int outputFrameIndex) { - - if (mPTS == AudioBufferProvider::kInvalidPTS) { - return AudioBufferProvider::kInvalidPTS; - } else { - return mPTS + ((outputFrameIndex * mLocalTimeFreq) / mSampleRate); - } -} - -void AudioResampler::reset() { - mInputIndex = 0; - mPhaseFraction = 0; - mBuffer.frameCount = 0; -} - -// ---------------------------------------------------------------------------- - -size_t AudioResamplerOrder1::resample(int32_t* out, size_t outFrameCount, - AudioBufferProvider* provider) { - - // should never happen, but we overflow if it does - // ALOG_ASSERT(outFrameCount < 32767); - - // select the appropriate resampler - switch (mChannelCount) { - case 1: - return resampleMono16(out, outFrameCount, provider); - case 2: - return resampleStereo16(out, outFrameCount, provider); - default: - LOG_ALWAYS_FATAL("invalid channel count: %d", mChannelCount); - return 0; - } -} - -size_t AudioResamplerOrder1::resampleStereo16(int32_t* out, size_t outFrameCount, - AudioBufferProvider* provider) { - - int32_t vl = mVolume[0]; - int32_t vr = mVolume[1]; - - size_t inputIndex = mInputIndex; - uint32_t phaseFraction = mPhaseFraction; - uint32_t phaseIncrement = mPhaseIncrement; - size_t outputIndex = 0; - size_t outputSampleCount = outFrameCount * 2; - size_t inFrameCount = getInFrameCountRequired(outFrameCount); - - // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d", - // outFrameCount, inputIndex, phaseFraction, phaseIncrement); - - while (outputIndex < outputSampleCount) { - - // buffer is empty, fetch a new one - while (mBuffer.frameCount == 0) { - mBuffer.frameCount = inFrameCount; - provider->getNextBuffer(&mBuffer, - calculateOutputPTS(outputIndex / 2)); - if (mBuffer.raw == NULL) { - goto resampleStereo16_exit; - } - - // ALOGE("New buffer fetched: %d frames", mBuffer.frameCount); - if (mBuffer.frameCount > inputIndex) break; - - inputIndex -= mBuffer.frameCount; - mX0L = mBuffer.i16[mBuffer.frameCount*2-2]; - mX0R = mBuffer.i16[mBuffer.frameCount*2-1]; - provider->releaseBuffer(&mBuffer); - // mBuffer.frameCount == 0 now so we reload a new buffer - } - - int16_t *in = mBuffer.i16; - - // handle boundary case - while (inputIndex == 0) { - // ALOGE("boundary case"); - out[outputIndex++] += vl * Interp(mX0L, in[0], phaseFraction); - out[outputIndex++] += vr * Interp(mX0R, in[1], phaseFraction); - Advance(&inputIndex, &phaseFraction, phaseIncrement); - if (outputIndex == outputSampleCount) { - break; - } - } - - // process input samples - // ALOGE("general case"); - -#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1 - if (inputIndex + 2 < mBuffer.frameCount) { - int32_t* maxOutPt; - int32_t maxInIdx; - - maxOutPt = out + (outputSampleCount - 2); // 2 because 2 frames per loop - maxInIdx = mBuffer.frameCount - 2; - AsmStereo16Loop(in, maxOutPt, maxInIdx, outputIndex, out, inputIndex, vl, vr, - phaseFraction, phaseIncrement); - } -#endif // ASM_ARM_RESAMP1 - - while (outputIndex < outputSampleCount && inputIndex < mBuffer.frameCount) { - out[outputIndex++] += vl * Interp(in[inputIndex*2-2], - in[inputIndex*2], phaseFraction); - out[outputIndex++] += vr * Interp(in[inputIndex*2-1], - in[inputIndex*2+1], phaseFraction); - Advance(&inputIndex, &phaseFraction, phaseIncrement); - } - - // ALOGE("loop done - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex); - - // if done with buffer, save samples - if (inputIndex >= mBuffer.frameCount) { - inputIndex -= mBuffer.frameCount; - - // ALOGE("buffer done, new input index %d", inputIndex); - - mX0L = mBuffer.i16[mBuffer.frameCount*2-2]; - mX0R = mBuffer.i16[mBuffer.frameCount*2-1]; - provider->releaseBuffer(&mBuffer); - - // verify that the releaseBuffer resets the buffer frameCount - // ALOG_ASSERT(mBuffer.frameCount == 0); - } - } - - // ALOGE("output buffer full - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex); - -resampleStereo16_exit: - // save state - mInputIndex = inputIndex; - mPhaseFraction = phaseFraction; - return outputIndex / 2 /* channels for stereo */; -} - -size_t AudioResamplerOrder1::resampleMono16(int32_t* out, size_t outFrameCount, - AudioBufferProvider* provider) { - - int32_t vl = mVolume[0]; - int32_t vr = mVolume[1]; - - size_t inputIndex = mInputIndex; - uint32_t phaseFraction = mPhaseFraction; - uint32_t phaseIncrement = mPhaseIncrement; - size_t outputIndex = 0; - size_t outputSampleCount = outFrameCount * 2; - size_t inFrameCount = getInFrameCountRequired(outFrameCount); - - // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d", - // outFrameCount, inputIndex, phaseFraction, phaseIncrement); - while (outputIndex < outputSampleCount) { - // buffer is empty, fetch a new one - while (mBuffer.frameCount == 0) { - mBuffer.frameCount = inFrameCount; - provider->getNextBuffer(&mBuffer, - calculateOutputPTS(outputIndex / 2)); - if (mBuffer.raw == NULL) { - mInputIndex = inputIndex; - mPhaseFraction = phaseFraction; - goto resampleMono16_exit; - } - // ALOGE("New buffer fetched: %d frames", mBuffer.frameCount); - if (mBuffer.frameCount > inputIndex) break; - - inputIndex -= mBuffer.frameCount; - mX0L = mBuffer.i16[mBuffer.frameCount-1]; - provider->releaseBuffer(&mBuffer); - // mBuffer.frameCount == 0 now so we reload a new buffer - } - int16_t *in = mBuffer.i16; - - // handle boundary case - while (inputIndex == 0) { - // ALOGE("boundary case"); - int32_t sample = Interp(mX0L, in[0], phaseFraction); - out[outputIndex++] += vl * sample; - out[outputIndex++] += vr * sample; - Advance(&inputIndex, &phaseFraction, phaseIncrement); - if (outputIndex == outputSampleCount) { - break; - } - } - - // process input samples - // ALOGE("general case"); - -#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1 - if (inputIndex + 2 < mBuffer.frameCount) { - int32_t* maxOutPt; - int32_t maxInIdx; - - maxOutPt = out + (outputSampleCount - 2); - maxInIdx = (int32_t)mBuffer.frameCount - 2; - AsmMono16Loop(in, maxOutPt, maxInIdx, outputIndex, out, inputIndex, vl, vr, - phaseFraction, phaseIncrement); - } -#endif // ASM_ARM_RESAMP1 - - while (outputIndex < outputSampleCount && inputIndex < mBuffer.frameCount) { - int32_t sample = Interp(in[inputIndex-1], in[inputIndex], - phaseFraction); - out[outputIndex++] += vl * sample; - out[outputIndex++] += vr * sample; - Advance(&inputIndex, &phaseFraction, phaseIncrement); - } - - - // ALOGE("loop done - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex); - - // if done with buffer, save samples - if (inputIndex >= mBuffer.frameCount) { - inputIndex -= mBuffer.frameCount; - - // ALOGE("buffer done, new input index %d", inputIndex); - - mX0L = mBuffer.i16[mBuffer.frameCount-1]; - provider->releaseBuffer(&mBuffer); - - // verify that the releaseBuffer resets the buffer frameCount - // ALOG_ASSERT(mBuffer.frameCount == 0); - } - } - - // ALOGE("output buffer full - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex); - -resampleMono16_exit: - // save state - mInputIndex = inputIndex; - mPhaseFraction = phaseFraction; - return outputIndex; -} - -#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1 - -/******************************************************************* -* -* AsmMono16Loop -* asm optimized monotonic loop version; one loop is 2 frames -* Input: -* in : pointer on input samples -* maxOutPt : pointer on first not filled -* maxInIdx : index on first not used -* outputIndex : pointer on current output index -* out : pointer on output buffer -* inputIndex : pointer on current input index -* vl, vr : left and right gain -* phaseFraction : pointer on current phase fraction -* phaseIncrement -* Output: -* outputIndex : -* out : updated buffer -* inputIndex : index of next to use -* phaseFraction : phase fraction for next interpolation -* -*******************************************************************/ -__attribute__((noinline)) -void AudioResamplerOrder1::AsmMono16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx, - size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr, - uint32_t &phaseFraction, uint32_t phaseIncrement) -{ - (void)maxOutPt; // remove unused parameter warnings - (void)maxInIdx; - (void)outputIndex; - (void)out; - (void)inputIndex; - (void)vl; - (void)vr; - (void)phaseFraction; - (void)phaseIncrement; - (void)in; -#define MO_PARAM5 "36" // offset of parameter 5 (outputIndex) - - asm( - "stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n" - // get parameters - " ldr r6, [sp, #" MO_PARAM5 " + 20]\n" // &phaseFraction - " ldr r6, [r6]\n" // phaseFraction - " ldr r7, [sp, #" MO_PARAM5 " + 8]\n" // &inputIndex - " ldr r7, [r7]\n" // inputIndex - " ldr r8, [sp, #" MO_PARAM5 " + 4]\n" // out - " ldr r0, [sp, #" MO_PARAM5 " + 0]\n" // &outputIndex - " ldr r0, [r0]\n" // outputIndex - " add r8, r8, r0, asl #2\n" // curOut - " ldr r9, [sp, #" MO_PARAM5 " + 24]\n" // phaseIncrement - " ldr r10, [sp, #" MO_PARAM5 " + 12]\n" // vl - " ldr r11, [sp, #" MO_PARAM5 " + 16]\n" // vr - - // r0 pin, x0, Samp - - // r1 in - // r2 maxOutPt - // r3 maxInIdx - - // r4 x1, i1, i3, Out1 - // r5 out0 - - // r6 frac - // r7 inputIndex - // r8 curOut - - // r9 inc - // r10 vl - // r11 vr - - // r12 - // r13 sp - // r14 - - // the following loop works on 2 frames - - "1:\n" - " cmp r8, r2\n" // curOut - maxCurOut - " bcs 2f\n" - -#define MO_ONE_FRAME \ - " add r0, r1, r7, asl #1\n" /* in + inputIndex */\ - " ldrsh r4, [r0]\n" /* in[inputIndex] */\ - " ldr r5, [r8]\n" /* out[outputIndex] */\ - " ldrsh r0, [r0, #-2]\n" /* in[inputIndex-1] */\ - " bic r6, r6, #0xC0000000\n" /* phaseFraction & ... */\ - " sub r4, r4, r0\n" /* in[inputIndex] - in[inputIndex-1] */\ - " mov r4, r4, lsl #2\n" /* <<2 */\ - " smulwt r4, r4, r6\n" /* (x1-x0)*.. */\ - " add r6, r6, r9\n" /* phaseFraction + phaseIncrement */\ - " add r0, r0, r4\n" /* x0 - (..) */\ - " mla r5, r0, r10, r5\n" /* vl*interp + out[] */\ - " ldr r4, [r8, #4]\n" /* out[outputIndex+1] */\ - " str r5, [r8], #4\n" /* out[outputIndex++] = ... */\ - " mla r4, r0, r11, r4\n" /* vr*interp + out[] */\ - " add r7, r7, r6, lsr #30\n" /* inputIndex + phaseFraction>>30 */\ - " str r4, [r8], #4\n" /* out[outputIndex++] = ... */ - - MO_ONE_FRAME // frame 1 - MO_ONE_FRAME // frame 2 - - " cmp r7, r3\n" // inputIndex - maxInIdx - " bcc 1b\n" - "2:\n" - - " bic r6, r6, #0xC0000000\n" // phaseFraction & ... - // save modified values - " ldr r0, [sp, #" MO_PARAM5 " + 20]\n" // &phaseFraction - " str r6, [r0]\n" // phaseFraction - " ldr r0, [sp, #" MO_PARAM5 " + 8]\n" // &inputIndex - " str r7, [r0]\n" // inputIndex - " ldr r0, [sp, #" MO_PARAM5 " + 4]\n" // out - " sub r8, r0\n" // curOut - out - " asr r8, #2\n" // new outputIndex - " ldr r0, [sp, #" MO_PARAM5 " + 0]\n" // &outputIndex - " str r8, [r0]\n" // save outputIndex - - " ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}\n" - ); -} - -/******************************************************************* -* -* AsmStereo16Loop -* asm optimized stereo loop version; one loop is 2 frames -* Input: -* in : pointer on input samples -* maxOutPt : pointer on first not filled -* maxInIdx : index on first not used -* outputIndex : pointer on current output index -* out : pointer on output buffer -* inputIndex : pointer on current input index -* vl, vr : left and right gain -* phaseFraction : pointer on current phase fraction -* phaseIncrement -* Output: -* outputIndex : -* out : updated buffer -* inputIndex : index of next to use -* phaseFraction : phase fraction for next interpolation -* -*******************************************************************/ -__attribute__((noinline)) -void AudioResamplerOrder1::AsmStereo16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx, - size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr, - uint32_t &phaseFraction, uint32_t phaseIncrement) -{ - (void)maxOutPt; // remove unused parameter warnings - (void)maxInIdx; - (void)outputIndex; - (void)out; - (void)inputIndex; - (void)vl; - (void)vr; - (void)phaseFraction; - (void)phaseIncrement; - (void)in; -#define ST_PARAM5 "40" // offset of parameter 5 (outputIndex) - asm( - "stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, lr}\n" - // get parameters - " ldr r6, [sp, #" ST_PARAM5 " + 20]\n" // &phaseFraction - " ldr r6, [r6]\n" // phaseFraction - " ldr r7, [sp, #" ST_PARAM5 " + 8]\n" // &inputIndex - " ldr r7, [r7]\n" // inputIndex - " ldr r8, [sp, #" ST_PARAM5 " + 4]\n" // out - " ldr r0, [sp, #" ST_PARAM5 " + 0]\n" // &outputIndex - " ldr r0, [r0]\n" // outputIndex - " add r8, r8, r0, asl #2\n" // curOut - " ldr r9, [sp, #" ST_PARAM5 " + 24]\n" // phaseIncrement - " ldr r10, [sp, #" ST_PARAM5 " + 12]\n" // vl - " ldr r11, [sp, #" ST_PARAM5 " + 16]\n" // vr - - // r0 pin, x0, Samp - - // r1 in - // r2 maxOutPt - // r3 maxInIdx - - // r4 x1, i1, i3, out1 - // r5 out0 - - // r6 frac - // r7 inputIndex - // r8 curOut - - // r9 inc - // r10 vl - // r11 vr - - // r12 temporary - // r13 sp - // r14 - - "3:\n" - " cmp r8, r2\n" // curOut - maxCurOut - " bcs 4f\n" - -#define ST_ONE_FRAME \ - " bic r6, r6, #0xC0000000\n" /* phaseFraction & ... */\ -\ - " add r0, r1, r7, asl #2\n" /* in + 2*inputIndex */\ -\ - " ldrsh r4, [r0]\n" /* in[2*inputIndex] */\ - " ldr r5, [r8]\n" /* out[outputIndex] */\ - " ldrsh r12, [r0, #-4]\n" /* in[2*inputIndex-2] */\ - " sub r4, r4, r12\n" /* in[2*InputIndex] - in[2*InputIndex-2] */\ - " mov r4, r4, lsl #2\n" /* <<2 */\ - " smulwt r4, r4, r6\n" /* (x1-x0)*.. */\ - " add r12, r12, r4\n" /* x0 - (..) */\ - " mla r5, r12, r10, r5\n" /* vl*interp + out[] */\ - " ldr r4, [r8, #4]\n" /* out[outputIndex+1] */\ - " str r5, [r8], #4\n" /* out[outputIndex++] = ... */\ -\ - " ldrsh r12, [r0, #+2]\n" /* in[2*inputIndex+1] */\ - " ldrsh r0, [r0, #-2]\n" /* in[2*inputIndex-1] */\ - " sub r12, r12, r0\n" /* in[2*InputIndex] - in[2*InputIndex-2] */\ - " mov r12, r12, lsl #2\n" /* <<2 */\ - " smulwt r12, r12, r6\n" /* (x1-x0)*.. */\ - " add r12, r0, r12\n" /* x0 - (..) */\ - " mla r4, r12, r11, r4\n" /* vr*interp + out[] */\ - " str r4, [r8], #4\n" /* out[outputIndex++] = ... */\ -\ - " add r6, r6, r9\n" /* phaseFraction + phaseIncrement */\ - " add r7, r7, r6, lsr #30\n" /* inputIndex + phaseFraction>>30 */ - - ST_ONE_FRAME // frame 1 - ST_ONE_FRAME // frame 1 - - " cmp r7, r3\n" // inputIndex - maxInIdx - " bcc 3b\n" - "4:\n" - - " bic r6, r6, #0xC0000000\n" // phaseFraction & ... - // save modified values - " ldr r0, [sp, #" ST_PARAM5 " + 20]\n" // &phaseFraction - " str r6, [r0]\n" // phaseFraction - " ldr r0, [sp, #" ST_PARAM5 " + 8]\n" // &inputIndex - " str r7, [r0]\n" // inputIndex - " ldr r0, [sp, #" ST_PARAM5 " + 4]\n" // out - " sub r8, r0\n" // curOut - out - " asr r8, #2\n" // new outputIndex - " ldr r0, [sp, #" ST_PARAM5 " + 0]\n" // &outputIndex - " str r8, [r0]\n" // save outputIndex - - " ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, pc}\n" - ); -} - -#endif // ASM_ARM_RESAMP1 - - -// ---------------------------------------------------------------------------- - -} // namespace cocos2d { diff --git a/cocos/audio/android/AudioResampler.h b/cocos/audio/android/AudioResampler.h deleted file mode 100644 index 1e2a6ab..0000000 --- a/cocos/audio/android/AudioResampler.h +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include -#include - -#include "audio/android/AudioBufferProvider.h" - -//#include -//#include - -//#include -//#include -#include -#include "audio/android/audio.h" - -namespace cocos2d { - - -class AudioResampler { -public: - // Determines quality of SRC. - // LOW_QUALITY: linear interpolator (1st order) - // MED_QUALITY: cubic interpolator (3rd order) - // HIGH_QUALITY: fixed multi-tap FIR (e.g. 48KHz->44.1KHz) - // NOTE: high quality SRC will only be supported for - // certain fixed rate conversions. Sample rate cannot be - // changed dynamically. - enum src_quality { - DEFAULT_QUALITY=0, - LOW_QUALITY=1, - MED_QUALITY=2, - HIGH_QUALITY=3, - VERY_HIGH_QUALITY=4, - }; - - static const CONSTEXPR float UNITY_GAIN_FLOAT = 1.0f; - - static AudioResampler* create(audio_format_t format, int inChannelCount, - int32_t sampleRate, src_quality quality=DEFAULT_QUALITY); - - virtual ~AudioResampler(); - - virtual void init() = 0; - virtual void setSampleRate(int32_t inSampleRate); - virtual void setVolume(float left, float right); - virtual void setLocalTimeFreq(uint64_t freq); - - // set the PTS of the next buffer output by the resampler - virtual void setPTS(int64_t pts); - - // Resample int16_t samples from provider and accumulate into 'out'. - // A mono provider delivers a sequence of samples. - // A stereo provider delivers a sequence of interleaved pairs of samples. - // - // In either case, 'out' holds interleaved pairs of fixed-point Q4.27. - // That is, for a mono provider, there is an implicit up-channeling. - // Since this method accumulates, the caller is responsible for clearing 'out' initially. - // - // For a float resampler, 'out' holds interleaved pairs of float samples. - // - // Multichannel interleaved frames for n > 2 is supported for quality DYN_LOW_QUALITY, - // DYN_MED_QUALITY, and DYN_HIGH_QUALITY. - // - // Returns the number of frames resampled into the out buffer. - virtual size_t resample(int32_t* out, size_t outFrameCount, - AudioBufferProvider* provider) = 0; - - virtual void reset(); - virtual size_t getUnreleasedFrames() const { return mInputIndex; } - - // called from destructor, so must not be virtual - src_quality getQuality() const { return mQuality; } - -protected: - // number of bits for phase fraction - 30 bits allows nearly 2x downsampling - static const int kNumPhaseBits = 30; - - // phase mask for fraction - static const uint32_t kPhaseMask = (1LU<(outFrameCount)*mInSampleRate + (mSampleRate - 1))/mSampleRate; - // - // The double precision equivalent (float may not be precise enough): - // ceil(static_cast(outFrameCount) * mInSampleRate / mSampleRate); - // - // this relies on the fact that the mPhaseIncrement is rounded down from - // #phases * mInSampleRate/mSampleRate and the fact that Sum(Floor(x)) <= Floor(Sum(x)). - // http://www.proofwiki.org/wiki/Sum_of_Floors_Not_Greater_Than_Floor_of_Sums - // - // (so long as double precision is computed accurately enough to be considered - // greater than or equal to the Floor(x) value in int32_t arithmetic; thus this - // will not necessarily hold for floats). - // - // TODO: - // Greater accuracy and a tight bound is obtained by: - // 1) subtract and adjust for the current state of the AudioBufferProvider buffer. - // 2) using the exact integer formula where (ignoring 64b casting) - // inFrameCount = (mPhaseIncrement * (outFrameCount - 1) + mPhaseFraction) / phaseWrapLimit; - // phaseWrapLimit is the wraparound (1 << kNumPhaseBits), if not specified explicitly. - // - inline size_t getInFrameCountRequired(size_t outFrameCount) { - return (static_cast(outFrameCount)*mInSampleRate - + (mSampleRate - 1))/mSampleRate; - } - - inline float clampFloatVol(float volume) { - if (volume > UNITY_GAIN_FLOAT) { - return UNITY_GAIN_FLOAT; - } else if (volume >= 0.) { - return volume; - } - return 0.; // NaN or negative volume maps to 0. - } - -private: - const src_quality mQuality; - - // Return 'true' if the quality level is supported without explicit request - static bool qualityIsSupported(src_quality quality); - - // For pthread_once() - static void init_routine(); - - // Return the estimated CPU load for specific resampler in MHz. - // The absolute number is irrelevant, it's the relative values that matter. - static uint32_t qualityMHz(src_quality quality); -}; - -// ---------------------------------------------------------------------------- -} // namespace cocos2d { diff --git a/cocos/audio/android/AudioResamplerCubic.cpp b/cocos/audio/android/AudioResamplerCubic.cpp deleted file mode 100644 index c2cbf13..0000000 --- a/cocos/audio/android/AudioResamplerCubic.cpp +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "AudioResamplerCubic" - -#include -#include -#include -#include "audio/android/cutils/log.h" - -#include "audio/android/AudioResampler.h" -#include "audio/android/AudioResamplerCubic.h" - -namespace cocos2d { -// ---------------------------------------------------------------------------- - -void AudioResamplerCubic::init() { - memset(&left, 0, sizeof(state)); - memset(&right, 0, sizeof(state)); -} - -size_t AudioResamplerCubic::resample(int32_t* out, size_t outFrameCount, - AudioBufferProvider* provider) { - - // should never happen, but we overflow if it does - // ALOG_ASSERT(outFrameCount < 32767); - - // select the appropriate resampler - switch (mChannelCount) { - case 1: - return resampleMono16(out, outFrameCount, provider); - case 2: - return resampleStereo16(out, outFrameCount, provider); - default: - LOG_ALWAYS_FATAL("invalid channel count: %d", mChannelCount); - return 0; - } -} - -size_t AudioResamplerCubic::resampleStereo16(int32_t* out, size_t outFrameCount, - AudioBufferProvider* provider) { - - int32_t vl = mVolume[0]; - int32_t vr = mVolume[1]; - - size_t inputIndex = mInputIndex; - uint32_t phaseFraction = mPhaseFraction; - uint32_t phaseIncrement = mPhaseIncrement; - size_t outputIndex = 0; - size_t outputSampleCount = outFrameCount * 2; - size_t inFrameCount = getInFrameCountRequired(outFrameCount); - - // fetch first buffer - if (mBuffer.frameCount == 0) { - mBuffer.frameCount = inFrameCount; - provider->getNextBuffer(&mBuffer, mPTS); - if (mBuffer.raw == NULL) { - return 0; - } - // ALOGW("New buffer: offset=%p, frames=%dn", mBuffer.raw, mBuffer.frameCount); - } - int16_t *in = mBuffer.i16; - - while (outputIndex < outputSampleCount) { - int32_t sample; - int32_t x; - - // calculate output sample - x = phaseFraction >> kPreInterpShift; - out[outputIndex++] += vl * interp(&left, x); - out[outputIndex++] += vr * interp(&right, x); - // out[outputIndex++] += vr * in[inputIndex*2]; - - // increment phase - phaseFraction += phaseIncrement; - uint32_t indexIncrement = (phaseFraction >> kNumPhaseBits); - phaseFraction &= kPhaseMask; - - // time to fetch another sample - while (indexIncrement--) { - - inputIndex++; - if (inputIndex == mBuffer.frameCount) { - inputIndex = 0; - provider->releaseBuffer(&mBuffer); - mBuffer.frameCount = inFrameCount; - provider->getNextBuffer(&mBuffer, - calculateOutputPTS(outputIndex / 2)); - if (mBuffer.raw == NULL) { - goto save_state; // ugly, but efficient - } - in = mBuffer.i16; - // ALOGW("New buffer: offset=%p, frames=%d", mBuffer.raw, mBuffer.frameCount); - } - - // advance sample state - advance(&left, in[inputIndex*2]); - advance(&right, in[inputIndex*2+1]); - } - } - -save_state: - // ALOGW("Done: index=%d, fraction=%u", inputIndex, phaseFraction); - mInputIndex = inputIndex; - mPhaseFraction = phaseFraction; - return outputIndex / 2 /* channels for stereo */; -} - -size_t AudioResamplerCubic::resampleMono16(int32_t* out, size_t outFrameCount, - AudioBufferProvider* provider) { - - int32_t vl = mVolume[0]; - int32_t vr = mVolume[1]; - - size_t inputIndex = mInputIndex; - uint32_t phaseFraction = mPhaseFraction; - uint32_t phaseIncrement = mPhaseIncrement; - size_t outputIndex = 0; - size_t outputSampleCount = outFrameCount * 2; - size_t inFrameCount = getInFrameCountRequired(outFrameCount); - - // fetch first buffer - if (mBuffer.frameCount == 0) { - mBuffer.frameCount = inFrameCount; - provider->getNextBuffer(&mBuffer, mPTS); - if (mBuffer.raw == NULL) { - return 0; - } - // ALOGW("New buffer: offset=%p, frames=%d", mBuffer.raw, mBuffer.frameCount); - } - int16_t *in = mBuffer.i16; - - while (outputIndex < outputSampleCount) { - int32_t sample; - int32_t x; - - // calculate output sample - x = phaseFraction >> kPreInterpShift; - sample = interp(&left, x); - out[outputIndex++] += vl * sample; - out[outputIndex++] += vr * sample; - - // increment phase - phaseFraction += phaseIncrement; - uint32_t indexIncrement = (phaseFraction >> kNumPhaseBits); - phaseFraction &= kPhaseMask; - - // time to fetch another sample - while (indexIncrement--) { - - inputIndex++; - if (inputIndex == mBuffer.frameCount) { - inputIndex = 0; - provider->releaseBuffer(&mBuffer); - mBuffer.frameCount = inFrameCount; - provider->getNextBuffer(&mBuffer, - calculateOutputPTS(outputIndex / 2)); - if (mBuffer.raw == NULL) { - goto save_state; // ugly, but efficient - } - // ALOGW("New buffer: offset=%p, frames=%dn", mBuffer.raw, mBuffer.frameCount); - in = mBuffer.i16; - } - - // advance sample state - advance(&left, in[inputIndex]); - } - } - -save_state: - // ALOGW("Done: index=%d, fraction=%u", inputIndex, phaseFraction); - mInputIndex = inputIndex; - mPhaseFraction = phaseFraction; - return outputIndex; -} - -// ---------------------------------------------------------------------------- -} // namespace cocos2d { diff --git a/cocos/audio/android/AudioResamplerCubic.h b/cocos/audio/android/AudioResamplerCubic.h deleted file mode 100644 index ab7145f..0000000 --- a/cocos/audio/android/AudioResamplerCubic.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include - -#include "audio/android/AudioResampler.h" -#include "audio/android/AudioBufferProvider.h" - -namespace cocos2d { -// ---------------------------------------------------------------------------- - -class AudioResamplerCubic : public AudioResampler { -public: - AudioResamplerCubic(int inChannelCount, int32_t sampleRate) : - AudioResampler(inChannelCount, sampleRate, MED_QUALITY) { - } - virtual size_t resample(int32_t* out, size_t outFrameCount, - AudioBufferProvider* provider); -private: - // number of bits used in interpolation multiply - 14 bits avoids overflow - static const int kNumInterpBits = 14; - - // bits to shift the phase fraction down to avoid overflow - static const int kPreInterpShift = kNumPhaseBits - kNumInterpBits; - typedef struct { - int32_t a, b, c, y0, y1, y2, y3; - } state; - void init(); - size_t resampleMono16(int32_t* out, size_t outFrameCount, - AudioBufferProvider* provider); - size_t resampleStereo16(int32_t* out, size_t outFrameCount, - AudioBufferProvider* provider); - static inline int32_t interp(state* p, int32_t x) { - return (((((p->a * x >> 14) + p->b) * x >> 14) + p->c) * x >> 14) + p->y1; - } - static inline void advance(state* p, int16_t in) { - p->y0 = p->y1; - p->y1 = p->y2; - p->y2 = p->y3; - p->y3 = in; - p->a = (3 * (p->y1 - p->y2) - p->y0 + p->y3) >> 1; - p->b = (p->y2 << 1) + p->y0 - (((5 * p->y1 + p->y3)) >> 1); - p->c = (p->y2 - p->y0) >> 1; - } - state left, right; -}; - -// ---------------------------------------------------------------------------- -} // namespace cocos2d { diff --git a/cocos/audio/android/AudioResamplerPublic.h b/cocos/audio/android/AudioResamplerPublic.h deleted file mode 100644 index cb6e05b..0000000 --- a/cocos/audio/android/AudioResamplerPublic.h +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include - -namespace cocos2d { - -// AUDIO_RESAMPLER_DOWN_RATIO_MAX is the maximum ratio between the original -// audio sample rate and the target rate when downsampling, -// as permitted in the audio framework, e.g. AudioTrack and AudioFlinger. -// In practice, it is not recommended to downsample more than 6:1 -// for best audio quality, even though the audio framework permits a larger -// downsampling ratio. -// TODO: replace with an API -#define AUDIO_RESAMPLER_DOWN_RATIO_MAX 256 - -// AUDIO_RESAMPLER_UP_RATIO_MAX is the maximum suggested ratio between the original -// audio sample rate and the target rate when upsampling. It is loosely enforced by -// the system. One issue with large upsampling ratios is the approximation by -// an int32_t of the phase increments, making the resulting sample rate inexact. -#define AUDIO_RESAMPLER_UP_RATIO_MAX 65536 - -// AUDIO_TIMESTRETCH_SPEED_MIN and AUDIO_TIMESTRETCH_SPEED_MAX define the min and max time stretch -// speeds supported by the system. These are enforced by the system and values outside this range -// will result in a runtime error. -// Depending on the AudioPlaybackRate::mStretchMode, the effective limits might be narrower than -// the ones specified here -// AUDIO_TIMESTRETCH_SPEED_MIN_DELTA is the minimum absolute speed difference that might trigger a -// parameter update -#define AUDIO_TIMESTRETCH_SPEED_MIN 0.01f -#define AUDIO_TIMESTRETCH_SPEED_MAX 20.0f -#define AUDIO_TIMESTRETCH_SPEED_NORMAL 1.0f -#define AUDIO_TIMESTRETCH_SPEED_MIN_DELTA 0.0001f - -// AUDIO_TIMESTRETCH_PITCH_MIN and AUDIO_TIMESTRETCH_PITCH_MAX define the min and max time stretch -// pitch shifting supported by the system. These are not enforced by the system and values -// outside this range might result in a pitch different than the one requested. -// Depending on the AudioPlaybackRate::mStretchMode, the effective limits might be narrower than -// the ones specified here. -// AUDIO_TIMESTRETCH_PITCH_MIN_DELTA is the minimum absolute pitch difference that might trigger a -// parameter update -#define AUDIO_TIMESTRETCH_PITCH_MIN 0.25f -#define AUDIO_TIMESTRETCH_PITCH_MAX 4.0f -#define AUDIO_TIMESTRETCH_PITCH_NORMAL 1.0f -#define AUDIO_TIMESTRETCH_PITCH_MIN_DELTA 0.0001f - - -//Determines the current algorithm used for stretching -enum AudioTimestretchStretchMode : int32_t { - AUDIO_TIMESTRETCH_STRETCH_DEFAULT = 0, - AUDIO_TIMESTRETCH_STRETCH_SPEECH = 1, - //TODO: add more stretch modes/algorithms -}; - -//Limits for AUDIO_TIMESTRETCH_STRETCH_SPEECH mode -#define TIMESTRETCH_SONIC_SPEED_MIN 0.1f -#define TIMESTRETCH_SONIC_SPEED_MAX 6.0f - -//Determines behavior of Timestretch if current algorithm can't perform -//with current parameters. -// FALLBACK_CUT_REPEAT: (internal only) for speed <1.0 will truncate frames -// for speed > 1.0 will repeat frames -// FALLBACK_MUTE: will set all processed frames to zero -// FALLBACK_FAIL: will stop program execution and log a fatal error -enum AudioTimestretchFallbackMode : int32_t { - AUDIO_TIMESTRETCH_FALLBACK_CUT_REPEAT = -1, - AUDIO_TIMESTRETCH_FALLBACK_DEFAULT = 0, - AUDIO_TIMESTRETCH_FALLBACK_MUTE = 1, - AUDIO_TIMESTRETCH_FALLBACK_FAIL = 2, -}; - -struct AudioPlaybackRate { - float mSpeed; - float mPitch; - enum AudioTimestretchStretchMode mStretchMode; - enum AudioTimestretchFallbackMode mFallbackMode; -}; - -static const AudioPlaybackRate AUDIO_PLAYBACK_RATE_DEFAULT = { - AUDIO_TIMESTRETCH_SPEED_NORMAL, - AUDIO_TIMESTRETCH_PITCH_NORMAL, - AUDIO_TIMESTRETCH_STRETCH_DEFAULT, - AUDIO_TIMESTRETCH_FALLBACK_DEFAULT -}; - -static inline bool isAudioPlaybackRateEqual(const AudioPlaybackRate &pr1, - const AudioPlaybackRate &pr2) { - return fabs(pr1.mSpeed - pr2.mSpeed) < AUDIO_TIMESTRETCH_SPEED_MIN_DELTA && - fabs(pr1.mPitch - pr2.mPitch) < AUDIO_TIMESTRETCH_PITCH_MIN_DELTA && - pr2.mStretchMode == pr2.mStretchMode && - pr2.mFallbackMode == pr2.mFallbackMode; -} - -static inline bool isAudioPlaybackRateValid(const AudioPlaybackRate &playbackRate) { - if (playbackRate.mFallbackMode == AUDIO_TIMESTRETCH_FALLBACK_FAIL && - (playbackRate.mStretchMode == AUDIO_TIMESTRETCH_STRETCH_SPEECH || - playbackRate.mStretchMode == AUDIO_TIMESTRETCH_STRETCH_DEFAULT)) { - //test sonic specific constraints - return playbackRate.mSpeed >= TIMESTRETCH_SONIC_SPEED_MIN && - playbackRate.mSpeed <= TIMESTRETCH_SONIC_SPEED_MAX && - playbackRate.mPitch >= AUDIO_TIMESTRETCH_PITCH_MIN && - playbackRate.mPitch <= AUDIO_TIMESTRETCH_PITCH_MAX; - } else { - return playbackRate.mSpeed >= AUDIO_TIMESTRETCH_SPEED_MIN && - playbackRate.mSpeed <= AUDIO_TIMESTRETCH_SPEED_MAX && - playbackRate.mPitch >= AUDIO_TIMESTRETCH_PITCH_MIN && - playbackRate.mPitch <= AUDIO_TIMESTRETCH_PITCH_MAX; - } -} - -// TODO: Consider putting these inlines into a class scope - -// Returns the source frames needed to resample to destination frames. This is not a precise -// value and depends on the resampler (and possibly how it handles rounding internally). -// Nevertheless, this should be an upper bound on the requirements of the resampler. -// If srcSampleRate and dstSampleRate are equal, then it returns destination frames, which -// may not be true if the resampler is asynchronous. -static inline size_t sourceFramesNeeded( - uint32_t srcSampleRate, size_t dstFramesRequired, uint32_t dstSampleRate) { - // +1 for rounding - always do this even if matched ratio (resampler may use phases not ratio) - // +1 for additional sample needed for interpolation - return srcSampleRate == dstSampleRate ? dstFramesRequired : - size_t((uint64_t)dstFramesRequired * srcSampleRate / dstSampleRate + 1 + 1); -} - -// An upper bound for the number of destination frames possible from srcFrames -// after sample rate conversion. This may be used for buffer sizing. -static inline size_t destinationFramesPossible(size_t srcFrames, uint32_t srcSampleRate, - uint32_t dstSampleRate) { - if (srcSampleRate == dstSampleRate) { - return srcFrames; - } - uint64_t dstFrames = (uint64_t)srcFrames * dstSampleRate / srcSampleRate; - return dstFrames > 2 ? dstFrames - 2 : 0; -} - -static inline size_t sourceFramesNeededWithTimestretch( - uint32_t srcSampleRate, size_t dstFramesRequired, uint32_t dstSampleRate, - float speed) { - // required is the number of input frames the resampler needs - size_t required = sourceFramesNeeded(srcSampleRate, dstFramesRequired, dstSampleRate); - // to deliver this, the time stretcher requires: - return required * (double)speed + 1 + 1; // accounting for rounding dependencies -} - -// Identifies sample rates that we associate with music -// and thus eligible for better resampling and fast capture. -// This is somewhat less than 44100 to allow for pitch correction -// involving resampling as well as asynchronous resampling. -#define AUDIO_PROCESSING_MUSIC_RATE 40000 - -static inline bool isMusicRate(uint32_t sampleRate) { - return sampleRate >= AUDIO_PROCESSING_MUSIC_RATE; -} - -} // namespace cocos2d { - -// --------------------------------------------------------------------------- diff --git a/cocos/audio/android/CCThreadPool.cpp b/cocos/audio/android/CCThreadPool.cpp deleted file mode 100644 index 9cdc674..0000000 --- a/cocos/audio/android/CCThreadPool.cpp +++ /dev/null @@ -1,443 +0,0 @@ -/**************************************************************************** - Copyright (c) 2016 Chukong Technologies Inc. - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - - Inspired by https://github.com/vit-vit/CTPL - - ****************************************************************************/ - -#include "audio/android/CCThreadPool.h" -#include - - -#ifdef __ANDROID__ -#include -#define LOG_TAG "ThreadPool" -#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG,__VA_ARGS__) -#else -#define LOGD(...) printf(__VA_ARGS__) -#endif - -namespace cocos2d { - -#define DEFAULT_THREAD_POOL_MIN_NUM (4) -#define DEFAULT_THREAD_POOL_MAX_NUM (20) - -#define DEFAULT_SHRINK_INTERVAL (5.0f) -#define DEFAULT_SHRINK_STEP (2) -#define DEFAULT_STRETCH_STEP (2) - -static ThreadPool *__defaultThreadPool = nullptr; - -ThreadPool *ThreadPool::getDefaultThreadPool() -{ - if (__defaultThreadPool == nullptr) - { - __defaultThreadPool = newCachedThreadPool(DEFAULT_THREAD_POOL_MIN_NUM, - DEFAULT_THREAD_POOL_MAX_NUM, - DEFAULT_SHRINK_INTERVAL, DEFAULT_SHRINK_STEP, - DEFAULT_STRETCH_STEP); - } - - return __defaultThreadPool; -} - -void ThreadPool::destroyDefaultThreadPool() -{ - delete __defaultThreadPool; - __defaultThreadPool = nullptr; -} - -ThreadPool *ThreadPool::newCachedThreadPool(int minThreadNum, int maxThreadNum, int shrinkInterval, - int shrinkStep, int stretchStep) -{ - ThreadPool *pool = new(std::nothrow) ThreadPool(minThreadNum, maxThreadNum); - if (pool != nullptr) - { - pool->setFixedSize(false); - pool->setShrinkInterval(shrinkInterval); - pool->setShrinkStep(shrinkStep); - pool->setStretchStep(stretchStep); - } - return pool; -} - -ThreadPool *ThreadPool::newFixedThreadPool(int threadNum) -{ - ThreadPool *pool = new(std::nothrow) ThreadPool(threadNum, threadNum); - if (pool != nullptr) - { - pool->setFixedSize(true); - } - return pool; -} - -ThreadPool *ThreadPool::newSingleThreadPool() -{ - ThreadPool *pool = new(std::nothrow) ThreadPool(1, 1); - if (pool != nullptr) - { - pool->setFixedSize(true); - } - return pool; -} - -ThreadPool::ThreadPool(int minNum, int maxNum) - : _isDone(false), _isStop(false), _idleThreadNum(0), _minThreadNum(minNum), - _maxThreadNum(maxNum), _initedThreadNum(0), _shrinkInterval(DEFAULT_SHRINK_INTERVAL), - _shrinkStep(DEFAULT_SHRINK_STEP), _stretchStep(DEFAULT_STRETCH_STEP), - _isFixedSize(false) -{ - init(); -} - -// the destructor waits for all the functions in the queue to be finished -ThreadPool::~ThreadPool() -{ - stop(); -} - -// number of idle threads -int ThreadPool::getIdleThreadNum() const -{ - ThreadPool* thiz = const_cast(this); - std::lock_guard lk(thiz->_idleThreadNumMutex); - return _idleThreadNum; -} - -void ThreadPool::init() -{ - gettimeofday(&_lastShrinkTime, nullptr); - - _maxThreadNum = std::max(_minThreadNum, _maxThreadNum); - - _threads.resize(_maxThreadNum); - _abortFlags.resize(_maxThreadNum); - _idleFlags.resize(_maxThreadNum); - _initedFlags.resize(_maxThreadNum); - - for (int i = 0; i < _maxThreadNum; ++i) - { - _idleFlags[i] = std::make_shared>(false); - if (i < _minThreadNum) - { - _abortFlags[i] = std::make_shared>(false); - setThread(i); - _initedFlags[i] = std::make_shared>(true); - ++_initedThreadNum; - } - else - { - _abortFlags[i] = std::make_shared>(true); - _initedFlags[i] = std::make_shared>(false); - } - } -} - -bool ThreadPool::tryShrinkPool() -{ - LOGD("shrink pool, _idleThreadNum = %d \n", getIdleThreadNum()); - - struct timeval before; - gettimeofday(&before, nullptr); - - std::vector threadIDsToJoin; - int maxThreadNumToJoin = std::min(_initedThreadNum - _minThreadNum, _shrinkStep); - - for (int i = 0; i < _maxThreadNum; ++i) - { - if (threadIDsToJoin.size() >= maxThreadNumToJoin) - { - break; - } - - if (*_idleFlags[i]) - { - *_abortFlags[i] = true; - threadIDsToJoin.push_back(i); - } - } - - { - // stop the detached threads that were waiting - std::unique_lock lock(_mutex); - _cv.notify_all(); - } - - for (const auto& threadID : threadIDsToJoin) - { // wait for the computing threads to finish - if (_threads[threadID]->joinable()) - { - _threads[threadID]->join(); - } - - _threads[threadID].reset(); - *_initedFlags[threadID] = false; - --_initedThreadNum; - } - - struct timeval after; - gettimeofday(&after, nullptr); - - float seconds = (after.tv_sec - before.tv_sec) + (after.tv_usec - before.tv_usec) / 1000000.0f; - - LOGD("shrink %d threads, waste: %f seconds\n", (int) threadIDsToJoin.size(), seconds); - - if (_initedThreadNum <= _minThreadNum) - return true; - - return false; -} - -void ThreadPool::stretchPool(int count) -{ - struct timeval before; - gettimeofday(&before, nullptr); - - int oldThreadCount = _initedThreadNum; - int newThreadCount = 0; - - for (int i = 0; i < _maxThreadNum; ++i) - { - if (!*_initedFlags[i]) - { - *_abortFlags[i] = false; - setThread(i); - *_initedFlags[i] = true; - ++_initedThreadNum; - - if (++newThreadCount >= count) - { - break; - } - } - } - - if (newThreadCount > 0) - { - struct timeval after; - gettimeofday(&after, nullptr); - - float seconds = - (after.tv_sec - before.tv_sec) + (after.tv_usec - before.tv_usec) / 1000000.0f; - - LOGD("stretch pool from %d to %d, waste %f seconds\n", oldThreadCount, _initedThreadNum, - seconds); - } -} - -void ThreadPool::pushTask(const std::function& runnable, - TaskType type/* = DEFAULT*/) -{ - if (!_isFixedSize) - { - _idleThreadNumMutex.lock(); - int idleNum = _idleThreadNum; - _idleThreadNumMutex.unlock(); - - if (idleNum > _minThreadNum) - { - if (_taskQueue.empty()) - { - struct timeval now; - gettimeofday(&now, nullptr); - - float seconds = (now.tv_sec - _lastShrinkTime.tv_sec) + - (now.tv_usec - _lastShrinkTime.tv_usec) / 1000000.0f; - if (seconds > _shrinkInterval) - { - tryShrinkPool(); - _lastShrinkTime = now; - } - } - } - else if (idleNum == 0) - { - stretchPool(_stretchStep); - } - } - - auto callback = new(std::nothrow) std::function([runnable](int tid) { - runnable(tid); - }); - - Task task; - task.type = type; - task.callback = callback; - _taskQueue.push(std::move(task)); - - { - std::unique_lock lock(_mutex); - _cv.notify_one(); - } -} - -void ThreadPool::stopAllTasks() -{ - Task task; - while (_taskQueue.pop(task)) - { - delete task.callback; // empty the queue - } -} - -void ThreadPool::stopTasksByType(TaskType type) -{ - Task task; - - std::vector notStopTasks; - notStopTasks.reserve(_taskQueue.size()); - - while (_taskQueue.pop(task)) - { - if (task.type == type) - {// Delete the task from queue - delete task.callback; - } - else - {// If task type isn't match, push it into a vector, then insert to task queue again - notStopTasks.push_back(task); - } - } - - if (!notStopTasks.empty()) - { - for (const auto& t : notStopTasks) - { - _taskQueue.push(t); - } - } -} - -void ThreadPool::joinThread(int tid) -{ - if (tid < 0 || tid >= _threads.size()) - { - LOGD("Invalid thread id %d\n", tid); - return; - } - - // wait for the computing threads to finish - if (*_initedFlags[tid] && _threads[tid]->joinable()) - { - _threads[tid]->join(); - *_initedFlags[tid] = false; - --_initedThreadNum; - } -} - -int ThreadPool::getTaskNum() const -{ - return (int) _taskQueue.size(); -} - -void ThreadPool::setFixedSize(bool isFixedSize) -{ - _isFixedSize = isFixedSize; -} - -void ThreadPool::setShrinkInterval(int seconds) -{ - if (seconds >= 0) - _shrinkInterval = seconds; -} - -void ThreadPool::setShrinkStep(int step) -{ - if (step > 0) - _shrinkStep = step; -} - -void ThreadPool::setStretchStep(int step) -{ - if (step > 0) - _stretchStep = step; -} - -void ThreadPool::stop() -{ - if (_isDone || _isStop) - return; - _isDone = true; // give the waiting threads a command to finish - - { - std::unique_lock lock(_mutex); - _cv.notify_all(); // stop all waiting threads - } - - for (int i = 0, n = static_cast(_threads.size()); i < n; ++i) - { - joinThread(i); - } - // if there were no threads in the pool but some functors in the queue, the functors are not deleted by the threads - // therefore delete them here - stopAllTasks(); - _threads.clear(); - _abortFlags.clear(); -} - -void ThreadPool::setThread(int tid) -{ - std::shared_ptr> abort_ptr( - _abortFlags[tid]); // a copy of the shared ptr to the flag - auto f = [this, tid, abort_ptr/* a copy of the shared ptr to the abort */]() { - std::atomic& abort = *abort_ptr; - Task task; - bool isPop = _taskQueue.pop(task); - while (true) - { - while (isPop) - { // if there is anything in the queue - std::unique_ptr> func( - task.callback); // at return, delete the function even if an exception occurred - (*task.callback)(tid); - if (abort) - return; // the thread is wanted to stop, return even if the queue is not empty yet - else - isPop = _taskQueue.pop(task); - } - // the queue is empty here, wait for the next command - std::unique_lock lock(_mutex); - _idleThreadNumMutex.lock(); - ++_idleThreadNum; - _idleThreadNumMutex.unlock(); - - *_idleFlags[tid] = true; - _cv.wait(lock, [this, &task, &isPop, &abort]() { - isPop = _taskQueue.pop(task); - return isPop || _isDone || abort; - }); - *_idleFlags[tid] = false; - _idleThreadNumMutex.lock(); - --_idleThreadNum; - _idleThreadNumMutex.unlock(); - - if (!isPop) - return; // if the queue is empty and isDone == true or *flag then return - } - }; - _threads[tid].reset( - new(std::nothrow) std::thread(f)); // compiler may not support std::make_unique() -} - -} // namespace cocos2d { diff --git a/cocos/audio/android/CCThreadPool.h b/cocos/audio/android/CCThreadPool.h deleted file mode 100644 index b7783b4..0000000 --- a/cocos/audio/android/CCThreadPool.h +++ /dev/null @@ -1,237 +0,0 @@ -/**************************************************************************** - Copyright (c) 2016 Chukong Technologies Inc. - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - - Inspired by https://github.com/vit-vit/CTPL - - ****************************************************************************/ -#pragma once - -//#include "platform/CCPlatformMacros.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace cocos2d { - -/** - * @addtogroup base - * @{ - */ - -class ThreadPool -{ -public: - - enum class TaskType - { - DEFAULT = 0, - NETWORK, - IO, - AUDIO, - USER = 1000 - }; - - /* - * Gets the default thread pool which is a cached thread pool with default parameters. - */ - static ThreadPool *getDefaultThreadPool(); - - /* - * Destroys the default thread pool - */ - static void destroyDefaultThreadPool(); - - /* - * Creates a cached thread pool - * @note The return value has to be delete while it doesn't needed - */ - static ThreadPool *newCachedThreadPool(int minThreadNum, int maxThreadNum, int shrinkInterval, - int shrinkStep, int stretchStep); - - /* - * Creates a thread pool with fixed thread count - * @note The return value has to be delete while it doesn't needed - */ - static ThreadPool *newFixedThreadPool(int threadNum); - - /* - * Creates a thread pool with only one thread in the pool, it could be used to execute multiply tasks serially in just one thread. - * @note The return value has to be delete while it doesn't needed - */ - static ThreadPool *newSingleThreadPool(); - - // the destructor waits for all the functions in the queue to be finished - ~ThreadPool(); - - /* Pushs a task to thread pool - * @param runnable The callback of the task executed in sub thread - * @param type The task type, it's TASK_TYPE_DEFAULT if this argument isn't assigned - * @note This function has to be invoked in cocos thread - */ - void pushTask(const std::function& runnable, TaskType type = TaskType::DEFAULT); - - // Stops all tasks, it will remove all tasks in queue - void stopAllTasks(); - - // Stops some tasks by type - void stopTasksByType(TaskType type); - - // Gets the minimum thread numbers - inline int getMinThreadNum() const - { return _minThreadNum; }; - - // Gets the maximum thread numbers - inline int getMaxThreadNum() const - { return _maxThreadNum; }; - - // Gets the number of idle threads - int getIdleThreadNum() const; - - // Gets the number of initialized threads - inline int getInitedThreadNum() const - { return _initedThreadNum; }; - - // Gets the task number - int getTaskNum() const; - - /* - * Trys to shrink pool - * @note This method is only available for cached thread pool - */ - bool tryShrinkPool(); - -private: - ThreadPool(int minNum, int maxNum); - - ThreadPool(const ThreadPool&); - - ThreadPool(ThreadPool&&); - - ThreadPool& operator=(const ThreadPool&); - - ThreadPool& operator=(ThreadPool&&); - - void init(); - - void stop(); - - void setThread(int tid); - - void joinThread(int tid); - - void setFixedSize(bool isFixedSize); - - void setShrinkInterval(int seconds); - - void setShrinkStep(int step); - - void setStretchStep(int step); - - void stretchPool(int count); - - std::vector> _threads; - std::vector>> _abortFlags; - std::vector>> _idleFlags; - std::vector>> _initedFlags; - - template - class ThreadSafeQueue - { - public: - bool push(T const& value) - { - std::unique_lock lock(this->mutex); - this->q.push(value); - return true; - } - - // deletes the retrieved element, do not use for non integral types - bool pop(T& v) - { - std::unique_lock lock(this->mutex); - if (this->q.empty()) - return false; - v = this->q.front(); - this->q.pop(); - return true; - } - - bool empty() const - { - auto thiz = const_cast(this); - std::unique_lock lock(thiz->mutex); - return this->q.empty(); - } - - size_t size() const - { - auto thiz = const_cast(this); - std::unique_lock lock(thiz->mutex); - return this->q.size(); - } - - private: - std::queue q; - std::mutex mutex; - }; - - struct Task - { - TaskType type; - std::function *callback; - }; - - ThreadSafeQueue _taskQueue; - std::atomic _isDone; - std::atomic _isStop; - - //FIXME: std::atomic isn't supported by ndk-r10e while compiling with `armeabi` arch. - // So using a mutex here instead. - int _idleThreadNum; // how many threads are waiting - std::mutex _idleThreadNumMutex; - - std::mutex _mutex; - std::condition_variable _cv; - - int _minThreadNum; - int _maxThreadNum; - int _initedThreadNum; - - struct timeval _lastShrinkTime; - float _shrinkInterval; - int _shrinkStep; - int _stretchStep; - bool _isFixedSize; -}; - -// end of base group -/// @} - -} // namespace cocos2d { diff --git a/cocos/audio/android/IAudioPlayer.h b/cocos/audio/android/IAudioPlayer.h deleted file mode 100644 index 61eefd5..0000000 --- a/cocos/audio/android/IAudioPlayer.h +++ /dev/null @@ -1,89 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ - -#pragma once - -#include - -namespace cocos2d { - -class IAudioPlayer -{ -public: - enum class State - { - INVALID = 0, - INITIALIZED, - PLAYING, - PAUSED, - STOPPED, - OVER - }; - - using PlayEventCallback = std::function; - - virtual ~IAudioPlayer() - { }; - - virtual int getId() const = 0; - - virtual void setId(int id) = 0; - - virtual std::string getUrl() const = 0; - - virtual State getState() const = 0; - - virtual void play() = 0; - - virtual void pause() = 0; - - virtual void resume() = 0; - - virtual void stop() = 0; - - virtual void rewind() = 0; - - virtual void setVolume(float volume) = 0; - - virtual float getVolume() const = 0; - - virtual void setAudioFocus(bool isFocus) = 0; - - virtual void setLoop(bool isLoop) = 0; - - virtual bool isLoop() const = 0; - - virtual float getDuration() const = 0; - - virtual float getPosition() const = 0; - - virtual bool setPosition(float pos) = 0; - - // @note: STOPPED event is invoked in main thread - // OVER event is invoked in sub thread - virtual void setPlayEventCallback(const PlayEventCallback &playEventCallback) = 0; -}; - -} // namespace cocos2d { diff --git a/cocos/audio/android/ICallerThreadUtils.h b/cocos/audio/android/ICallerThreadUtils.h deleted file mode 100644 index 8363334..0000000 --- a/cocos/audio/android/ICallerThreadUtils.h +++ /dev/null @@ -1,42 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ -#pragma once - -#include -#include - -namespace cocos2d { - -class ICallerThreadUtils -{ -public: - virtual ~ICallerThreadUtils() - { }; - - virtual void performFunctionInCallerThread(const std::function& func) = 0; - virtual std::thread::id getCallerThreadId() = 0; -}; - -} // namespace cocos2d { diff --git a/cocos/audio/android/IVolumeProvider.h b/cocos/audio/android/IVolumeProvider.h deleted file mode 100644 index 5aeb7c2..0000000 --- a/cocos/audio/android/IVolumeProvider.h +++ /dev/null @@ -1,45 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ -#pragma once - -#include "audio/android/audio_utils/include/audio_utils/minifloat.h" - -namespace cocos2d { - -class IVolumeProvider -{ -public: - // The provider implementation is responsible for validating that the return value is in range. - virtual gain_minifloat_packed_t getVolumeLR() = 0; - -protected: - IVolumeProvider() - { } - - virtual ~IVolumeProvider() - { } -}; - -} // namespace cocos2d { diff --git a/cocos/audio/android/OpenSLHelper.h b/cocos/audio/android/OpenSLHelper.h deleted file mode 100644 index bc81316..0000000 --- a/cocos/audio/android/OpenSLHelper.h +++ /dev/null @@ -1,100 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ - -#pragma once - -#include "audio/android/cutils/log.h" - -#include -#include -#include -#include - -#define SL_SAFE_DELETE(obj) \ - if ((obj) != nullptr) { delete (obj); (obj) = nullptr; } - -#define SL_DESTROY_OBJ(OBJ) \ - if ((OBJ) != nullptr) { \ - (*(OBJ))->Destroy(OBJ); \ - (OBJ) = nullptr; \ - } - -#define SL_RETURN_VAL_IF_FAILED(r, rval, ...) \ - if (r != SL_RESULT_SUCCESS) {\ - ALOGE(__VA_ARGS__); \ - return rval; \ - } - -#define SL_RETURN_IF_FAILED(r, ...) \ - if (r != SL_RESULT_SUCCESS) {\ - ALOGE(__VA_ARGS__); \ - return; \ - } - -#define SL_PRINT_ERROR_IF_FAILED(r, ...) \ - if (r != SL_RESULT_SUCCESS) {\ - ALOGE(__VA_ARGS__); \ - } - -typedef std::function FdGetterCallback; - - -// Copied from OpenSLES_AndroidMetadata.h in android-21 -// It's because android-10 doesn't contain this header file -/** - * Additional metadata keys to be used in SLMetadataExtractionItf: - * the ANDROID_KEY_PCMFORMAT_* keys follow the fields of the SLDataFormat_PCM struct, and as such - * all values corresponding to these keys are of SLuint32 type, and are defined as the fields - * of the same name in SLDataFormat_PCM. The exception is that sample rate is expressed here - * in Hz units, rather than in milliHz units. - */ -#ifndef ANDROID_KEY_PCMFORMAT_NUMCHANNELS -#define ANDROID_KEY_PCMFORMAT_NUMCHANNELS "AndroidPcmFormatNumChannels" -#endif - -#ifndef ANDROID_KEY_PCMFORMAT_SAMPLERATE -#define ANDROID_KEY_PCMFORMAT_SAMPLERATE "AndroidPcmFormatSampleRate" -#endif - -#ifndef ANDROID_KEY_PCMFORMAT_BITSPERSAMPLE -#define ANDROID_KEY_PCMFORMAT_BITSPERSAMPLE "AndroidPcmFormatBitsPerSample" -#endif - -#ifndef ANDROID_KEY_PCMFORMAT_CONTAINERSIZE -#define ANDROID_KEY_PCMFORMAT_CONTAINERSIZE "AndroidPcmFormatContainerSize" -#endif - -#ifndef ANDROID_KEY_PCMFORMAT_CHANNELMASK -#define ANDROID_KEY_PCMFORMAT_CHANNELMASK "AndroidPcmFormatChannelMask" -#endif - -#ifndef ANDROID_KEY_PCMFORMAT_ENDIANNESS -#define ANDROID_KEY_PCMFORMAT_ENDIANNESS "AndroidPcmFormatEndianness" -#endif - -#define clockNow() std::chrono::high_resolution_clock::now() -#define intervalInMS(oldTime, newTime) (static_cast(std::chrono::duration_cast((newTime) - (oldTime)).count()) / 1000.f) - -#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) diff --git a/cocos/audio/android/PcmAudioPlayer.cpp b/cocos/audio/android/PcmAudioPlayer.cpp deleted file mode 100644 index ab88880..0000000 --- a/cocos/audio/android/PcmAudioPlayer.cpp +++ /dev/null @@ -1,226 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ - -#define LOG_TAG "PcmAudioPlayer" - -#include "audio/android/cutils/log.h" -#include "audio/android/PcmAudioPlayer.h" -#include "audio/android/AudioMixerController.h" -#include "audio/android/ICallerThreadUtils.h" - -namespace cocos2d { - -PcmAudioPlayer::PcmAudioPlayer(AudioMixerController * controller, ICallerThreadUtils* callerThreadUtils) - : _id(-1) - , _track(nullptr) - , _playEventCallback(nullptr) - , _controller(controller) - , _callerThreadUtils(callerThreadUtils) -{ - ALOGV("PcmAudioPlayer constructor: %p", this); -} - -PcmAudioPlayer::~PcmAudioPlayer() -{ - ALOGV("In the destructor of PcmAudioPlayer (%p)", this); - delete _track; -} - -bool PcmAudioPlayer::prepare(const std::string &url, const PcmData &decResult) -{ - _url = url; - _decResult = decResult; - - _track = new (std::nothrow) Track(_decResult); - - std::thread::id callerThreadId = _callerThreadUtils->getCallerThreadId(); - - // @note The logic may cause this issue https://github.com/cocos2d/cocos2d-x/issues/17707 - // Assume that AudioEngine::stop(id) is invoked and the audio is played over meanwhile. - // Since State::OVER and State::DESTROYED are triggered in the audio mixing thread, it will - // call 'performFunctionInCallerThread' to post events to cocos's message queue. - // Therefore, the sequence in cocos's thread will be |STOP|OVER|DESTROYED|. - // Although, we remove the audio id in |STOPPED| callback, because it's asynchronous operation, - // |OVER| and |DESTROYED| callbacks will still be invoked in cocos's thread. - // HOW TO FIX: If the previous state is |STOPPED| and the current state - // is |OVER|, just skip to invoke |OVER| callback. - - _track->onStateChanged = [this, callerThreadId](Track::State state) { - // It maybe in sub thread - Track::State prevState = _track->getPrevState(); - auto func = [this, state, prevState](){ - // It's in caller's thread - if (state == Track::State::OVER && prevState != Track::State::STOPPED) - { - if (_playEventCallback != nullptr) - { - _playEventCallback(State::OVER); - } - } - else if (state == Track::State::STOPPED) - { - if (_playEventCallback != nullptr) - { - _playEventCallback(State::STOPPED); - } - } - else if (state == Track::State::DESTROYED) - { - delete this; - } - }; - - if (callerThreadId == std::this_thread::get_id()) - { // onStateChanged(Track::State::STOPPED) is in caller's (Cocos's) thread. - func(); - } - else - { // onStateChanged(Track::State::OVER) or onStateChanged(Track::State::DESTROYED) are in audio mixing thread. - _callerThreadUtils->performFunctionInCallerThread(func); - } - }; - - setVolume(1.0f); - - return true; -} - -void PcmAudioPlayer::rewind() -{ - ALOGW("PcmAudioPlayer::rewind isn't supported!"); -} - -void PcmAudioPlayer::setVolume(float volume) -{ - _track->setVolume(volume); -} - -float PcmAudioPlayer::getVolume() const -{ - return _track->getVolume(); -} - -void PcmAudioPlayer::setAudioFocus(bool isFocus) -{ - _track->setAudioFocus(isFocus); -} - -void PcmAudioPlayer::setLoop(bool isLoop) -{ - _track->setLoop(isLoop); -} - -bool PcmAudioPlayer::isLoop() const -{ - return _track->isLoop(); -} - -float PcmAudioPlayer::getDuration() const -{ - return _decResult.duration; -} - -float PcmAudioPlayer::getPosition() const -{ - return _track->getPosition(); -} - -bool PcmAudioPlayer::setPosition(float pos) -{ - return _track->setPosition(pos); -} - -void PcmAudioPlayer::setPlayEventCallback(const PlayEventCallback &playEventCallback) -{ - _playEventCallback = playEventCallback; -} - -void PcmAudioPlayer::play() -{ - // put track to AudioMixerController - ALOGV("PcmAudioPlayer (%p) play, url: %s", this, _url.c_str()); - _controller->addTrack(_track); - _track->setState(Track::State::PLAYING); -} - -void PcmAudioPlayer::pause() -{ - ALOGV("PcmAudioPlayer (%p) pause, url: %s", this, _url.c_str()); - _track->setState(Track::State::PAUSED); -} - -void PcmAudioPlayer::resume() -{ - ALOGV("PcmAudioPlayer (%p) resume, url: %s", this, _url.c_str()); - _track->setState(Track::State::RESUMED); -} - -void PcmAudioPlayer::stop() -{ - ALOGV("PcmAudioPlayer (%p) stop, url: %s", this, _url.c_str()); - _track->setState(Track::State::STOPPED); -} - -IAudioPlayer::State PcmAudioPlayer::getState() const -{ - IAudioPlayer::State state = State::INVALID; - - if (_track != nullptr) - { - switch (_track->getState()) - { - case Track::State::IDLE: - state = State::INITIALIZED; - break; - - case Track::State::PLAYING: - state = State::PLAYING; - break; - - case Track::State::RESUMED: - state = State::PLAYING; - break; - - case Track::State::PAUSED: - state = State::PAUSED; - break; - - case Track::State::STOPPED: - state = State::STOPPED; - break; - - case Track::State::OVER: - state = State::OVER; - break; - - default: - state = State::INVALID; - break; - } - } - return state; -} - -} // namespace cocos2d { diff --git a/cocos/audio/android/PcmAudioPlayer.h b/cocos/audio/android/PcmAudioPlayer.h deleted file mode 100644 index 4959877..0000000 --- a/cocos/audio/android/PcmAudioPlayer.h +++ /dev/null @@ -1,98 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ -#pragma once - -#include -#include "audio/android/IAudioPlayer.h" -#include "audio/android/PcmData.h" -#include "audio/android/Track.h" - -namespace cocos2d { - -class ICallerThreadUtils; -class AudioMixerController; - -class PcmAudioPlayer : public IAudioPlayer -{ -public: - - bool prepare(const std::string &url, const PcmData &decResult); - - // Override Functions Begin - virtual int getId() const override { return _id; }; - - virtual void setId(int id) override { _id = id; }; - - virtual std::string getUrl() const override { return _url; }; - - virtual State getState() const override; - - virtual void play() override; - - virtual void pause() override; - - virtual void resume() override; - - virtual void stop() override; - - virtual void rewind() override; - - virtual void setVolume(float volume) override; - - virtual float getVolume() const override; - - virtual void setAudioFocus(bool isFocus) override; - - virtual void setLoop(bool isLoop) override; - - virtual bool isLoop() const override; - - virtual float getDuration() const override; - - virtual float getPosition() const override; - - virtual bool setPosition(float pos) override; - - virtual void setPlayEventCallback(const PlayEventCallback &playEventCallback) override; - - // Override Functions End - -private: - PcmAudioPlayer(AudioMixerController * controller, ICallerThreadUtils* callerThreadUtils); - virtual ~PcmAudioPlayer(); - -private: - int _id; - std::string _url; - PcmData _decResult; - Track* _track; - PlayEventCallback _playEventCallback; - AudioMixerController * _controller; - ICallerThreadUtils* _callerThreadUtils; - - friend class AudioPlayerProvider; -}; - -} // namespace cocos2d { diff --git a/cocos/audio/android/PcmAudioService.cpp b/cocos/audio/android/PcmAudioService.cpp deleted file mode 100644 index 70950e4..0000000 --- a/cocos/audio/android/PcmAudioService.cpp +++ /dev/null @@ -1,200 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ - -#define LOG_TAG "PcmAudioService" - -#include "audio/android/PcmAudioService.h" -#include "audio/android/AudioMixerController.h" - -namespace cocos2d { - -static std::vector __silenceData; - -#define AUDIO_PLAYER_BUFFER_COUNT (2) - -class SLPcmAudioPlayerCallbackProxy -{ -public: - static void samplePlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) - { - PcmAudioService *thiz = reinterpret_cast(context); - thiz->bqFetchBufferCallback(bq); - } -}; - -PcmAudioService::PcmAudioService(SLEngineItf engineItf, SLObjectItf outputMixObject) - : _engineItf(engineItf), _outputMixObj(outputMixObject), _playObj(nullptr), - _playItf(nullptr), _volumeItf(nullptr), _bufferQueueItf(nullptr), _numChannels(-1), - _sampleRate(-1), _bufferSizeInBytes(0), _controller(nullptr), _isInitialised(false) -{ -} - -PcmAudioService::~PcmAudioService() -{ - ALOGV("PcmAudioServicee() (%p), before destroy play object", this); - SL_DESTROY_OBJ(_playObj); - ALOGV("PcmAudioServicee() end"); -} - -bool PcmAudioService::enqueue() -{ - if (_controller->hasPlayingTacks()) - { - if (_controller->isPaused()) - { - SLresult r = (*_bufferQueueItf)->Enqueue(_bufferQueueItf, __silenceData.data(), __silenceData.size()); - SL_RETURN_VAL_IF_FAILED(r, false, "enqueue silent data failed!"); - } - else - { - _controller->mixOneFrame(); - - auto current = _controller->current(); - ALOG_ASSERT(current != nullptr, "current buffer is nullptr ..."); - SLresult r = (*_bufferQueueItf)->Enqueue(_bufferQueueItf, current->buf, current->size); - SL_RETURN_VAL_IF_FAILED(r, false, "enqueue failed!"); - } - } - else - { - SLresult r = (*_bufferQueueItf)->Enqueue(_bufferQueueItf, __silenceData.data(), __silenceData.size()); - SL_RETURN_VAL_IF_FAILED(r, false, "enqueue silent data failed!"); - } - - return true; -} - -void PcmAudioService::bqFetchBufferCallback(SLAndroidSimpleBufferQueueItf bq) -{ - // FIXME: PcmAudioService instance may be destroyed, we need to find a way to wait... - // It's in sub thread - enqueue(); -} - -bool PcmAudioService::init(AudioMixerController* controller, int numChannels, int sampleRate, int bufferSizeInBytes) -{ - _controller = controller; - _numChannels = numChannels; - _sampleRate = sampleRate; - _bufferSizeInBytes = bufferSizeInBytes; - - SLuint32 channelMask = SL_SPEAKER_FRONT_CENTER; - - if (numChannels > 1) - { - channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; - } - - SLDataFormat_PCM formatPcm = { - SL_DATAFORMAT_PCM, - (SLuint32) numChannels, - (SLuint32) sampleRate * 1000, - SL_PCMSAMPLEFORMAT_FIXED_16, - SL_PCMSAMPLEFORMAT_FIXED_16, - channelMask, - SL_BYTEORDER_LITTLEENDIAN - }; - - SLDataLocator_AndroidSimpleBufferQueue locBufQueue = { - SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, - AUDIO_PLAYER_BUFFER_COUNT - }; - SLDataSource source = {&locBufQueue, &formatPcm}; - - SLDataLocator_OutputMix locOutmix = { - SL_DATALOCATOR_OUTPUTMIX, - _outputMixObj - }; - SLDataSink sink = {&locOutmix, nullptr}; - - const SLInterfaceID ids[] = { - SL_IID_PLAY, - SL_IID_VOLUME, - SL_IID_ANDROIDSIMPLEBUFFERQUEUE, - }; - - const SLboolean req[] = { - SL_BOOLEAN_TRUE, - SL_BOOLEAN_TRUE, - SL_BOOLEAN_TRUE, - }; - - SLresult r; - - r = (*_engineItf)->CreateAudioPlayer(_engineItf, &_playObj, &source, &sink, - sizeof(ids) / sizeof(ids[0]), ids, req); - SL_RETURN_VAL_IF_FAILED(r, false, "CreateAudioPlayer failed"); - - r = (*_playObj)->Realize(_playObj, SL_BOOLEAN_FALSE); - SL_RETURN_VAL_IF_FAILED(r, false, "Realize failed"); - - r = (*_playObj)->GetInterface(_playObj, SL_IID_PLAY, &_playItf); - SL_RETURN_VAL_IF_FAILED(r, false, "GetInterface SL_IID_PLAY failed"); - - r = (*_playObj)->GetInterface(_playObj, SL_IID_VOLUME, &_volumeItf); - SL_RETURN_VAL_IF_FAILED(r, false, "GetInterface SL_IID_VOLUME failed"); - - r = (*_playObj)->GetInterface(_playObj, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &_bufferQueueItf); - SL_RETURN_VAL_IF_FAILED(r, false, "GetInterface SL_IID_ANDROIDSIMPLEBUFFERQUEUE failed"); - - r = (*_bufferQueueItf)->RegisterCallback(_bufferQueueItf, - SLPcmAudioPlayerCallbackProxy::samplePlayerCallback, - this); - SL_RETURN_VAL_IF_FAILED(r, false, "_bufferQueueItf RegisterCallback failed"); - - if (__silenceData.empty()) - { - __silenceData.resize(_numChannels * _bufferSizeInBytes, 0x00); - } - - r = (*_bufferQueueItf)->Enqueue(_bufferQueueItf, __silenceData.data(), __silenceData.size()); - SL_RETURN_VAL_IF_FAILED(r, false, "_bufferQueueItf Enqueue failed"); - - r = (*_playItf)->SetPlayState(_playItf, SL_PLAYSTATE_PLAYING); - SL_RETURN_VAL_IF_FAILED(r, false, "SetPlayState failed"); - - _isInitialised = true; - return true; -} - -void PcmAudioService::pause() -{ - if (_isInitialised) - { - SLresult r = (*_playItf)->SetPlayState(_playItf, SL_PLAYSTATE_PAUSED); - SL_RETURN_IF_FAILED(r, "PcmAudioService::pause failed"); - } -} - -void PcmAudioService::resume() -{ - if (_isInitialised) - { - SLresult r = (*_playItf)->SetPlayState(_playItf, SL_PLAYSTATE_PLAYING); - SL_RETURN_IF_FAILED(r, "PcmAudioService::resume failed"); - } -} - -} // namespace cocos2d { diff --git a/cocos/audio/android/PcmAudioService.h b/cocos/audio/android/PcmAudioService.h deleted file mode 100644 index cebb82f..0000000 --- a/cocos/audio/android/PcmAudioService.h +++ /dev/null @@ -1,82 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ - -#pragma once - -#include "audio/android/IAudioPlayer.h" -#include "audio/android/OpenSLHelper.h" -#include "audio/android/PcmData.h" - -#include -#include - -namespace cocos2d { - -class AudioMixerController; - -class PcmAudioService -{ -public: - inline int getChannelCount() const - { return _numChannels; }; - - inline int getSampleRate() const - { return _sampleRate; }; - -private: - PcmAudioService(SLEngineItf engineItf, SLObjectItf outputMixObject); - - virtual ~PcmAudioService(); - - bool init(AudioMixerController* controller, int numChannels, int sampleRate, int bufferSizeInBytes); - - bool enqueue(); - - void bqFetchBufferCallback(SLAndroidSimpleBufferQueueItf bq); - - void pause(); - void resume(); - -private: - SLEngineItf _engineItf; - SLObjectItf _outputMixObj; - - SLObjectItf _playObj; - SLPlayItf _playItf; - SLVolumeItf _volumeItf; - SLAndroidSimpleBufferQueueItf _bufferQueueItf; - - int _numChannels; - int _sampleRate; - int _bufferSizeInBytes; - bool _isInitialised; - - AudioMixerController* _controller; - - friend class SLPcmAudioPlayerCallbackProxy; - friend class AudioPlayerProvider; -}; - -} // namespace cocos2d { diff --git a/cocos/audio/android/PcmBufferProvider.cpp b/cocos/audio/android/PcmBufferProvider.cpp deleted file mode 100644 index 82ca9b6..0000000 --- a/cocos/audio/android/PcmBufferProvider.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ - -#define LOG_TAG "PcmBufferProvider" - -#include "audio/android/cutils/log.h" -#include "audio/android/PcmBufferProvider.h" - -//#define VERY_VERY_VERBOSE_LOGGING -#ifdef VERY_VERY_VERBOSE_LOGGING -#define ALOGVV ALOGV -#else -#define ALOGVV(a...) do { } while (0) -#endif - -namespace cocos2d { - -PcmBufferProvider::PcmBufferProvider() - : _addr(nullptr) - , _numFrames(0) - , _frameSize(0) - , _nextFrame(0) - , _unrel(0) -{ - -} - -bool PcmBufferProvider::init(const void *addr, size_t frames, size_t frameSize) -{ - _addr = addr; - _numFrames = frames; - _frameSize = frameSize; - _nextFrame = 0; - _unrel = 0; - return true; -} - -status_t PcmBufferProvider::getNextBuffer(Buffer *buffer, - int64_t pts/* = kInvalidPTS*/) { - (void) pts; // suppress warning - size_t requestedFrames = buffer->frameCount; - if (requestedFrames > _numFrames - _nextFrame) { - buffer->frameCount = _numFrames - _nextFrame; - } - - ALOGVV("getNextBuffer() requested %zu frames out of %zu frames available," - " and returned %zu frames", - requestedFrames, (size_t) (_numFrames - _nextFrame), buffer->frameCount); - - _unrel = buffer->frameCount; - if (buffer->frameCount > 0) { - buffer->raw = (char *) _addr + _frameSize * _nextFrame; - return NO_ERROR; - } else { - buffer->raw = NULL; - return NOT_ENOUGH_DATA; - } -} - -void PcmBufferProvider::releaseBuffer(Buffer *buffer) { - if (buffer->frameCount > _unrel) { - ALOGVV("ERROR releaseBuffer() released %zu frames but only %zu available " - "to release", buffer->frameCount, _unrel); - _nextFrame += _unrel; - _unrel = 0; - } else { - ALOGVV("releaseBuffer() released %zu frames out of %zu frames available " - "to release", buffer->frameCount, _unrel); - _nextFrame += buffer->frameCount; - _unrel -= buffer->frameCount; - } - buffer->frameCount = 0; - buffer->raw = NULL; -} - -void PcmBufferProvider::reset() { - _nextFrame = 0; -} - -} // namespace cocos2d { diff --git a/cocos/audio/android/PcmBufferProvider.h b/cocos/audio/android/PcmBufferProvider.h deleted file mode 100644 index 253d9e9..0000000 --- a/cocos/audio/android/PcmBufferProvider.h +++ /dev/null @@ -1,52 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ - -#pragma once - -#include "audio/android/AudioBufferProvider.h" - -#include -#include - -namespace cocos2d { - -class PcmBufferProvider : public AudioBufferProvider -{ -public: - PcmBufferProvider(); - bool init(const void *addr, size_t frames, size_t frameSize); - virtual status_t getNextBuffer(Buffer *buffer, int64_t pts = kInvalidPTS) override ; - virtual void releaseBuffer(Buffer *buffer) override ; - void reset(); - -protected: - const void *_addr; // base address - size_t _numFrames; // total frames - size_t _frameSize; // size of each frame in bytes - size_t _nextFrame; // index of next frame to provide - size_t _unrel; // number of frames not yet released -}; - -} // namespace cocos2d { diff --git a/cocos/audio/android/PcmData.cpp b/cocos/audio/android/PcmData.cpp deleted file mode 100644 index 240aae8..0000000 --- a/cocos/audio/android/PcmData.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ - -#define LOG_TAG "PcmData" - -#include "audio/android/OpenSLHelper.h" -#include "audio/android/PcmData.h" - -namespace cocos2d { - -PcmData::PcmData() -{ -// ALOGV("In the constructor of PcmData (%p)", this); - reset(); -} - -PcmData::~PcmData() -{ -// ALOGV("In the destructor of PcmData (%p)", this); -} - -PcmData::PcmData(const PcmData &o) -{ -// ALOGV("In the copy constructor of PcmData (%p)", this); - numChannels = o.numChannels; - sampleRate = o.sampleRate; - bitsPerSample = o.bitsPerSample; - containerSize = o.containerSize; - channelMask = o.channelMask; - endianness = o.endianness; - numFrames = o.numFrames; - duration = o.duration; - pcmBuffer = std::move(o.pcmBuffer); -} - -PcmData::PcmData(PcmData &&o) -{ -// ALOGV("In the move constructor of PcmData (%p)", this); - numChannels = o.numChannels; - sampleRate = o.sampleRate; - bitsPerSample = o.bitsPerSample; - containerSize = o.containerSize; - channelMask = o.channelMask; - endianness = o.endianness; - numFrames = o.numFrames; - duration = o.duration; - pcmBuffer = std::move(o.pcmBuffer); - o.reset(); -} - -PcmData &PcmData::operator=(const PcmData &o) -{ -// ALOGV("In the copy assignment of PcmData"); - numChannels = o.numChannels; - sampleRate = o.sampleRate; - bitsPerSample = o.bitsPerSample; - containerSize = o.containerSize; - channelMask = o.channelMask; - endianness = o.endianness; - numFrames = o.numFrames; - duration = o.duration; - pcmBuffer = o.pcmBuffer; - return *this; -} - -PcmData &PcmData::operator=(PcmData &&o) -{ -// ALOGV("In the move assignment of PcmData"); - numChannels = o.numChannels; - sampleRate = o.sampleRate; - bitsPerSample = o.bitsPerSample; - containerSize = o.containerSize; - channelMask = o.channelMask; - endianness = o.endianness; - numFrames = o.numFrames; - duration = o.duration; - pcmBuffer = std::move(o.pcmBuffer); - o.reset(); - return *this; -} - -void PcmData::reset() -{ - numChannels = -1; - sampleRate = -1; - bitsPerSample = -1; - containerSize = -1; - channelMask = -1; - endianness = -1; - numFrames = -1; - duration = -1.0f; - pcmBuffer = nullptr; -} - -bool PcmData::isValid() const -{ - return numChannels > 0 && sampleRate > 0 && bitsPerSample > 0 && containerSize > 0 - && numFrames > 0 && duration > 0 && pcmBuffer != nullptr; -} - -std::string PcmData::toString() const -{ - std::string ret; - char buf[256] = {0}; - - snprintf(buf, sizeof(buf), - "numChannels: %d, sampleRate: %d, bitPerSample: %d, containerSize: %d, " - "channelMask: %d, endianness: %d, numFrames: %d, duration: %f", - numChannels, sampleRate, bitsPerSample, containerSize, channelMask, endianness, - numFrames, duration - ); - - ret = buf; - return ret; -} - -} // namespace cocos2d { diff --git a/cocos/audio/android/PcmData.h b/cocos/audio/android/PcmData.h deleted file mode 100644 index 18cf5cc..0000000 --- a/cocos/audio/android/PcmData.h +++ /dev/null @@ -1,66 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ - -#pragma once - -#include -#include -#include -#include - -namespace cocos2d { - -struct PcmData -{ - std::shared_ptr> pcmBuffer; - int numChannels; - int sampleRate; - int bitsPerSample; - int containerSize; - int channelMask; - int endianness; - int numFrames; - float duration; // in seconds - - PcmData(); - - ~PcmData(); - - PcmData(const PcmData &o); - - PcmData(PcmData &&o); - - PcmData &operator=(const PcmData &o); - - PcmData &operator=(PcmData &&o); - - void reset(); - - bool isValid() const; - - std::string toString() const; -}; - -} // namespace cocos2d { diff --git a/cocos/audio/android/Track.cpp b/cocos/audio/android/Track.cpp deleted file mode 100644 index f93fcae..0000000 --- a/cocos/audio/android/Track.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ - -#define LOG_TAG "Track" - -#include "audio/android/cutils/log.h" -#include "audio/android/Track.h" - -#include - -namespace cocos2d { - -Track::Track(const PcmData &pcmData) - : onStateChanged(nullptr) - , _pcmData(pcmData) - , _prevState(State::IDLE) - , _state(State::IDLE) - , _name(-1) - , _volume(1.0f) - , _isVolumeDirty(true) - , _isLoop(false) - , _isInitialized(false) - , _isAudioFocus(true) -{ - init(_pcmData.pcmBuffer->data(), _pcmData.numFrames, _pcmData.bitsPerSample / 8 * _pcmData.numChannels); -} - -Track::~Track() -{ - ALOGV("~Track(): %p", this); -} - -gain_minifloat_packed_t Track::getVolumeLR() -{ - float volume = _isAudioFocus ? _volume : 0.0f; - gain_minifloat_t v = gain_from_float(volume); - return gain_minifloat_pack(v, v); -} - -bool Track::setPosition(float pos) -{ - _nextFrame = (size_t) (pos * _numFrames / _pcmData.duration); - _unrel = 0; - return true; -} - -float Track::getPosition() const -{ - return _nextFrame * _pcmData.duration / _numFrames; -} - -void Track::setVolume(float volume) -{ - std::lock_guard lk(_volumeDirtyMutex); - if (fabs(_volume - volume) > 0.00001) - { - _volume = volume; - setVolumeDirty(true); - } -} - -float Track::getVolume() const -{ - return _volume; -} - -void Track::setAudioFocus(bool isFocus) -{ - _isAudioFocus = isFocus; - setVolumeDirty(true); -} - -void Track::setState(State state) -{ - std::lock_guard lk(_stateMutex); - if (_state != state) - { - _prevState = _state; - _state = state; - onStateChanged(_state); - } -}; - -} // namespace cocos2d { \ No newline at end of file diff --git a/cocos/audio/android/Track.h b/cocos/audio/android/Track.h deleted file mode 100644 index cec7588..0000000 --- a/cocos/audio/android/Track.h +++ /dev/null @@ -1,107 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ - -#pragma once - -#include "audio/android/PcmData.h" -#include "audio/android/IVolumeProvider.h" -#include "audio/android/PcmBufferProvider.h" - -#include -#include - -namespace cocos2d { - -class Track : public PcmBufferProvider, public IVolumeProvider -{ -public: - enum class State - { - IDLE, - PLAYING, - RESUMED, - PAUSED, - STOPPED, - OVER, - DESTROYED - }; - - Track(const PcmData &pcmData); - virtual ~Track(); - - inline State getState() const { return _state; }; - void setState(State state); - - inline State getPrevState() const { return _prevState; }; - - inline bool isPlayOver() const { return _state == State::PLAYING && _nextFrame >= _numFrames;}; - inline void setName(int name) { _name = name; }; - inline int getName() const { return _name; }; - - void setVolume(float volume); - float getVolume() const; - - void setAudioFocus(bool isFocus); - - bool setPosition(float pos); - float getPosition() const; - - virtual gain_minifloat_packed_t getVolumeLR() override ; - - inline void setLoop(bool isLoop) { _isLoop = isLoop; }; - inline bool isLoop() const { return _isLoop; }; - - std::function onStateChanged; - -private: - inline bool isVolumeDirty() const - { return _isVolumeDirty; }; - - inline void setVolumeDirty(bool isDirty) - { _isVolumeDirty = isDirty; }; - - inline bool isInitialized() const - { return _isInitialized; }; - - inline void setInitialized(bool isInitialized) - { _isInitialized = isInitialized; }; - -private: - PcmData _pcmData; - State _prevState; - State _state; - std::mutex _stateMutex; - int _name; - float _volume; - bool _isVolumeDirty; - std::mutex _volumeDirtyMutex; - bool _isLoop; - bool _isInitialized; - bool _isAudioFocus; - - friend class AudioMixerController; -}; - -} // namespace cocos2d { diff --git a/cocos/audio/android/UrlAudioPlayer.cpp b/cocos/audio/android/UrlAudioPlayer.cpp deleted file mode 100644 index b05b0f4..0000000 --- a/cocos/audio/android/UrlAudioPlayer.cpp +++ /dev/null @@ -1,424 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ - -#define LOG_TAG "UrlAudioPlayer" - -#include "audio/android/UrlAudioPlayer.h" -#include "audio/android/ICallerThreadUtils.h" - -#include -#include // for std::find - -namespace { - -std::mutex __playerContainerMutex; -std::vector __playerContainer; -std::once_flag __onceFlag; - -} - -namespace cocos2d { - -class SLUrlAudioPlayerCallbackProxy -{ -public: - static void playEventCallback(SLPlayItf caller, void *context, SLuint32 playEvent) - { - UrlAudioPlayer *thiz = (UrlAudioPlayer *) context; - // We must use a mutex for the whole block of the following function invocation. - std::lock_guard lk(__playerContainerMutex); - auto iter = std::find(__playerContainer.begin(), __playerContainer.end(), thiz); - if (iter != __playerContainer.end()) - { - thiz->playEventCallback(caller, playEvent); - } - } -}; - -UrlAudioPlayer::UrlAudioPlayer(SLEngineItf engineItf, SLObjectItf outputMixObject, ICallerThreadUtils* callerThreadUtils) - : _engineItf(engineItf), _outputMixObj(outputMixObject), - _callerThreadUtils(callerThreadUtils), _id(-1), _assetFd(nullptr), - _playObj(nullptr), _playItf(nullptr), _seekItf(nullptr), _volumeItf(nullptr), - _volume(0.0f), _duration(0.0f), _isLoop(false), _isAudioFocus(true), _state(State::INVALID), - _playEventCallback(nullptr), _isDestroyed(std::make_shared(false)) -{ - std::call_once(__onceFlag, [](){ - __playerContainer.reserve(10); - }); - - __playerContainerMutex.lock(); - __playerContainer.push_back(this); - ALOGV("Current UrlAudioPlayer instance count: %d", (int)__playerContainer.size()); - __playerContainerMutex.unlock(); - - _callerThreadId = callerThreadUtils->getCallerThreadId(); -} - -UrlAudioPlayer::~UrlAudioPlayer() -{ - ALOGV("~UrlAudioPlayer(): %p", this); - - __playerContainerMutex.lock(); - - auto iter = std::find(__playerContainer.begin(), __playerContainer.end(), this); - if (iter != __playerContainer.end()) - { - __playerContainer.erase(iter); - } - - __playerContainerMutex.unlock(); -} - -void UrlAudioPlayer::playEventCallback(SLPlayItf caller, SLuint32 playEvent) -{ - // Note that it's on sub thread, please don't invoke OpenSLES API on sub thread - if (playEvent == SL_PLAYEVENT_HEADATEND) - { - std::shared_ptr isDestroyed = _isDestroyed; - - auto func = [this, isDestroyed](){ - // If it was destroyed, just return. - if (*isDestroyed) - { - ALOGV("The UrlAudioPlayer (%p) was destroyed!", this); - return; - } - - //Note that It's in the caller's thread (Cocos Thread) - // If state is already stopped, ignore the play over event. - - if (_state == State::STOPPED) - { - return; - } - - //fix issue#8965:AudioEngine can't looping audio on Android 2.3.x - if (isLoop()) - { - play(); - } - else - { - setState(State::OVER); - if (_playEventCallback != nullptr) - { - _playEventCallback(State::OVER); - } - - ALOGV("UrlAudioPlayer (%p) played over, destroy self ...", this); - destroy(); - delete this; - } - }; - - if (_callerThreadId == std::this_thread::get_id()) - { - func(); - } - else - { - _callerThreadUtils->performFunctionInCallerThread(func); - } - } -} - -void UrlAudioPlayer::setPlayEventCallback(const PlayEventCallback &playEventCallback) -{ - _playEventCallback = playEventCallback; -} - -void UrlAudioPlayer::stop() -{ - ALOGV("UrlAudioPlayer::stop (%p, %d)", this, getId()); - SLresult r = (*_playItf)->SetPlayState(_playItf, SL_PLAYSTATE_STOPPED); - SL_RETURN_IF_FAILED(r, "UrlAudioPlayer::stop failed"); - - if (_state == State::PLAYING || _state == State::PAUSED) - { - setLoop(false); - setState(State::STOPPED); - - if (_playEventCallback != nullptr) - { - _playEventCallback(State::STOPPED); - } - - destroy(); - delete this; - } - else - { - ALOGW("UrlAudioPlayer (%p, state:%d) isn't playing or paused, could not invoke stop!", this, static_cast(_state)); - } -} - -void UrlAudioPlayer::pause() -{ - if (_state == State::PLAYING) - { - SLresult r = (*_playItf)->SetPlayState(_playItf, SL_PLAYSTATE_PAUSED); - SL_RETURN_IF_FAILED(r, "UrlAudioPlayer::pause failed"); - setState(State::PAUSED); - } - else - { - ALOGW("UrlAudioPlayer (%p, state:%d) isn't playing, could not invoke pause!", this, static_cast(_state)); - } -} - -void UrlAudioPlayer::resume() -{ - if (_state == State::PAUSED) - { - SLresult r = (*_playItf)->SetPlayState(_playItf, SL_PLAYSTATE_PLAYING); - SL_RETURN_IF_FAILED(r, "UrlAudioPlayer::resume failed"); - setState(State::PLAYING); - } - else - { - ALOGW("UrlAudioPlayer (%p, state:%d) isn't paused, could not invoke resume!", this, static_cast(_state)); - } -} - -void UrlAudioPlayer::play() -{ - if (_state == State::INITIALIZED || _state == State::PAUSED) - { - SLresult r = (*_playItf)->SetPlayState(_playItf, SL_PLAYSTATE_PLAYING); - SL_RETURN_IF_FAILED(r, "UrlAudioPlayer::play failed"); - setState(State::PLAYING); - } - else - { - ALOGW("UrlAudioPlayer (%p, state:%d) isn't paused or initialized, could not invoke play!", this, static_cast(_state)); - } -} - -void UrlAudioPlayer::setVolumeToSLPlayer(float volume) -{ - int dbVolume = 2000 * log10(volume); - if (dbVolume < SL_MILLIBEL_MIN) - { - dbVolume = SL_MILLIBEL_MIN; - } - SLresult r = (*_volumeItf)->SetVolumeLevel(_volumeItf, dbVolume); - SL_RETURN_IF_FAILED(r, "UrlAudioPlayer::setVolumeToSLPlayer %d failed", dbVolume); -} - -void UrlAudioPlayer::setVolume(float volume) -{ - _volume = volume; - if (_isAudioFocus) - { - setVolumeToSLPlayer(_volume); - } -} - -float UrlAudioPlayer::getVolume() const -{ - return _volume; -} - -void UrlAudioPlayer::setAudioFocus(bool isFocus) -{ - _isAudioFocus = isFocus; - float volume = _isAudioFocus ? _volume : 0.0f; - setVolumeToSLPlayer(volume); -} - -float UrlAudioPlayer::getDuration() const -{ - if (_duration > 0) - { - return _duration; - } - - SLmillisecond duration; - SLresult r = (*_playItf)->GetDuration(_playItf, &duration); - SL_RETURN_VAL_IF_FAILED(r, 0.0f, "UrlAudioPlayer::getDuration failed"); - - if (duration == SL_TIME_UNKNOWN) - { - return -1.0f; - } - else - { - const_cast(this)->_duration = duration / 1000.0f; - - if (_duration <= 0) - { - return -1.0f; - } - } - return _duration; -} - -float UrlAudioPlayer::getPosition() const -{ - SLmillisecond millisecond; - SLresult r = (*_playItf)->GetPosition(_playItf, &millisecond); - SL_RETURN_VAL_IF_FAILED(r, 0.0f, "UrlAudioPlayer::getPosition failed"); - return millisecond / 1000.0f; -} - -bool UrlAudioPlayer::setPosition(float pos) -{ - SLmillisecond millisecond = 1000.0f * pos; - SLresult r = (*_seekItf)->SetPosition(_seekItf, millisecond, SL_SEEKMODE_ACCURATE); - SL_RETURN_VAL_IF_FAILED(r, false, "UrlAudioPlayer::setPosition %f failed", pos); - return true; -} - -bool UrlAudioPlayer::prepare(const std::string &url, SLuint32 locatorType, std::shared_ptr assetFd, int start, - int length) -{ - _url = url; - _assetFd = assetFd; - - const char* locatorTypeStr= "UNKNOWN"; - if (locatorType == SL_DATALOCATOR_ANDROIDFD) - locatorTypeStr = "SL_DATALOCATOR_ANDROIDFD"; - else if (locatorType == SL_DATALOCATOR_URI) - locatorTypeStr = "SL_DATALOCATOR_URI"; - else - { - ALOGE("Oops, invalid locatorType: %d", (int)locatorType); - return false; - } - - ALOGV("UrlAudioPlayer::prepare: %s, %s, %d, %d, %d", _url.c_str(), locatorTypeStr, _assetFd->getFd(), start, - length); - SLDataSource audioSrc; - - SLDataFormat_MIME formatMime = {SL_DATAFORMAT_MIME, nullptr, SL_CONTAINERTYPE_UNSPECIFIED}; - audioSrc.pFormat = &formatMime; - - //Note: locFd & locUri should be outside of the following if/else block - // Although locFd & locUri are only used inside if/else block, its lifecycle - // will be destroyed right after '}' block. And since we pass a pointer to - // 'audioSrc.pLocator=&locFd/&locUri', pLocator will point to an invalid address - // while invoking Engine::createAudioPlayer interface. So be care of change the position - // of these two variables. - SLDataLocator_AndroidFD locFd; - SLDataLocator_URI locUri; - - if (locatorType == SL_DATALOCATOR_ANDROIDFD) - { - locFd = {locatorType, _assetFd->getFd(), start, length}; - audioSrc.pLocator = &locFd; - } - else if (locatorType == SL_DATALOCATOR_URI) - { - locUri = {locatorType, (SLchar *) _url.c_str()}; - audioSrc.pLocator = &locUri; - ALOGV("locUri: locatorType: %d", (int)locUri.locatorType); - } - - // configure audio sink - SLDataLocator_OutputMix locOutmix = {SL_DATALOCATOR_OUTPUTMIX, _outputMixObj}; - SLDataSink audioSnk = {&locOutmix, nullptr}; - - // create audio player - const SLInterfaceID ids[3] = {SL_IID_SEEK, SL_IID_PREFETCHSTATUS, SL_IID_VOLUME}; - const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; - - SLresult result = (*_engineItf)->CreateAudioPlayer(_engineItf, &_playObj, &audioSrc, &audioSnk, - 3, ids, req); - SL_RETURN_VAL_IF_FAILED(result, false, "CreateAudioPlayer failed"); - - // realize the player - result = (*_playObj)->Realize(_playObj, SL_BOOLEAN_FALSE); - SL_RETURN_VAL_IF_FAILED(result, false, "Realize failed"); - - // get the play interface - result = (*_playObj)->GetInterface(_playObj, SL_IID_PLAY, &_playItf); - SL_RETURN_VAL_IF_FAILED(result, false, "GetInterface SL_IID_PLAY failed"); - - // get the seek interface - result = (*_playObj)->GetInterface(_playObj, SL_IID_SEEK, &_seekItf); - SL_RETURN_VAL_IF_FAILED(result, false, "GetInterface SL_IID_SEEK failed"); - - // get the volume interface - result = (*_playObj)->GetInterface(_playObj, SL_IID_VOLUME, &_volumeItf); - SL_RETURN_VAL_IF_FAILED(result, false, "GetInterface SL_IID_VOLUME failed"); - - result = (*_playItf)->RegisterCallback(_playItf, - SLUrlAudioPlayerCallbackProxy::playEventCallback, this); - SL_RETURN_VAL_IF_FAILED(result, false, "RegisterCallback failed"); - - result = (*_playItf)->SetCallbackEventsMask(_playItf, SL_PLAYEVENT_HEADATEND); - SL_RETURN_VAL_IF_FAILED(result, false, "SetCallbackEventsMask SL_PLAYEVENT_HEADATEND failed"); - - setState(State::INITIALIZED); - - setVolume(1.0f); - - return true; -} - -void UrlAudioPlayer::rewind() -{ -// Not supported currently. since cocos audio engine will new -> prepare -> play again. -} - -void UrlAudioPlayer::setLoop(bool isLoop) -{ - _isLoop = isLoop; - - SLboolean loopEnable = _isLoop ? SL_BOOLEAN_TRUE : SL_BOOLEAN_FALSE; - SLresult r = (*_seekItf)->SetLoop(_seekItf, loopEnable, 0, SL_TIME_UNKNOWN); - SL_RETURN_IF_FAILED(r, "UrlAudioPlayer::setLoop %d failed", _isLoop ? 1 : 0); -} - -bool UrlAudioPlayer::isLoop() const -{ - return _isLoop; -} - -void UrlAudioPlayer::stopAll() -{ - // To avoid break the for loop, we need to copy a new map - __playerContainerMutex.lock(); - auto temp = __playerContainer; - __playerContainerMutex.unlock(); - - for (auto&& player : temp) - { - player->stop(); - } -} - -void UrlAudioPlayer::destroy() -{ - if (!*_isDestroyed) - { - *_isDestroyed = true; - ALOGV("UrlAudioPlayer::destroy() %p", this); - SL_DESTROY_OBJ(_playObj); - ALOGV("UrlAudioPlayer::destroy end"); - } -} - -} // namespace cocos2d { diff --git a/cocos/audio/android/UrlAudioPlayer.h b/cocos/audio/android/UrlAudioPlayer.h deleted file mode 100644 index 22b4f4e..0000000 --- a/cocos/audio/android/UrlAudioPlayer.h +++ /dev/null @@ -1,135 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ - -#pragma once - -#include "audio/android/IAudioPlayer.h" -#include "audio/android/OpenSLHelper.h" -#include "audio/android/AssetFd.h" -#include -#include -#include -#include - -namespace cocos2d { - -class ICallerThreadUtils; -class AssetFd; - -class UrlAudioPlayer : public IAudioPlayer -{ -public: - - // Override Functions Begin - virtual int getId() const override - { return _id; }; - - virtual void setId(int id) override - { _id = id; }; - - virtual std::string getUrl() const override - { return _url; }; - - virtual State getState() const override - { return _state; }; - - virtual void play() override; - - virtual void pause() override; - - virtual void resume() override; - - virtual void stop() override; - - virtual void rewind() override; - - virtual void setVolume(float volume) override; - - virtual float getVolume() const override; - - virtual void setAudioFocus(bool isFocus) override; - - virtual void setLoop(bool isLoop) override; - - virtual bool isLoop() const override; - - virtual float getDuration() const override; - - virtual float getPosition() const override; - - virtual bool setPosition(float pos) override; - - virtual void setPlayEventCallback(const PlayEventCallback &playEventCallback) override; - - // Override Functions EndOv - -private: - UrlAudioPlayer(SLEngineItf engineItf, SLObjectItf outputMixObject, ICallerThreadUtils* callerThreadUtils); - virtual ~UrlAudioPlayer(); - - bool prepare(const std::string &url, SLuint32 locatorType, std::shared_ptr assetFd, int start, int length); - - static void stopAll(); - - void destroy(); - - inline void setState(State state) - { _state = state; }; - - void playEventCallback(SLPlayItf caller, SLuint32 playEvent); - - void setVolumeToSLPlayer(float volume); - -private: - SLEngineItf _engineItf; - SLObjectItf _outputMixObj; - ICallerThreadUtils* _callerThreadUtils; - - int _id; - std::string _url; - - std::shared_ptr _assetFd; - - SLObjectItf _playObj; - SLPlayItf _playItf; - SLSeekItf _seekItf; - SLVolumeItf _volumeItf; - - float _volume; - float _duration; - bool _isLoop; - bool _isAudioFocus; - State _state; - - PlayEventCallback _playEventCallback; - - std::thread::id _callerThreadId; - std::shared_ptr _isDestroyed; - - friend class SLUrlAudioPlayerCallbackProxy; - friend class AudioPlayerProvider; -}; - -} // namespace cocos2d { diff --git a/cocos/audio/android/audio.h b/cocos/audio/android/audio.h deleted file mode 100644 index a702214..0000000 --- a/cocos/audio/android/audio.h +++ /dev/null @@ -1,504 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ - -#pragma once - -// ---------------------------------------------------------------------------- - -#include -#include -#include "audio/android/cutils/bitops.h" - -#define PROPERTY_VALUE_MAX 256 -#define CONSTEXPR constexpr - - -#ifdef __cplusplus -# define CC_LIKELY( exp ) (__builtin_expect( !!(exp), true )) -# define CC_UNLIKELY( exp ) (__builtin_expect( !!(exp), false )) -#else -# define CC_LIKELY( exp ) (__builtin_expect( !!(exp), 1 )) -# define CC_UNLIKELY( exp ) (__builtin_expect( !!(exp), 0 )) -#endif - - -/* special audio session values - * (XXX: should this be living in the audio effects land?) - */ -typedef enum { - /* session for effects attached to a particular output stream - * (value must be less than 0) - */ - AUDIO_SESSION_OUTPUT_STAGE = -1, - - /* session for effects applied to output mix. These effects can - * be moved by audio policy manager to another output stream - * (value must be 0) - */ - AUDIO_SESSION_OUTPUT_MIX = 0, - - /* application does not specify an explicit session ID to be used, - * and requests a new session ID to be allocated - * TODO use unique values for AUDIO_SESSION_OUTPUT_MIX and AUDIO_SESSION_ALLOCATE, - * after all uses have been updated from 0 to the appropriate symbol, and have been tested. - */ - AUDIO_SESSION_ALLOCATE = 0, -} audio_session_t; - -/* Audio sub formats (see enum audio_format). */ - -/* PCM sub formats */ -typedef enum { - /* All of these are in native byte order */ - AUDIO_FORMAT_PCM_SUB_16_BIT = 0x1, /* DO NOT CHANGE - PCM signed 16 bits */ - AUDIO_FORMAT_PCM_SUB_8_BIT = 0x2, /* DO NOT CHANGE - PCM unsigned 8 bits */ - AUDIO_FORMAT_PCM_SUB_32_BIT = 0x3, /* PCM signed .31 fixed point */ - AUDIO_FORMAT_PCM_SUB_8_24_BIT = 0x4, /* PCM signed 8.23 fixed point */ - AUDIO_FORMAT_PCM_SUB_FLOAT = 0x5, /* PCM single-precision floating point */ - AUDIO_FORMAT_PCM_SUB_24_BIT_PACKED = 0x6, /* PCM signed .23 fixed point packed in 3 bytes */ -} audio_format_pcm_sub_fmt_t; - -/* The audio_format_*_sub_fmt_t declarations are not currently used */ - -/* MP3 sub format field definition : can use 11 LSBs in the same way as MP3 - * frame header to specify bit rate, stereo mode, version... - */ -typedef enum { - AUDIO_FORMAT_MP3_SUB_NONE = 0x0, -} audio_format_mp3_sub_fmt_t; - -/* AMR NB/WB sub format field definition: specify frame block interleaving, - * bandwidth efficient or octet aligned, encoding mode for recording... - */ -typedef enum { - AUDIO_FORMAT_AMR_SUB_NONE = 0x0, -} audio_format_amr_sub_fmt_t; - -/* AAC sub format field definition: specify profile or bitrate for recording... */ -typedef enum { - AUDIO_FORMAT_AAC_SUB_MAIN = 0x1, - AUDIO_FORMAT_AAC_SUB_LC = 0x2, - AUDIO_FORMAT_AAC_SUB_SSR = 0x4, - AUDIO_FORMAT_AAC_SUB_LTP = 0x8, - AUDIO_FORMAT_AAC_SUB_HE_V1 = 0x10, - AUDIO_FORMAT_AAC_SUB_SCALABLE = 0x20, - AUDIO_FORMAT_AAC_SUB_ERLC = 0x40, - AUDIO_FORMAT_AAC_SUB_LD = 0x80, - AUDIO_FORMAT_AAC_SUB_HE_V2 = 0x100, - AUDIO_FORMAT_AAC_SUB_ELD = 0x200, -} audio_format_aac_sub_fmt_t; - -/* VORBIS sub format field definition: specify quality for recording... */ -typedef enum { - AUDIO_FORMAT_VORBIS_SUB_NONE = 0x0, -} audio_format_vorbis_sub_fmt_t; - -/* Audio format consists of a main format field (upper 8 bits) and a sub format - * field (lower 24 bits). - * - * The main format indicates the main codec type. The sub format field - * indicates options and parameters for each format. The sub format is mainly - * used for record to indicate for instance the requested bitrate or profile. - * It can also be used for certain formats to give informations not present in - * the encoded audio stream (e.g. octet alignment for AMR). - */ -typedef enum { - AUDIO_FORMAT_INVALID = 0xFFFFFFFFUL, - AUDIO_FORMAT_DEFAULT = 0, - AUDIO_FORMAT_PCM = 0x00000000UL, /* DO NOT CHANGE */ - AUDIO_FORMAT_MP3 = 0x01000000UL, - AUDIO_FORMAT_AMR_NB = 0x02000000UL, - AUDIO_FORMAT_AMR_WB = 0x03000000UL, - AUDIO_FORMAT_AAC = 0x04000000UL, - AUDIO_FORMAT_HE_AAC_V1 = 0x05000000UL, /* Deprecated, Use AUDIO_FORMAT_AAC_HE_V1*/ - AUDIO_FORMAT_HE_AAC_V2 = 0x06000000UL, /* Deprecated, Use AUDIO_FORMAT_AAC_HE_V2*/ - AUDIO_FORMAT_VORBIS = 0x07000000UL, - AUDIO_FORMAT_OPUS = 0x08000000UL, - AUDIO_FORMAT_AC3 = 0x09000000UL, - AUDIO_FORMAT_E_AC3 = 0x0A000000UL, - AUDIO_FORMAT_DTS = 0x0B000000UL, - AUDIO_FORMAT_DTS_HD = 0x0C000000UL, - AUDIO_FORMAT_MAIN_MASK = 0xFF000000UL, - AUDIO_FORMAT_SUB_MASK = 0x00FFFFFFUL, - - /* Aliases */ - /* note != AudioFormat.ENCODING_PCM_16BIT */ - AUDIO_FORMAT_PCM_16_BIT = (AUDIO_FORMAT_PCM | - AUDIO_FORMAT_PCM_SUB_16_BIT), - /* note != AudioFormat.ENCODING_PCM_8BIT */ - AUDIO_FORMAT_PCM_8_BIT = (AUDIO_FORMAT_PCM | - AUDIO_FORMAT_PCM_SUB_8_BIT), - AUDIO_FORMAT_PCM_32_BIT = (AUDIO_FORMAT_PCM | - AUDIO_FORMAT_PCM_SUB_32_BIT), - AUDIO_FORMAT_PCM_8_24_BIT = (AUDIO_FORMAT_PCM | - AUDIO_FORMAT_PCM_SUB_8_24_BIT), - AUDIO_FORMAT_PCM_FLOAT = (AUDIO_FORMAT_PCM | - AUDIO_FORMAT_PCM_SUB_FLOAT), - AUDIO_FORMAT_PCM_24_BIT_PACKED = (AUDIO_FORMAT_PCM | - AUDIO_FORMAT_PCM_SUB_24_BIT_PACKED), - AUDIO_FORMAT_AAC_MAIN = (AUDIO_FORMAT_AAC | - AUDIO_FORMAT_AAC_SUB_MAIN), - AUDIO_FORMAT_AAC_LC = (AUDIO_FORMAT_AAC | - AUDIO_FORMAT_AAC_SUB_LC), - AUDIO_FORMAT_AAC_SSR = (AUDIO_FORMAT_AAC | - AUDIO_FORMAT_AAC_SUB_SSR), - AUDIO_FORMAT_AAC_LTP = (AUDIO_FORMAT_AAC | - AUDIO_FORMAT_AAC_SUB_LTP), - AUDIO_FORMAT_AAC_HE_V1 = (AUDIO_FORMAT_AAC | - AUDIO_FORMAT_AAC_SUB_HE_V1), - AUDIO_FORMAT_AAC_SCALABLE = (AUDIO_FORMAT_AAC | - AUDIO_FORMAT_AAC_SUB_SCALABLE), - AUDIO_FORMAT_AAC_ERLC = (AUDIO_FORMAT_AAC | - AUDIO_FORMAT_AAC_SUB_ERLC), - AUDIO_FORMAT_AAC_LD = (AUDIO_FORMAT_AAC | - AUDIO_FORMAT_AAC_SUB_LD), - AUDIO_FORMAT_AAC_HE_V2 = (AUDIO_FORMAT_AAC | - AUDIO_FORMAT_AAC_SUB_HE_V2), - AUDIO_FORMAT_AAC_ELD = (AUDIO_FORMAT_AAC | - AUDIO_FORMAT_AAC_SUB_ELD), -} audio_format_t; - -/* For the channel mask for position assignment representation */ -enum { -/* These can be a complete audio_channel_mask_t. */ - AUDIO_CHANNEL_NONE = 0x0, - AUDIO_CHANNEL_INVALID = 0xC0000000, -/* These can be the bits portion of an audio_channel_mask_t - * with representation AUDIO_CHANNEL_REPRESENTATION_POSITION. - * Using these bits as a complete audio_channel_mask_t is deprecated. - */ - /* output channels */ - AUDIO_CHANNEL_OUT_FRONT_LEFT = 0x1, - AUDIO_CHANNEL_OUT_FRONT_RIGHT = 0x2, - AUDIO_CHANNEL_OUT_FRONT_CENTER = 0x4, - AUDIO_CHANNEL_OUT_LOW_FREQUENCY = 0x8, - AUDIO_CHANNEL_OUT_BACK_LEFT = 0x10, - AUDIO_CHANNEL_OUT_BACK_RIGHT = 0x20, - AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x40, - AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x80, - AUDIO_CHANNEL_OUT_BACK_CENTER = 0x100, - AUDIO_CHANNEL_OUT_SIDE_LEFT = 0x200, - AUDIO_CHANNEL_OUT_SIDE_RIGHT = 0x400, - AUDIO_CHANNEL_OUT_TOP_CENTER = 0x800, - AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT = 0x1000, - AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER = 0x2000, - AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT = 0x4000, - AUDIO_CHANNEL_OUT_TOP_BACK_LEFT = 0x8000, - AUDIO_CHANNEL_OUT_TOP_BACK_CENTER = 0x10000, - AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT = 0x20000, -/* TODO: should these be considered complete channel masks, or only bits? */ - AUDIO_CHANNEL_OUT_MONO = AUDIO_CHANNEL_OUT_FRONT_LEFT, - AUDIO_CHANNEL_OUT_STEREO = (AUDIO_CHANNEL_OUT_FRONT_LEFT | - AUDIO_CHANNEL_OUT_FRONT_RIGHT), - AUDIO_CHANNEL_OUT_QUAD = (AUDIO_CHANNEL_OUT_FRONT_LEFT | - AUDIO_CHANNEL_OUT_FRONT_RIGHT | - AUDIO_CHANNEL_OUT_BACK_LEFT | - AUDIO_CHANNEL_OUT_BACK_RIGHT), - AUDIO_CHANNEL_OUT_QUAD_BACK = AUDIO_CHANNEL_OUT_QUAD, - /* like AUDIO_CHANNEL_OUT_QUAD_BACK with *_SIDE_* instead of *_BACK_* */ - AUDIO_CHANNEL_OUT_QUAD_SIDE = (AUDIO_CHANNEL_OUT_FRONT_LEFT | - AUDIO_CHANNEL_OUT_FRONT_RIGHT | - AUDIO_CHANNEL_OUT_SIDE_LEFT | - AUDIO_CHANNEL_OUT_SIDE_RIGHT), - AUDIO_CHANNEL_OUT_5POINT1 = (AUDIO_CHANNEL_OUT_FRONT_LEFT | - AUDIO_CHANNEL_OUT_FRONT_RIGHT | - AUDIO_CHANNEL_OUT_FRONT_CENTER | - AUDIO_CHANNEL_OUT_LOW_FREQUENCY | - AUDIO_CHANNEL_OUT_BACK_LEFT | - AUDIO_CHANNEL_OUT_BACK_RIGHT), - AUDIO_CHANNEL_OUT_5POINT1_BACK = AUDIO_CHANNEL_OUT_5POINT1, - /* like AUDIO_CHANNEL_OUT_5POINT1_BACK with *_SIDE_* instead of *_BACK_* */ - AUDIO_CHANNEL_OUT_5POINT1_SIDE = (AUDIO_CHANNEL_OUT_FRONT_LEFT | - AUDIO_CHANNEL_OUT_FRONT_RIGHT | - AUDIO_CHANNEL_OUT_FRONT_CENTER | - AUDIO_CHANNEL_OUT_LOW_FREQUENCY | - AUDIO_CHANNEL_OUT_SIDE_LEFT | - AUDIO_CHANNEL_OUT_SIDE_RIGHT), - // matches the correct AudioFormat.CHANNEL_OUT_7POINT1_SURROUND definition for 7.1 - AUDIO_CHANNEL_OUT_7POINT1 = (AUDIO_CHANNEL_OUT_FRONT_LEFT | - AUDIO_CHANNEL_OUT_FRONT_RIGHT | - AUDIO_CHANNEL_OUT_FRONT_CENTER | - AUDIO_CHANNEL_OUT_LOW_FREQUENCY | - AUDIO_CHANNEL_OUT_BACK_LEFT | - AUDIO_CHANNEL_OUT_BACK_RIGHT | - AUDIO_CHANNEL_OUT_SIDE_LEFT | - AUDIO_CHANNEL_OUT_SIDE_RIGHT), - AUDIO_CHANNEL_OUT_ALL = (AUDIO_CHANNEL_OUT_FRONT_LEFT | - AUDIO_CHANNEL_OUT_FRONT_RIGHT | - AUDIO_CHANNEL_OUT_FRONT_CENTER | - AUDIO_CHANNEL_OUT_LOW_FREQUENCY | - AUDIO_CHANNEL_OUT_BACK_LEFT | - AUDIO_CHANNEL_OUT_BACK_RIGHT | - AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER | - AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER | - AUDIO_CHANNEL_OUT_BACK_CENTER| - AUDIO_CHANNEL_OUT_SIDE_LEFT| - AUDIO_CHANNEL_OUT_SIDE_RIGHT| - AUDIO_CHANNEL_OUT_TOP_CENTER| - AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT| - AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER| - AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT| - AUDIO_CHANNEL_OUT_TOP_BACK_LEFT| - AUDIO_CHANNEL_OUT_TOP_BACK_CENTER| - AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT), -/* These are bits only, not complete values */ - /* input channels */ - AUDIO_CHANNEL_IN_LEFT = 0x4, - AUDIO_CHANNEL_IN_RIGHT = 0x8, - AUDIO_CHANNEL_IN_FRONT = 0x10, - AUDIO_CHANNEL_IN_BACK = 0x20, - AUDIO_CHANNEL_IN_LEFT_PROCESSED = 0x40, - AUDIO_CHANNEL_IN_RIGHT_PROCESSED = 0x80, - AUDIO_CHANNEL_IN_FRONT_PROCESSED = 0x100, - AUDIO_CHANNEL_IN_BACK_PROCESSED = 0x200, - AUDIO_CHANNEL_IN_PRESSURE = 0x400, - AUDIO_CHANNEL_IN_X_AXIS = 0x800, - AUDIO_CHANNEL_IN_Y_AXIS = 0x1000, - AUDIO_CHANNEL_IN_Z_AXIS = 0x2000, - AUDIO_CHANNEL_IN_VOICE_UPLINK = 0x4000, - AUDIO_CHANNEL_IN_VOICE_DNLINK = 0x8000, -/* TODO: should these be considered complete channel masks, or only bits, or deprecated? */ - AUDIO_CHANNEL_IN_MONO = AUDIO_CHANNEL_IN_FRONT, - AUDIO_CHANNEL_IN_STEREO = (AUDIO_CHANNEL_IN_LEFT | AUDIO_CHANNEL_IN_RIGHT), - AUDIO_CHANNEL_IN_FRONT_BACK = (AUDIO_CHANNEL_IN_FRONT | AUDIO_CHANNEL_IN_BACK), - AUDIO_CHANNEL_IN_ALL = (AUDIO_CHANNEL_IN_LEFT | - AUDIO_CHANNEL_IN_RIGHT | - AUDIO_CHANNEL_IN_FRONT | - AUDIO_CHANNEL_IN_BACK| - AUDIO_CHANNEL_IN_LEFT_PROCESSED | - AUDIO_CHANNEL_IN_RIGHT_PROCESSED | - AUDIO_CHANNEL_IN_FRONT_PROCESSED | - AUDIO_CHANNEL_IN_BACK_PROCESSED| - AUDIO_CHANNEL_IN_PRESSURE | - AUDIO_CHANNEL_IN_X_AXIS | - AUDIO_CHANNEL_IN_Y_AXIS | - AUDIO_CHANNEL_IN_Z_AXIS | - AUDIO_CHANNEL_IN_VOICE_UPLINK | - AUDIO_CHANNEL_IN_VOICE_DNLINK), -}; -/* A channel mask per se only defines the presence or absence of a channel, not the order. - * But see AUDIO_INTERLEAVE_* below for the platform convention of order. - * - * audio_channel_mask_t is an opaque type and its internal layout should not - * be assumed as it may change in the future. - * Instead, always use the functions declared in this header to examine. - * - * These are the current representations: - * - * AUDIO_CHANNEL_REPRESENTATION_POSITION - * is a channel mask representation for position assignment. - * Each low-order bit corresponds to the spatial position of a transducer (output), - * or interpretation of channel (input). - * The user of a channel mask needs to know the context of whether it is for output or input. - * The constants AUDIO_CHANNEL_OUT_* or AUDIO_CHANNEL_IN_* apply to the bits portion. - * It is not permitted for no bits to be set. - * - * AUDIO_CHANNEL_REPRESENTATION_INDEX - * is a channel mask representation for index assignment. - * Each low-order bit corresponds to a selected channel. - * There is no platform interpretation of the various bits. - * There is no concept of output or input. - * It is not permitted for no bits to be set. - * - * All other representations are reserved for future use. - * - * Warning: current representation distinguishes between input and output, but this will not the be - * case in future revisions of the platform. Wherever there is an ambiguity between input and output - * that is currently resolved by checking the channel mask, the implementer should look for ways to - * fix it with additional information outside of the mask. - */ -typedef uint32_t audio_channel_mask_t; - -/* Maximum number of channels for all representations */ -#define AUDIO_CHANNEL_COUNT_MAX 30 - -/* log(2) of maximum number of representations, not part of public API */ -#define AUDIO_CHANNEL_REPRESENTATION_LOG2 2 - -/* Representations */ -typedef enum { - AUDIO_CHANNEL_REPRESENTATION_POSITION = 0, // must be zero for compatibility - // 1 is reserved for future use - AUDIO_CHANNEL_REPRESENTATION_INDEX = 2, - // 3 is reserved for future use -} audio_channel_representation_t; - -/* The return value is undefined if the channel mask is invalid. */ -static inline uint32_t audio_channel_mask_get_bits(audio_channel_mask_t channel) -{ - return channel & ((1 << AUDIO_CHANNEL_COUNT_MAX) - 1); -} - -/* The return value is undefined if the channel mask is invalid. */ -static inline audio_channel_representation_t audio_channel_mask_get_representation( - audio_channel_mask_t channel) -{ - // The right shift should be sufficient, but also "and" for safety in case mask is not 32 bits - return (audio_channel_representation_t) - ((channel >> AUDIO_CHANNEL_COUNT_MAX) & ((1 << AUDIO_CHANNEL_REPRESENTATION_LOG2) - 1)); -} - -/* Returns the number of channels from an output channel mask, - * used in the context of audio output or playback. - * If a channel bit is set which could _not_ correspond to an output channel, - * it is excluded from the count. - * Returns zero if the representation is invalid. - */ -static inline uint32_t audio_channel_count_from_out_mask(audio_channel_mask_t channel) -{ - uint32_t bits = audio_channel_mask_get_bits(channel); - switch (audio_channel_mask_get_representation(channel)) { - case AUDIO_CHANNEL_REPRESENTATION_POSITION: - // TODO: We can now merge with from_in_mask and remove anding - bits &= AUDIO_CHANNEL_OUT_ALL; - // fall through - case AUDIO_CHANNEL_REPRESENTATION_INDEX: - return popcount(bits); - default: - return 0; - } -} - -static inline bool audio_is_valid_format(audio_format_t format) -{ - switch (format & AUDIO_FORMAT_MAIN_MASK) { - case AUDIO_FORMAT_PCM: - switch (format) { - case AUDIO_FORMAT_PCM_16_BIT: - case AUDIO_FORMAT_PCM_8_BIT: - case AUDIO_FORMAT_PCM_32_BIT: - case AUDIO_FORMAT_PCM_8_24_BIT: - case AUDIO_FORMAT_PCM_FLOAT: - case AUDIO_FORMAT_PCM_24_BIT_PACKED: - return true; - default: - return false; - } - /* not reached */ - case AUDIO_FORMAT_MP3: - case AUDIO_FORMAT_AMR_NB: - case AUDIO_FORMAT_AMR_WB: - case AUDIO_FORMAT_AAC: - case AUDIO_FORMAT_HE_AAC_V1: - case AUDIO_FORMAT_HE_AAC_V2: - case AUDIO_FORMAT_VORBIS: - case AUDIO_FORMAT_OPUS: - case AUDIO_FORMAT_AC3: - case AUDIO_FORMAT_E_AC3: - case AUDIO_FORMAT_DTS: - case AUDIO_FORMAT_DTS_HD: - return true; - default: - return false; - } -} - -static inline bool audio_is_linear_pcm(audio_format_t format) -{ - return ((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_PCM); -} - -static inline size_t audio_bytes_per_sample(audio_format_t format) -{ - size_t size = 0; - - switch (format) { - case AUDIO_FORMAT_PCM_32_BIT: - case AUDIO_FORMAT_PCM_8_24_BIT: - size = sizeof(int32_t); - break; - case AUDIO_FORMAT_PCM_24_BIT_PACKED: - size = sizeof(uint8_t) * 3; - break; - case AUDIO_FORMAT_PCM_16_BIT: - size = sizeof(int16_t); - break; - case AUDIO_FORMAT_PCM_8_BIT: - size = sizeof(uint8_t); - break; - case AUDIO_FORMAT_PCM_FLOAT: - size = sizeof(float); - break; - default: - break; - } - return size; -} - -/* Not part of public API */ -static inline audio_channel_mask_t audio_channel_mask_from_representation_and_bits( - audio_channel_representation_t representation, uint32_t bits) -{ - return (audio_channel_mask_t) ((representation << AUDIO_CHANNEL_COUNT_MAX) | bits); -} - -/* Derive an output channel mask for position assignment from a channel count. - * This is to be used when the content channel mask is unknown. The 1, 2, 4, 5, 6, 7 and 8 channel - * cases are mapped to the standard game/home-theater layouts, but note that 4 is mapped to quad, - * and not stereo + FC + mono surround. A channel count of 3 is arbitrarily mapped to stereo + FC - * for continuity with stereo. - * Returns the matching channel mask, - * or AUDIO_CHANNEL_NONE if the channel count is zero, - * or AUDIO_CHANNEL_INVALID if the channel count exceeds that of the - * configurations for which a default output channel mask is defined. - */ -static inline audio_channel_mask_t audio_channel_out_mask_from_count(uint32_t channel_count) -{ - uint32_t bits; - switch (channel_count) { - case 0: - return AUDIO_CHANNEL_NONE; - case 1: - bits = AUDIO_CHANNEL_OUT_MONO; - break; - case 2: - bits = AUDIO_CHANNEL_OUT_STEREO; - break; - case 3: - bits = AUDIO_CHANNEL_OUT_STEREO | AUDIO_CHANNEL_OUT_FRONT_CENTER; - break; - case 4: // 4.0 - bits = AUDIO_CHANNEL_OUT_QUAD; - break; - case 5: // 5.0 - bits = AUDIO_CHANNEL_OUT_QUAD | AUDIO_CHANNEL_OUT_FRONT_CENTER; - break; - case 6: // 5.1 - bits = AUDIO_CHANNEL_OUT_5POINT1; - break; - case 7: // 6.1 - bits = AUDIO_CHANNEL_OUT_5POINT1 | AUDIO_CHANNEL_OUT_BACK_CENTER; - break; - case 8: - bits = AUDIO_CHANNEL_OUT_7POINT1; - break; - // FIXME FCC_8 - default: - return AUDIO_CHANNEL_INVALID; - } - return audio_channel_mask_from_representation_and_bits( - AUDIO_CHANNEL_REPRESENTATION_POSITION, bits); -} - diff --git a/cocos/audio/android/audio_utils/format.c b/cocos/audio/android/audio_utils/format.c deleted file mode 100644 index 3c0b231..0000000 --- a/cocos/audio/android/audio_utils/format.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* #define LOG_NDEBUG 0 */ -#define LOG_TAG "audio_utils_format" - -#include "audio/android/cutils/log.h" -#include "audio/android/audio_utils/include/audio_utils/primitives.h" -#include "audio/android/audio_utils/include/audio_utils/format.h" -#include "audio/android/audio.h" - -void memcpy_by_audio_format(void *dst, audio_format_t dst_format, - const void *src, audio_format_t src_format, size_t count) -{ - /* default cases for error falls through to fatal log below. */ - if (dst_format == src_format) { - switch (dst_format) { - case AUDIO_FORMAT_PCM_16_BIT: - case AUDIO_FORMAT_PCM_FLOAT: - case AUDIO_FORMAT_PCM_8_BIT: - case AUDIO_FORMAT_PCM_24_BIT_PACKED: - case AUDIO_FORMAT_PCM_32_BIT: - case AUDIO_FORMAT_PCM_8_24_BIT: - memcpy(dst, src, count * audio_bytes_per_sample(dst_format)); - return; - default: - break; - } - } - switch (dst_format) { - case AUDIO_FORMAT_PCM_16_BIT: - switch (src_format) { - case AUDIO_FORMAT_PCM_FLOAT: - memcpy_to_i16_from_float((int16_t*)dst, (float*)src, count); - return; - case AUDIO_FORMAT_PCM_8_BIT: - memcpy_to_i16_from_u8((int16_t*)dst, (uint8_t*)src, count); - return; - case AUDIO_FORMAT_PCM_24_BIT_PACKED: - memcpy_to_i16_from_p24((int16_t*)dst, (uint8_t*)src, count); - return; - case AUDIO_FORMAT_PCM_32_BIT: - memcpy_to_i16_from_i32((int16_t*)dst, (int32_t*)src, count); - return; - case AUDIO_FORMAT_PCM_8_24_BIT: - memcpy_to_i16_from_q8_23((int16_t*)dst, (int32_t*)src, count); - return; - default: - break; - } - break; - case AUDIO_FORMAT_PCM_FLOAT: - switch (src_format) { - case AUDIO_FORMAT_PCM_16_BIT: - memcpy_to_float_from_i16((float*)dst, (int16_t*)src, count); - return; - case AUDIO_FORMAT_PCM_8_BIT: - memcpy_to_float_from_u8((float*)dst, (uint8_t*)src, count); - return; - case AUDIO_FORMAT_PCM_24_BIT_PACKED: - memcpy_to_float_from_p24((float*)dst, (uint8_t*)src, count); - return; - case AUDIO_FORMAT_PCM_32_BIT: - memcpy_to_float_from_i32((float*)dst, (int32_t*)src, count); - return; - case AUDIO_FORMAT_PCM_8_24_BIT: - memcpy_to_float_from_q8_23((float*)dst, (int32_t*)src, count); - return; - default: - break; - } - break; - case AUDIO_FORMAT_PCM_8_BIT: - switch (src_format) { - case AUDIO_FORMAT_PCM_16_BIT: - memcpy_to_u8_from_i16((uint8_t*)dst, (int16_t*)src, count); - return; - case AUDIO_FORMAT_PCM_FLOAT: - memcpy_to_u8_from_float((uint8_t*)dst, (float*)src, count); - return; - default: - break; - } - break; - case AUDIO_FORMAT_PCM_24_BIT_PACKED: - switch (src_format) { - case AUDIO_FORMAT_PCM_16_BIT: - memcpy_to_p24_from_i16((uint8_t*)dst, (int16_t*)src, count); - return; - case AUDIO_FORMAT_PCM_FLOAT: - memcpy_to_p24_from_float((uint8_t*)dst, (float*)src, count); - return; - default: - break; - } - break; - case AUDIO_FORMAT_PCM_32_BIT: - switch (src_format) { - case AUDIO_FORMAT_PCM_16_BIT: - memcpy_to_i32_from_i16((int32_t*)dst, (int16_t*)src, count); - return; - case AUDIO_FORMAT_PCM_FLOAT: - memcpy_to_i32_from_float((int32_t*)dst, (float*)src, count); - return; - default: - break; - } - break; - case AUDIO_FORMAT_PCM_8_24_BIT: - switch (src_format) { - case AUDIO_FORMAT_PCM_16_BIT: - memcpy_to_q8_23_from_i16((int32_t*)dst, (int16_t*)src, count); - return; - case AUDIO_FORMAT_PCM_FLOAT: - memcpy_to_q8_23_from_float_with_clamp((int32_t*)dst, (float*)src, count); - return; - case AUDIO_FORMAT_PCM_24_BIT_PACKED: { - memcpy_to_q8_23_from_p24((int32_t *)dst, (uint8_t *)src, count); - return; - } - default: - break; - } - break; - default: - break; - } - LOG_ALWAYS_FATAL("invalid src format %#x for dst format %#x", - src_format, dst_format); -} - -size_t memcpy_by_index_array_initialization_from_channel_mask(int8_t *idxary, size_t arysize, - audio_channel_mask_t dst_channel_mask, audio_channel_mask_t src_channel_mask) -{ - const audio_channel_representation_t src_representation = - audio_channel_mask_get_representation(src_channel_mask); - const audio_channel_representation_t dst_representation = - audio_channel_mask_get_representation(dst_channel_mask); - const uint32_t src_bits = audio_channel_mask_get_bits(src_channel_mask); - const uint32_t dst_bits = audio_channel_mask_get_bits(dst_channel_mask); - - switch (src_representation) { - case AUDIO_CHANNEL_REPRESENTATION_POSITION: - switch (dst_representation) { - case AUDIO_CHANNEL_REPRESENTATION_POSITION: - return memcpy_by_index_array_initialization(idxary, arysize, - dst_bits, src_bits); - case AUDIO_CHANNEL_REPRESENTATION_INDEX: - return memcpy_by_index_array_initialization_dst_index(idxary, arysize, - dst_bits, src_bits); - default: - return 0; - } - break; - case AUDIO_CHANNEL_REPRESENTATION_INDEX: - switch (dst_representation) { - case AUDIO_CHANNEL_REPRESENTATION_POSITION: - return memcpy_by_index_array_initialization_src_index(idxary, arysize, - dst_bits, src_bits); - case AUDIO_CHANNEL_REPRESENTATION_INDEX: - return memcpy_by_index_array_initialization(idxary, arysize, - dst_bits, src_bits); - default: - return 0; - } - break; - default: - return 0; - } -} diff --git a/cocos/audio/android/audio_utils/include/audio_utils/format.h b/cocos/audio/android/audio_utils/include/audio_utils/format.h deleted file mode 100644 index b39f4ae..0000000 --- a/cocos/audio/android/audio_utils/include/audio_utils/format.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef COCOS_AUDIO_FORMAT_H -#define COCOS_AUDIO_FORMAT_H - -#include -#include -#include "audio/android/audio.h" - -__BEGIN_DECLS - -/* Copy buffers with conversion between buffer sample formats. - * - * dst Destination buffer - * dst_format Destination buffer format - * src Source buffer - * src_format Source buffer format - * count Number of samples to copy - * - * Allowed format conversions are given by either case 1 or 2 below: - * - * 1) One of src_format or dst_format is AUDIO_FORMAT_PCM_16_BIT or - * AUDIO_FORMAT_PCM_FLOAT, and the other format type is one of: - * - * AUDIO_FORMAT_PCM_16_BIT - * AUDIO_FORMAT_PCM_FLOAT - * AUDIO_FORMAT_PCM_8_BIT - * AUDIO_FORMAT_PCM_24_BIT_PACKED - * AUDIO_FORMAT_PCM_32_BIT - * AUDIO_FORMAT_PCM_8_24_BIT - * - * 2) Both dst_format and src_format are identical and of the list given - * in (1). This is a straight copy. - * - * The destination and source buffers must be completely separate if the destination - * format size is larger than the source format size. These routines call functions - * in primitives.h, so descriptions of detailed behavior can be reviewed there. - * - * Logs a fatal error if dst or src format is not allowed by the conversion rules above. - */ -void memcpy_by_audio_format(void *dst, audio_format_t dst_format, - const void *src, audio_format_t src_format, size_t count); - - -/* This function creates an index array for converting audio data with different - * channel position and index masks, used by memcpy_by_index_array(). - * Returns the number of array elements required. - * This may be greater than idxcount, so the return value should be checked - * if idxary size is less than 32. Returns zero if the input masks are unrecognized. - * - * Note that idxary is a caller allocated array - * of at least as many channels as present in the dst_mask. - * - * Parameters: - * idxary Updated array of indices of channels in the src frame for the dst frame - * idxcount Number of caller allocated elements in idxary - * dst_mask Bit mask corresponding to destination channels present - * src_mask Bit mask corresponding to source channels present - */ -size_t memcpy_by_index_array_initialization_from_channel_mask(int8_t *idxary, size_t arysize, - audio_channel_mask_t dst_channel_mask, audio_channel_mask_t src_channel_mask); - -__END_DECLS - -#endif // COCOS_AUDIO_FORMAT_H diff --git a/cocos/audio/android/audio_utils/include/audio_utils/minifloat.h b/cocos/audio/android/audio_utils/include/audio_utils/minifloat.h deleted file mode 100644 index 26be8eb..0000000 --- a/cocos/audio/android/audio_utils/include/audio_utils/minifloat.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef COCOS_AUDIO_MINIFLOAT_H -#define COCOS_AUDIO_MINIFLOAT_H - -#include -#include - -__BEGIN_DECLS - -/* A single gain expressed as minifloat */ -typedef uint16_t gain_minifloat_t; - -/* A pair of gain_minifloat_t packed into a single word */ -typedef uint32_t gain_minifloat_packed_t; - -/* The nominal range of a gain, expressed as a float */ -#define GAIN_FLOAT_ZERO 0.0f -#define GAIN_FLOAT_UNITY 1.0f - -/* Unity gain expressed as a minifloat */ -#define GAIN_MINIFLOAT_UNITY 0xE000 - -/* Pack a pair of gain_mini_float_t into a combined gain_minifloat_packed_t */ -static inline gain_minifloat_packed_t gain_minifloat_pack(gain_minifloat_t left, - gain_minifloat_t right) -{ - return (right << 16) | left; -} - -/* Unpack a gain_minifloat_packed_t into the two gain_minifloat_t components */ -static inline gain_minifloat_t gain_minifloat_unpack_left(gain_minifloat_packed_t packed) -{ - return packed & 0xFFFF; -} - -static inline gain_minifloat_t gain_minifloat_unpack_right(gain_minifloat_packed_t packed) -{ - return packed >> 16; -} - -/* A pair of unity gains expressed as a gain_minifloat_packed_t */ -#define GAIN_MINIFLOAT_PACKED_UNITY gain_minifloat_pack(GAIN_MINIFLOAT_UNITY, GAIN_MINIFLOAT_UNITY) - -/* Convert a float to the internal representation used for gains. - * The nominal range [0.0, 1.0], but the hard range is [0.0, 2.0). - * Negative and underflow values are converted to 0.0, - * and values larger than the hard maximum are truncated to the hard maximum. - * - * Minifloats are ordered, and standard comparisons may be used between them - * in the gain_minifloat_t representation. - * - * Details on internal representation of gains, based on mini-floats: - * The nominal maximum is 1.0 and the hard maximum is 1 ULP less than 2.0, or +6 dB. - * The minimum non-zero value is approximately 1.9e-6 or -114 dB. - * Negative numbers, infinity, and NaN are not supported. - * There are 13 significand bits specified, 1 implied hidden bit, 3 exponent bits, - * and no sign bit. Denormals are supported. - */ -gain_minifloat_t gain_from_float(float f); - -/* Convert the internal representation used for gains to float */ -float float_from_gain(gain_minifloat_t gain); - -__END_DECLS - -#endif // COCOS_AUDIO_MINIFLOAT_H diff --git a/cocos/audio/android/audio_utils/include/audio_utils/primitives.h b/cocos/audio/android/audio_utils/include/audio_utils/primitives.h deleted file mode 100644 index 1421fd9..0000000 --- a/cocos/audio/android/audio_utils/include/audio_utils/primitives.h +++ /dev/null @@ -1,959 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef COCOS_AUDIO_PRIMITIVES_H -#define COCOS_AUDIO_PRIMITIVES_H - -#include -#include -#include - -__BEGIN_DECLS - -/* The memcpy_* conversion routines are designed to work in-place on same dst as src - * buffers only if the types shrink on copy, with the exception of memcpy_to_i16_from_u8(). - * This allows the loops to go upwards for faster cache access (and may be more flexible - * for future optimization later). - */ - -/** - * Dither and clamp pairs of 32-bit input samples (sums) to 16-bit output samples (out). - * Each 32-bit input sample can be viewed as a signed fixed-point Q19.12 of which the - * .12 fraction bits are dithered and the 19 integer bits are clamped to signed 16 bits. - * Alternatively the input can be viewed as Q4.27, of which the lowest .12 of the fraction - * is dithered and the remaining fraction is converted to the output Q.15, with clamping - * on the 4 integer guard bits. - * - * For interleaved stereo, c is the number of sample pairs, - * and out is an array of interleaved pairs of 16-bit samples per channel. - * For mono, c is the number of samples / 2, and out is an array of 16-bit samples. - * The name "dither" is a misnomer; the current implementation does not actually dither - * but uses truncation. This may change. - * The out and sums buffers must either be completely separate (non-overlapping), or - * they must both start at the same address. Partially overlapping buffers are not supported. - */ -void ditherAndClamp(int32_t* out, const int32_t *sums, size_t c); - -/* Expand and copy samples from unsigned 8-bit offset by 0x80 to signed 16-bit. - * Parameters: - * dst Destination buffer - * src Source buffer - * count Number of samples to copy - * The destination and source buffers must either be completely separate (non-overlapping), or - * they must both start at the same address. Partially overlapping buffers are not supported. - */ -void memcpy_to_i16_from_u8(int16_t *dst, const uint8_t *src, size_t count); - -/* Shrink and copy samples from signed 16-bit to unsigned 8-bit offset by 0x80. - * Parameters: - * dst Destination buffer - * src Source buffer - * count Number of samples to copy - * The destination and source buffers must either be completely separate (non-overlapping), or - * they must both start at the same address. Partially overlapping buffers are not supported. - * The conversion is done by truncation, without dithering, so it loses resolution. - */ -void memcpy_to_u8_from_i16(uint8_t *dst, const int16_t *src, size_t count); - -/* Copy samples from float to unsigned 8-bit offset by 0x80. - * Parameters: - * dst Destination buffer - * src Source buffer - * count Number of samples to copy - * The destination and source buffers must either be completely separate (non-overlapping), or - * they must both start at the same address. Partially overlapping buffers are not supported. - * The conversion is done by truncation, without dithering, so it loses resolution. - */ -void memcpy_to_u8_from_float(uint8_t *dst, const float *src, size_t count); - -/* Shrink and copy samples from signed 32-bit fixed-point Q0.31 to signed 16-bit Q0.15. - * Parameters: - * dst Destination buffer - * src Source buffer - * count Number of samples to copy - * The destination and source buffers must either be completely separate (non-overlapping), or - * they must both start at the same address. Partially overlapping buffers are not supported. - * The conversion is done by truncation, without dithering, so it loses resolution. - */ -void memcpy_to_i16_from_i32(int16_t *dst, const int32_t *src, size_t count); - -/* Shrink and copy samples from single-precision floating-point to signed 16-bit. - * Each float should be in the range -1.0 to 1.0. Values outside that range are clamped, - * refer to clamp16_from_float(). - * Parameters: - * dst Destination buffer - * src Source buffer - * count Number of samples to copy - * The destination and source buffers must either be completely separate (non-overlapping), or - * they must both start at the same address. Partially overlapping buffers are not supported. - * The conversion is done by truncation, without dithering, so it loses resolution. - */ -void memcpy_to_i16_from_float(int16_t *dst, const float *src, size_t count); - -/* Copy samples from signed fixed-point 32-bit Q4.27 to single-precision floating-point. - * The nominal output float range is [-1.0, 1.0] if the fixed-point range is - * [0xf8000000, 0x07ffffff]. The full float range is [-16.0, 16.0]. Note the closed range - * at 1.0 and 16.0 is due to rounding on conversion to float. See float_from_q4_27() for details. - * Parameters: - * dst Destination buffer - * src Source buffer - * count Number of samples to copy - * The destination and source buffers must either be completely separate (non-overlapping), or - * they must both start at the same address. Partially overlapping buffers are not supported. - */ -void memcpy_to_float_from_q4_27(float *dst, const int32_t *src, size_t count); - -/* Copy samples from signed fixed-point 16 bit Q0.15 to single-precision floating-point. - * The output float range is [-1.0, 1.0) for the fixed-point range [0x8000, 0x7fff]. - * No rounding is needed as the representation is exact. - * Parameters: - * dst Destination buffer - * src Source buffer - * count Number of samples to copy - * The destination and source buffers must be completely separate. - */ -void memcpy_to_float_from_i16(float *dst, const int16_t *src, size_t count); - -/* Copy samples from unsigned fixed-point 8 bit to single-precision floating-point. - * The output float range is [-1.0, 1.0) for the fixed-point range [0x00, 0xFF]. - * No rounding is needed as the representation is exact. - * Parameters: - * dst Destination buffer - * src Source buffer - * count Number of samples to copy - * The destination and source buffers must be completely separate. - */ -void memcpy_to_float_from_u8(float *dst, const uint8_t *src, size_t count); - -/* Copy samples from signed fixed-point packed 24 bit Q0.23 to single-precision floating-point. - * The packed 24 bit input is stored in native endian format in a uint8_t byte array. - * The output float range is [-1.0, 1.0) for the fixed-point range [0x800000, 0x7fffff]. - * No rounding is needed as the representation is exact. - * Parameters: - * dst Destination buffer - * src Source buffer - * count Number of samples to copy - * The destination and source buffers must be completely separate. - */ -void memcpy_to_float_from_p24(float *dst, const uint8_t *src, size_t count); - -/* Copy samples from signed fixed-point packed 24 bit Q0.23 to signed fixed point 16 bit Q0.15. - * The packed 24 bit output is stored in native endian format in a uint8_t byte array. - * The data is truncated without rounding. - * Parameters: - * dst Destination buffer - * src Source buffer - * count Number of samples to copy - * The destination and source buffers must either be completely separate (non-overlapping), or - * they must both start at the same address. Partially overlapping buffers are not supported. - */ -void memcpy_to_i16_from_p24(int16_t *dst, const uint8_t *src, size_t count); - -/* Copy samples from signed fixed-point packed 24 bit Q0.23 to signed fixed-point 32-bit Q0.31. - * The packed 24 bit input is stored in native endian format in a uint8_t byte array. - * The output data range is [0x80000000, 0x7fffff00] at intervals of 0x100. - * Parameters: - * dst Destination buffer - * src Source buffer - * count Number of samples to copy - * The destination and source buffers must be completely separate. - */ -void memcpy_to_i32_from_p24(int32_t *dst, const uint8_t *src, size_t count); - -/* Copy samples from signed fixed point 16 bit Q0.15 to signed fixed-point packed 24 bit Q0.23. - * The packed 24 bit output is assumed to be a native-endian uint8_t byte array. - * The output data range is [0x800000, 0x7fff00] (not full). - * Nevertheless there is no DC offset on the output, if the input has no DC offset. - * Parameters: - * dst Destination buffer - * src Source buffer - * count Number of samples to copy - * The destination and source buffers must be completely separate. - */ -void memcpy_to_p24_from_i16(uint8_t *dst, const int16_t *src, size_t count); - -/* Copy samples from single-precision floating-point to signed fixed-point packed 24 bit Q0.23. - * The packed 24 bit output is assumed to be a native-endian uint8_t byte array. - * The data is clamped and rounded to nearest, ties away from zero. See clamp24_from_float() - * for details. - * Parameters: - * dst Destination buffer - * src Source buffer - * count Number of samples to copy - * The destination and source buffers must either be completely separate (non-overlapping), or - * they must both start at the same address. Partially overlapping buffers are not supported. - */ -void memcpy_to_p24_from_float(uint8_t *dst, const float *src, size_t count); - -/* Copy samples from signed fixed-point 32-bit Q8.23 to signed fixed-point packed 24 bit Q0.23. - * The packed 24 bit output is assumed to be a native-endian uint8_t byte array. - * The data is clamped to the range is [0x800000, 0x7fffff]. - * Parameters: - * dst Destination buffer - * src Source buffer - * count Number of samples to copy - * The destination and source buffers must be completely separate. - */ -void memcpy_to_p24_from_q8_23(uint8_t *dst, const int32_t *src, size_t count); - -/* Shrink and copy samples from signed 32-bit fixed-point Q0.31 - * to signed fixed-point packed 24 bit Q0.23. - * The packed 24 bit output is assumed to be a native-endian uint8_t byte array. - * Parameters: - * dst Destination buffer - * src Source buffer - * count Number of samples to copy - * The destination and source buffers must either be completely separate (non-overlapping), or - * they must both start at the same address. Partially overlapping buffers are not supported. - * The conversion is done by truncation, without dithering, so it loses resolution. - */ -void memcpy_to_p24_from_i32(uint8_t *dst, const int32_t *src, size_t count); - -/* Copy samples from signed fixed point 16-bit Q0.15 to signed fixed-point 32-bit Q8.23. - * The output data range is [0xff800000, 0x007fff00] at intervals of 0x100. - * Parameters: - * dst Destination buffer - * src Source buffer - * count Number of samples to copy - * The destination and source buffers must be completely separate. - */ -void memcpy_to_q8_23_from_i16(int32_t *dst, const int16_t *src, size_t count); - -/* Copy samples from single-precision floating-point to signed fixed-point 32-bit Q8.23. - * This copy will clamp the Q8.23 representation to [0xff800000, 0x007fffff] even though there - * are guard bits available. Fractional lsb is rounded to nearest, ties away from zero. - * See clamp24_from_float() for details. - * Parameters: - * dst Destination buffer - * src Source buffer - * count Number of samples to copy - * The destination and source buffers must either be completely separate (non-overlapping), or - * they must both start at the same address. Partially overlapping buffers are not supported. - */ -void memcpy_to_q8_23_from_float_with_clamp(int32_t *dst, const float *src, size_t count); - -/* Copy samples from signed fixed point packed 24-bit Q0.23 to signed fixed-point 32-bit Q8.23. - * The output data range is [0xff800000, 0x007fffff]. - * Parameters: - * dst Destination buffer - * src Source buffer - * count Number of samples to copy - * The destination and source buffers must be completely separate. - */ -void memcpy_to_q8_23_from_p24(int32_t *dst, const uint8_t *src, size_t count); - -/* Copy samples from single-precision floating-point to signed fixed-point 32-bit Q4.27. - * The conversion will use the full available Q4.27 range, including guard bits. - * Fractional lsb is rounded to nearest, ties away from zero. - * See clampq4_27_from_float() for details. - * Parameters: - * dst Destination buffer - * src Source buffer - * count Number of samples to copy - * The destination and source buffers must either be completely separate (non-overlapping), or - * they must both start at the same address. Partially overlapping buffers are not supported. - */ -void memcpy_to_q4_27_from_float(int32_t *dst, const float *src, size_t count); - -/* Copy samples from signed fixed-point 32-bit Q8.23 to signed fixed point 16-bit Q0.15. - * The data is clamped, and truncated without rounding. - * Parameters: - * dst Destination buffer - * src Source buffer - * count Number of samples to copy - * The destination and source buffers must either be completely separate (non-overlapping), or - * they must both start at the same address. Partially overlapping buffers are not supported. - */ -void memcpy_to_i16_from_q8_23(int16_t *dst, const int32_t *src, size_t count); - -/* Copy samples from signed fixed-point 32-bit Q8.23 to single-precision floating-point. - * The nominal output float range is [-1.0, 1.0) for the fixed-point - * range [0xff800000, 0x007fffff]. The maximum output float range is [-256.0, 256.0). - * No rounding is needed as the representation is exact for nominal values. - * Rounding for overflow values is to nearest, ties to even. - * Parameters: - * dst Destination buffer - * src Source buffer - * count Number of samples to copy - * The destination and source buffers must either be completely separate (non-overlapping), or - * they must both start at the same address. Partially overlapping buffers are not supported. - */ -void memcpy_to_float_from_q8_23(float *dst, const int32_t *src, size_t count); - -/* Copy samples from signed fixed point 16-bit Q0.15 to signed fixed-point 32-bit Q0.31. - * The output data range is [0x80000000, 0x7fff0000] at intervals of 0x10000. - * Parameters: - * dst Destination buffer - * src Source buffer - * count Number of samples to copy - * The destination and source buffers must be completely separate. - */ -void memcpy_to_i32_from_i16(int32_t *dst, const int16_t *src, size_t count); - -/* Copy samples from single-precision floating-point to signed fixed-point 32-bit Q0.31. - * If rounding is needed on truncation, the fractional lsb is rounded to nearest, - * ties away from zero. See clamp32_from_float() for details. - * Parameters: - * dst Destination buffer - * src Source buffer - * count Number of samples to copy - * The destination and source buffers must either be completely separate (non-overlapping), or - * they must both start at the same address. Partially overlapping buffers are not supported. - */ -void memcpy_to_i32_from_float(int32_t *dst, const float *src, size_t count); - -/* Copy samples from signed fixed-point 32-bit Q0.31 to single-precision floating-point. - * The float range is [-1.0, 1.0] for the fixed-point range [0x80000000, 0x7fffffff]. - * Rounding is done according to float_from_i32(). - * Parameters: - * dst Destination buffer - * src Source buffer - * count Number of samples to copy - * The destination and source buffers must either be completely separate (non-overlapping), or - * they must both start at the same address. Partially overlapping buffers are not supported. - */ -void memcpy_to_float_from_i32(float *dst, const int32_t *src, size_t count); - -/* Downmix pairs of interleaved stereo input 16-bit samples to mono output 16-bit samples. - * Parameters: - * dst Destination buffer - * src Source buffer - * count Number of stereo frames to downmix - * The destination and source buffers must be completely separate (non-overlapping). - * The current implementation truncates the mean rather than dither, but this may change. - */ -void downmix_to_mono_i16_from_stereo_i16(int16_t *dst, const int16_t *src, size_t count); - -/* Upmix mono input 16-bit samples to pairs of interleaved stereo output 16-bit samples by - * duplicating. - * Parameters: - * dst Destination buffer - * src Source buffer - * count Number of mono samples to upmix - * The destination and source buffers must be completely separate (non-overlapping). - */ -void upmix_to_stereo_i16_from_mono_i16(int16_t *dst, const int16_t *src, size_t count); - -/* Downmix pairs of interleaved stereo input float samples to mono output float samples - * by averaging the stereo pair together. - * Parameters: - * dst Destination buffer - * src Source buffer - * count Number of stereo frames to downmix - * The destination and source buffers must be completely separate (non-overlapping), - * or they must both start at the same address. - */ -void downmix_to_mono_float_from_stereo_float(float *dst, const float *src, size_t count); - -/* Upmix mono input float samples to pairs of interleaved stereo output float samples by - * duplicating. - * Parameters: - * dst Destination buffer - * src Source buffer - * count Number of mono samples to upmix - * The destination and source buffers must be completely separate (non-overlapping). - */ -void upmix_to_stereo_float_from_mono_float(float *dst, const float *src, size_t count); - -/* Return the total number of non-zero 32-bit samples */ -size_t nonZeroMono32(const int32_t *samples, size_t count); - -/* Return the total number of non-zero 16-bit samples */ -size_t nonZeroMono16(const int16_t *samples, size_t count); - -/* Return the total number of non-zero stereo frames, where a frame is considered non-zero - * if either of its constituent 32-bit samples is non-zero - */ -size_t nonZeroStereo32(const int32_t *frames, size_t count); - -/* Return the total number of non-zero stereo frames, where a frame is considered non-zero - * if either of its constituent 16-bit samples is non-zero - */ -size_t nonZeroStereo16(const int16_t *frames, size_t count); - -/* Copy frames, selecting source samples based on a source channel mask to fit - * the destination channel mask. Unmatched channels in the destination channel mask - * are zero filled. Unmatched channels in the source channel mask are dropped. - * Channels present in the channel mask are represented by set bits in the - * uint32_t value and are matched without further interpretation. - * Parameters: - * dst Destination buffer - * dst_mask Bit mask corresponding to destination channels present - * src Source buffer - * src_mask Bit mask corresponding to source channels present - * sample_size Size of each sample in bytes. Must be 1, 2, 3, or 4. - * count Number of frames to copy - * The destination and source buffers must be completely separate (non-overlapping). - * If the sample size is not in range, the function will abort. - */ -void memcpy_by_channel_mask(void *dst, uint32_t dst_mask, - const void *src, uint32_t src_mask, size_t sample_size, size_t count); - -/* Copy frames, selecting source samples based on an index array (idxary). - * The idxary[] consists of dst_channels number of elements. - * The ith element if idxary[] corresponds the ith destination channel. - * A non-negative value is the channel index in the source frame. - * A negative index (-1) represents filling with 0. - * - * Example: Swapping L and R channels for stereo streams - * idxary[0] = 1; - * idxary[1] = 0; - * - * Example: Copying a mono source to the front center 5.1 channel - * idxary[0] = -1; - * idxary[1] = -1; - * idxary[2] = 0; - * idxary[3] = -1; - * idxary[4] = -1; - * idxary[5] = -1; - * - * This copy allows swizzling of channels or replication of channels. - * - * Parameters: - * dst Destination buffer - * dst_channels Number of destination channels per frame - * src Source buffer - * src_channels Number of source channels per frame - * idxary Array of indices representing channels in the source frame - * sample_size Size of each sample in bytes. Must be 1, 2, 3, or 4. - * count Number of frames to copy - * The destination and source buffers must be completely separate (non-overlapping). - * If the sample size is not in range, the function will abort. - */ -void memcpy_by_index_array(void *dst, uint32_t dst_channels, - const void *src, uint32_t src_channels, - const int8_t *idxary, size_t sample_size, size_t count); - -/* Prepares an index array (idxary) from channel masks, which can be later - * used by memcpy_by_index_array(). Returns the number of array elements required. - * This may be greater than idxcount, so the return value should be checked - * if idxary size is less than 32. Note that idxary is a caller allocated array - * of at least as many channels as present in the dst_mask. - * Channels present in the channel mask are represented by set bits in the - * uint32_t value and are matched without further interpretation. - * - * This function is typically used for converting audio data with different - * channel position masks. - * - * Parameters: - * idxary Updated array of indices of channels in the src frame for the dst frame - * idxcount Number of caller allocated elements in idxary - * dst_mask Bit mask corresponding to destination channels present - * src_mask Bit mask corresponding to source channels present - */ -size_t memcpy_by_index_array_initialization(int8_t *idxary, size_t idxcount, - uint32_t dst_mask, uint32_t src_mask); - -/* Prepares an index array (idxary) from channel masks, which can be later - * used by memcpy_by_index_array(). Returns the number of array elements required. - * - * For a source channel index mask, the source channels will map to the destination - * channels as if counting the set bits in dst_mask in order from lsb to msb - * (zero bits are ignored). The ith bit of the src_mask corresponds to the - * ith SET bit of dst_mask and the ith destination channel. Hence, a zero ith - * bit of the src_mask indicates that the ith destination channel plays silence. - * - * Parameters: - * idxary Updated array of indices of channels in the src frame for the dst frame - * idxcount Number of caller allocated elements in idxary - * dst_mask Bit mask corresponding to destination channels present - * src_mask Bit mask corresponding to source channels present - */ -size_t memcpy_by_index_array_initialization_src_index(int8_t *idxary, size_t idxcount, - uint32_t dst_mask, uint32_t src_mask); - -/* Prepares an index array (idxary) from channel mask bits, which can be later - * used by memcpy_by_index_array(). Returns the number of array elements required. - * - * This initialization is for a destination channel index mask from a positional - * source mask. - * - * For an destination channel index mask, the input channels will map - * to the destination channels, with the ith SET bit in the source bits corresponding - * to the ith bit in the destination bits. If there is a zero bit in the middle - * of set destination bits (unlikely), the corresponding source channel will - * be dropped. - * - * Parameters: - * idxary Updated array of indices of channels in the src frame for the dst frame - * idxcount Number of caller allocated elements in idxary - * dst_mask Bit mask corresponding to destination channels present - * src_mask Bit mask corresponding to source channels present - */ -size_t memcpy_by_index_array_initialization_dst_index(int8_t *idxary, size_t idxcount, - uint32_t dst_mask, uint32_t src_mask); - -/** - * Clamp (aka hard limit or clip) a signed 32-bit sample to 16-bit range. - */ -static inline int16_t clamp16(int32_t sample) -{ - if ((sample>>15) ^ (sample>>31)) - sample = 0x7FFF ^ (sample>>31); - return sample; -} - -/* - * Convert a IEEE 754 single precision float [-1.0, 1.0) to int16_t [-32768, 32767] - * with clamping. Note the open bound at 1.0, values within 1/65536 of 1.0 map - * to 32767 instead of 32768 (early clamping due to the smaller positive integer subrange). - * - * Values outside the range [-1.0, 1.0) are properly clamped to -32768 and 32767, - * including -Inf and +Inf. NaN will generally be treated either as -32768 or 32767, - * depending on the sign bit inside NaN (whose representation is not unique). - * Nevertheless, strictly speaking, NaN behavior should be considered undefined. - * - * Rounding of 0.5 lsb is to even (default for IEEE 754). - */ -static inline int16_t clamp16_from_float(float f) -{ - /* Offset is used to expand the valid range of [-1.0, 1.0) into the 16 lsbs of the - * floating point significand. The normal shift is 3<<22, but the -15 offset - * is used to multiply by 32768. - */ - static const float offset = (float)(3 << (22 - 15)); - /* zero = (0x10f << 22) = 0x43c00000 (not directly used) */ - static const int32_t limneg = (0x10f << 22) /*zero*/ - 32768; /* 0x43bf8000 */ - static const int32_t limpos = (0x10f << 22) /*zero*/ + 32767; /* 0x43c07fff */ - - union { - float f; - int32_t i; - } u; - - u.f = f + offset; /* recenter valid range */ - /* Now the valid range is represented as integers between [limneg, limpos]. - * Clamp using the fact that float representation (as an integer) is an ordered set. - */ - if (u.i < limneg) - u.i = -32768; - else if (u.i > limpos) - u.i = 32767; - return u.i; /* Return lower 16 bits, the part of interest in the significand. */ -} - -/* - * Convert a IEEE 754 single precision float [-1.0, 1.0) to uint8_t [0, 0xff] - * with clamping. Note the open bound at 1.0, values within 1/128 of 1.0 map - * to 255 instead of 256 (early clamping due to the smaller positive integer subrange). - * - * Values outside the range [-1.0, 1.0) are properly clamped to 0 and 255, - * including -Inf and +Inf. NaN will generally be treated either as 0 or 255, - * depending on the sign bit inside NaN (whose representation is not unique). - * Nevertheless, strictly speaking, NaN behavior should be considered undefined. - * - * Rounding of 0.5 lsb is to even (default for IEEE 754). - */ -static inline uint8_t clamp8_from_float(float f) -{ - /* Offset is used to expand the valid range of [-1.0, 1.0) into the 16 lsbs of the - * floating point significand. The normal shift is 3<<22, but the -7 offset - * is used to multiply by 128. - */ - static const float offset = (float)((3 << (22 - 7)) + 1 /* to cancel -1.0 */); - /* zero = (0x11f << 22) = 0x47c00000 */ - static const int32_t limneg = (0x11f << 22) /*zero*/; - static const int32_t limpos = (0x11f << 22) /*zero*/ + 255; /* 0x47c000ff */ - - union { - float f; - int32_t i; - } u; - - u.f = f + offset; /* recenter valid range */ - /* Now the valid range is represented as integers between [limneg, limpos]. - * Clamp using the fact that float representation (as an integer) is an ordered set. - */ - if (u.i < limneg) - return 0; - if (u.i > limpos) - return 255; - return u.i; /* Return lower 8 bits, the part of interest in the significand. */ -} - -/* Convert a single-precision floating point value to a Q0.23 integer value, stored in a - * 32 bit signed integer (technically stored as Q8.23, but clamped to Q0.23). - * - * Rounds to nearest, ties away from 0. - * - * Values outside the range [-1.0, 1.0) are properly clamped to -8388608 and 8388607, - * including -Inf and +Inf. NaN values are considered undefined, and behavior may change - * depending on hardware and future implementation of this function. - */ -static inline int32_t clamp24_from_float(float f) -{ - static const float scale = (float)(1 << 23); - static const float limpos = 0x7fffff / (float)(1 << 23); - static const float limneg = -0x800000 / (float)(1 << 23); - - if (f <= limneg) { - return -0x800000; - } else if (f >= limpos) { - return 0x7fffff; - } - f *= scale; - /* integer conversion is through truncation (though int to float is not). - * ensure that we round to nearest, ties away from 0. - */ - return f > 0 ? f + 0.5 : f - 0.5; -} - -/* Convert a signed fixed-point 32-bit Q8.23 value to a Q0.23 integer value, - * stored in a 32-bit signed integer (technically stored as Q8.23, but clamped to Q0.23). - * - * Values outside the range [-0x800000, 0x7fffff] are clamped to that range. - */ -static inline int32_t clamp24_from_q8_23(int32_t ival) -{ - static const int32_t limpos = 0x7fffff; - static const int32_t limneg = -0x800000; - if (ival < limneg) { - return limneg; - } else if (ival > limpos) { - return limpos; - } else { - return ival; - } -} - -/* Convert a single-precision floating point value to a Q4.27 integer value. - * Rounds to nearest, ties away from 0. - * - * Values outside the range [-16.0, 16.0) are properly clamped to -2147483648 and 2147483647, - * including -Inf and +Inf. NaN values are considered undefined, and behavior may change - * depending on hardware and future implementation of this function. - */ -static inline int32_t clampq4_27_from_float(float f) -{ - static const float scale = (float)(1UL << 27); - static const float limpos = 16.; - static const float limneg = -16.; - - if (f <= limneg) { - return -0x80000000; /* or 0x80000000 */ - } else if (f >= limpos) { - return 0x7fffffff; - } - f *= scale; - /* integer conversion is through truncation (though int to float is not). - * ensure that we round to nearest, ties away from 0. - */ - return f > 0 ? f + 0.5 : f - 0.5; -} - -/* Convert a single-precision floating point value to a Q0.31 integer value. - * Rounds to nearest, ties away from 0. - * - * Values outside the range [-1.0, 1.0) are properly clamped to -2147483648 and 2147483647, - * including -Inf and +Inf. NaN values are considered undefined, and behavior may change - * depending on hardware and future implementation of this function. - */ -static inline int32_t clamp32_from_float(float f) -{ - static const float scale = (float)(1UL << 31); - static const float limpos = 1.; - static const float limneg = -1.; - - if (f <= limneg) { - return -0x80000000; /* or 0x80000000 */ - } else if (f >= limpos) { - return 0x7fffffff; - } - f *= scale; - /* integer conversion is through truncation (though int to float is not). - * ensure that we round to nearest, ties away from 0. - */ - return f > 0 ? f + 0.5 : f - 0.5; -} - -/* Convert a signed fixed-point 32-bit Q4.27 value to single-precision floating-point. - * The nominal output float range is [-1.0, 1.0] if the fixed-point range is - * [0xf8000000, 0x07ffffff]. The full float range is [-16.0, 16.0]. - * - * Note the closed range at 1.0 and 16.0 is due to rounding on conversion to float. - * In more detail: if the fixed-point integer exceeds 24 bit significand of single - * precision floating point, the 0.5 lsb in the significand conversion will round - * towards even, as per IEEE 754 default. - */ -static inline float float_from_q4_27(int32_t ival) -{ - /* The scale factor is the reciprocal of the fractional bits. - * - * Since the scale factor is a power of 2, the scaling is exact, and there - * is no rounding due to the multiplication - the bit pattern is preserved. - * However, there may be rounding due to the fixed-point to float conversion, - * as described above. - */ - static const float scale = 1. / (float)(1UL << 27); - - return ival * scale; -} - -/* Convert an unsigned fixed-point 32-bit U4.28 value to single-precision floating-point. - * The nominal output float range is [0.0, 1.0] if the fixed-point range is - * [0x00000000, 0x10000000]. The full float range is [0.0, 16.0]. - * - * Note the closed range at 1.0 and 16.0 is due to rounding on conversion to float. - * In more detail: if the fixed-point integer exceeds 24 bit significand of single - * precision floating point, the 0.5 lsb in the significand conversion will round - * towards even, as per IEEE 754 default. - */ -static inline float float_from_u4_28(uint32_t uval) -{ - static const float scale = 1. / (float)(1UL << 28); - - return uval * scale; -} - -/* Convert an unsigned fixed-point 16-bit U4.12 value to single-precision floating-point. - * The nominal output float range is [0.0, 1.0] if the fixed-point range is - * [0x0000, 0x1000]. The full float range is [0.0, 16.0). - */ -static inline float float_from_u4_12(uint16_t uval) -{ - static const float scale = 1. / (float)(1UL << 12); - - return uval * scale; -} - -/* Convert a single-precision floating point value to a U4.28 integer value. - * Rounds to nearest, ties away from 0. - * - * Values outside the range [0, 16.0] are properly clamped to [0, 4294967295] - * including -Inf and +Inf. NaN values are considered undefined, and behavior may change - * depending on hardware and future implementation of this function. - */ -static inline uint32_t u4_28_from_float(float f) -{ - static const float scale = (float)(1 << 28); - static const float limpos = 0xffffffffUL / (float)(1 << 28); - - if (f <= 0.) { - return 0; - } else if (f >= limpos) { - return 0xffffffff; - } - /* integer conversion is through truncation (though int to float is not). - * ensure that we round to nearest, ties away from 0. - */ - return f * scale + 0.5; -} - -/* Convert a single-precision floating point value to a U4.12 integer value. - * Rounds to nearest, ties away from 0. - * - * Values outside the range [0, 16.0) are properly clamped to [0, 65535] - * including -Inf and +Inf. NaN values are considered undefined, and behavior may change - * depending on hardware and future implementation of this function. - */ -static inline uint16_t u4_12_from_float(float f) -{ - static const float scale = (float)(1 << 12); - static const float limpos = 0xffff / (float)(1 << 12); - - if (f <= 0.) { - return 0; - } else if (f >= limpos) { - return 0xffff; - } - /* integer conversion is through truncation (though int to float is not). - * ensure that we round to nearest, ties away from 0. - */ - return f * scale + 0.5; -} - -/* Convert a signed fixed-point 16-bit Q0.15 value to single-precision floating-point. - * The output float range is [-1.0, 1.0) for the fixed-point range - * [0x8000, 0x7fff]. - * - * There is no rounding, the conversion and representation is exact. - */ -static inline float float_from_i16(int16_t ival) -{ - /* The scale factor is the reciprocal of the nominal 16 bit integer - * half-sided range (32768). - * - * Since the scale factor is a power of 2, the scaling is exact, and there - * is no rounding due to the multiplication - the bit pattern is preserved. - */ - static const float scale = 1. / (float)(1UL << 15); - - return ival * scale; -} - -/* Convert an unsigned fixed-point 8-bit U0.8 value to single-precision floating-point. - * The nominal output float range is [-1.0, 1.0) if the fixed-point range is - * [0x00, 0xff]. - */ -static inline float float_from_u8(uint8_t uval) -{ - static const float scale = 1. / (float)(1UL << 7); - - return ((int)uval - 128) * scale; -} - -/* Convert a packed 24bit Q0.23 value stored native-endian in a uint8_t ptr - * to a signed fixed-point 32 bit integer Q0.31 value. The output Q0.31 range - * is [0x80000000, 0x7fffff00] for the fixed-point range [0x800000, 0x7fffff]. - * Even though the output range is limited on the positive side, there is no - * DC offset on the output, if the input has no DC offset. - * - * Avoid relying on the limited output range, as future implementations may go - * to full range. - */ -static inline int32_t i32_from_p24(const uint8_t *packed24) -{ - /* convert to 32b */ - return (packed24[0] << 8) | (packed24[1] << 16) | (packed24[2] << 24); -} - -/* Convert a 32-bit Q0.31 value to single-precision floating-point. - * The output float range is [-1.0, 1.0] for the fixed-point range - * [0x80000000, 0x7fffffff]. - * - * Rounding may occur in the least significant 8 bits for large fixed point - * values due to storage into the 24-bit floating-point significand. - * Rounding will be to nearest, ties to even. - */ -static inline float float_from_i32(int32_t ival) -{ - static const float scale = 1. / (float)(1UL << 31); - - return ival * scale; -} - -/* Convert a packed 24bit Q0.23 value stored native endian in a uint8_t ptr - * to single-precision floating-point. The output float range is [-1.0, 1.0) - * for the fixed-point range [0x800000, 0x7fffff]. - * - * There is no rounding, the conversion and representation is exact. - */ -static inline float float_from_p24(const uint8_t *packed24) -{ - return float_from_i32(i32_from_p24(packed24)); -} - -/* Convert a 24-bit Q8.23 value to single-precision floating-point. - * The nominal output float range is [-1.0, 1.0) for the fixed-point - * range [0xff800000, 0x007fffff]. The maximum float range is [-256.0, 256.0). - * - * There is no rounding in the nominal range, the conversion and representation - * is exact. For values outside the nominal range, rounding is to nearest, ties to even. - */ -static inline float float_from_q8_23(int32_t ival) -{ - static const float scale = 1. / (float)(1UL << 23); - - return ival * scale; -} - -/** - * Multiply-accumulate 16-bit terms with 32-bit result: return a + in*v. - */ -static inline -int32_t mulAdd(int16_t in, int16_t v, int32_t a) -{ -#if defined(__arm__) && !defined(__thumb__) - int32_t out; - asm( "smlabb %[out], %[in], %[v], %[a] \n" - : [out]"=r"(out) - : [in]"%r"(in), [v]"r"(v), [a]"r"(a) - : ); - return out; -#else - return a + in * (int32_t)v; -#endif -} - -/** - * Multiply 16-bit terms with 32-bit result: return in*v. - */ -static inline -int32_t mul(int16_t in, int16_t v) -{ -#if defined(__arm__) && !defined(__thumb__) - int32_t out; - asm( "smulbb %[out], %[in], %[v] \n" - : [out]"=r"(out) - : [in]"%r"(in), [v]"r"(v) - : ); - return out; -#else - return in * (int32_t)v; -#endif -} - -/** - * Similar to mulAdd, but the 16-bit terms are extracted from a 32-bit interleaved stereo pair. - */ -static inline -int32_t mulAddRL(int left, uint32_t inRL, uint32_t vRL, int32_t a) -{ -#if defined(__arm__) && !defined(__thumb__) - int32_t out; - if (left) { - asm( "smlabb %[out], %[inRL], %[vRL], %[a] \n" - : [out]"=r"(out) - : [inRL]"%r"(inRL), [vRL]"r"(vRL), [a]"r"(a) - : ); - } else { - asm( "smlatt %[out], %[inRL], %[vRL], %[a] \n" - : [out]"=r"(out) - : [inRL]"%r"(inRL), [vRL]"r"(vRL), [a]"r"(a) - : ); - } - return out; -#else - if (left) { - return a + (int16_t)(inRL&0xFFFF) * (int16_t)(vRL&0xFFFF); - } else { - return a + (int16_t)(inRL>>16) * (int16_t)(vRL>>16); - } -#endif -} - -/** - * Similar to mul, but the 16-bit terms are extracted from a 32-bit interleaved stereo pair. - */ -static inline -int32_t mulRL(int left, uint32_t inRL, uint32_t vRL) -{ -#if defined(__arm__) && !defined(__thumb__) - int32_t out; - if (left) { - asm( "smulbb %[out], %[inRL], %[vRL] \n" - : [out]"=r"(out) - : [inRL]"%r"(inRL), [vRL]"r"(vRL) - : ); - } else { - asm( "smultt %[out], %[inRL], %[vRL] \n" - : [out]"=r"(out) - : [inRL]"%r"(inRL), [vRL]"r"(vRL) - : ); - } - return out; -#else - if (left) { - return (int16_t)(inRL&0xFFFF) * (int16_t)(vRL&0xFFFF); - } else { - return (int16_t)(inRL>>16) * (int16_t)(vRL>>16); - } -#endif -} - -__END_DECLS - -#endif // COCOS_AUDIO_PRIMITIVES_H diff --git a/cocos/audio/android/audio_utils/minifloat.cpp b/cocos/audio/android/audio_utils/minifloat.cpp deleted file mode 100644 index 81fa18d..0000000 --- a/cocos/audio/android/audio_utils/minifloat.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include "audio/android/audio_utils/include/audio_utils/minifloat.h" - -#define EXPONENT_BITS 3 -#define EXPONENT_MAX ((1 << EXPONENT_BITS) - 1) -#define EXCESS ((1 << EXPONENT_BITS) - 2) - -#define MANTISSA_BITS 13 -#define MANTISSA_MAX ((1 << MANTISSA_BITS) - 1) -#define HIDDEN_BIT (1 << MANTISSA_BITS) -#define ONE_FLOAT ((float) (1 << (MANTISSA_BITS + 1))) - -#define MINIFLOAT_MAX ((EXPONENT_MAX << MANTISSA_BITS) | MANTISSA_MAX) - -#if EXPONENT_BITS + MANTISSA_BITS != 16 -#error EXPONENT_BITS and MANTISSA_BITS must sum to 16 -#endif - -extern "C" { - -gain_minifloat_t gain_from_float(float v) -{ - if (std::isnan(v) || v <= 0.0f) - { - return 0; - } - if (v >= 2.0f) - { - return MINIFLOAT_MAX; - } - int exp; - float r = frexpf(v, &exp); - if ((exp += EXCESS) > EXPONENT_MAX) - { - return MINIFLOAT_MAX; - } - if (-exp >= MANTISSA_BITS) - { - return 0; - } - int mantissa = (int) (r * ONE_FLOAT); - return exp > 0 ? (exp << MANTISSA_BITS) | (mantissa & ~HIDDEN_BIT) : - (mantissa >> (1 - exp)) & MANTISSA_MAX; -} - -float float_from_gain(gain_minifloat_t a) -{ - int mantissa = a & MANTISSA_MAX; - int exponent = (a >> MANTISSA_BITS) & EXPONENT_MAX; - return ldexpf((exponent > 0 ? HIDDEN_BIT | mantissa : mantissa << 1) / ONE_FLOAT, - exponent - EXCESS); -} - -} // extern "C" { diff --git a/cocos/audio/android/audio_utils/primitives.c b/cocos/audio/android/audio_utils/primitives.c deleted file mode 100644 index 269c20e..0000000 --- a/cocos/audio/android/audio_utils/primitives.c +++ /dev/null @@ -1,526 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "audio/android/cutils/bitops.h" /* for popcount() */ -#include "audio/android/audio_utils/include/audio_utils/primitives.h" -#include "audio/android/audio_utils/private/private.h" - -void ditherAndClamp(int32_t* out, const int32_t *sums, size_t c) -{ - size_t i; - for (i=0 ; i> 12; - int32_t nr = r >> 12; - l = clamp16(nl); - r = clamp16(nr); - *out++ = (r<<16) | (l & 0xFFFF); - } -} - -void memcpy_to_i16_from_u8(int16_t *dst, const uint8_t *src, size_t count) -{ - dst += count; - src += count; - while (count--) { - *--dst = (int16_t)(*--src - 0x80) << 8; - } -} - -void memcpy_to_u8_from_i16(uint8_t *dst, const int16_t *src, size_t count) -{ - while (count--) { - *dst++ = (*src++ >> 8) + 0x80; - } -} - -void memcpy_to_u8_from_float(uint8_t *dst, const float *src, size_t count) -{ - while (count--) { - *dst++ = clamp8_from_float(*src++); - } -} - -void memcpy_to_i16_from_i32(int16_t *dst, const int32_t *src, size_t count) -{ - while (count--) { - *dst++ = *src++ >> 16; - } -} - -void memcpy_to_i16_from_float(int16_t *dst, const float *src, size_t count) -{ - while (count--) { - *dst++ = clamp16_from_float(*src++); - } -} - -void memcpy_to_float_from_q4_27(float *dst, const int32_t *src, size_t count) -{ - while (count--) { - *dst++ = float_from_q4_27(*src++); - } -} - -void memcpy_to_float_from_i16(float *dst, const int16_t *src, size_t count) -{ - while (count--) { - *dst++ = float_from_i16(*src++); - } -} - -void memcpy_to_float_from_u8(float *dst, const uint8_t *src, size_t count) -{ - while (count--) { - *dst++ = float_from_u8(*src++); - } -} - -void memcpy_to_float_from_p24(float *dst, const uint8_t *src, size_t count) -{ - while (count--) { - *dst++ = float_from_p24(src); - src += 3; - } -} - -void memcpy_to_i16_from_p24(int16_t *dst, const uint8_t *src, size_t count) -{ - while (count--) { -#ifdef HAVE_BIG_ENDIAN - *dst++ = src[1] | (src[0] << 8); -#else - *dst++ = src[1] | (src[2] << 8); -#endif - src += 3; - } -} - -void memcpy_to_i32_from_p24(int32_t *dst, const uint8_t *src, size_t count) -{ - while (count--) { -#ifdef HAVE_BIG_ENDIAN - *dst++ = (src[2] << 8) | (src[1] << 16) | (src[0] << 24); -#else - *dst++ = (src[0] << 8) | (src[1] << 16) | (src[2] << 24); -#endif - src += 3; - } -} - -void memcpy_to_p24_from_i16(uint8_t *dst, const int16_t *src, size_t count) -{ - while (count--) { -#ifdef HAVE_BIG_ENDIAN - *dst++ = *src >> 8; - *dst++ = *src++; - *dst++ = 0; -#else - *dst++ = 0; - *dst++ = *src; - *dst++ = *src++ >> 8; -#endif - } -} - -void memcpy_to_p24_from_float(uint8_t *dst, const float *src, size_t count) -{ - while (count--) { - int32_t ival = clamp24_from_float(*src++); - -#ifdef HAVE_BIG_ENDIAN - *dst++ = ival >> 16; - *dst++ = ival >> 8; - *dst++ = ival; -#else - *dst++ = ival; - *dst++ = ival >> 8; - *dst++ = ival >> 16; -#endif - } -} - -void memcpy_to_p24_from_q8_23(uint8_t *dst, const int32_t *src, size_t count) -{ - while (count--) { - int32_t ival = clamp24_from_q8_23(*src++); - -#ifdef HAVE_BIG_ENDIAN - *dst++ = ival >> 16; - *dst++ = ival >> 8; - *dst++ = ival; -#else - *dst++ = ival; - *dst++ = ival >> 8; - *dst++ = ival >> 16; -#endif - } -} - -void memcpy_to_p24_from_i32(uint8_t *dst, const int32_t *src, size_t count) -{ - while (count--) { - int32_t ival = *src++ >> 8; - -#ifdef HAVE_BIG_ENDIAN - *dst++ = ival >> 16; - *dst++ = ival >> 8; - *dst++ = ival; -#else - *dst++ = ival; - *dst++ = ival >> 8; - *dst++ = ival >> 16; -#endif - } -} - -void memcpy_to_q8_23_from_i16(int32_t *dst, const int16_t *src, size_t count) -{ - while (count--) { - *dst++ = (int32_t)*src++ << 8; - } -} - -void memcpy_to_q8_23_from_float_with_clamp(int32_t *dst, const float *src, size_t count) -{ - while (count--) { - *dst++ = clamp24_from_float(*src++); - } -} - -void memcpy_to_q8_23_from_p24(int32_t *dst, const uint8_t *src, size_t count) -{ - while (count--) { -#ifdef HAVE_BIG_ENDIAN - *dst++ = (int8_t)src[0] << 16 | src[1] << 8 | src[2]; -#else - *dst++ = (int8_t)src[2] << 16 | src[1] << 8 | src[0]; -#endif - src += 3; - } -} - -void memcpy_to_q4_27_from_float(int32_t *dst, const float *src, size_t count) -{ - while (count--) { - *dst++ = clampq4_27_from_float(*src++); - } -} - -void memcpy_to_i16_from_q8_23(int16_t *dst, const int32_t *src, size_t count) -{ - while (count--) { - *dst++ = clamp16(*src++ >> 8); - } -} - -void memcpy_to_float_from_q8_23(float *dst, const int32_t *src, size_t count) -{ - while (count--) { - *dst++ = float_from_q8_23(*src++); - } -} - -void memcpy_to_i32_from_i16(int32_t *dst, const int16_t *src, size_t count) -{ - while (count--) { - *dst++ = (int32_t)*src++ << 16; - } -} - -void memcpy_to_i32_from_float(int32_t *dst, const float *src, size_t count) -{ - while (count--) { - *dst++ = clamp32_from_float(*src++); - } -} - -void memcpy_to_float_from_i32(float *dst, const int32_t *src, size_t count) -{ - while (count--) { - *dst++ = float_from_i32(*src++); - } -} - -void downmix_to_mono_i16_from_stereo_i16(int16_t *dst, const int16_t *src, size_t count) -{ - while (count--) { - *dst++ = (int16_t)(((int32_t)src[0] + (int32_t)src[1]) >> 1); - src += 2; - } -} - -void upmix_to_stereo_i16_from_mono_i16(int16_t *dst, const int16_t *src, size_t count) -{ - while (count--) { - int32_t temp = *src++; - dst[0] = temp; - dst[1] = temp; - dst += 2; - } -} - -void downmix_to_mono_float_from_stereo_float(float *dst, const float *src, size_t frames) -{ - while (frames--) { - *dst++ = (src[0] + src[1]) * 0.5; - src += 2; - } -} - -void upmix_to_stereo_float_from_mono_float(float *dst, const float *src, size_t frames) -{ - while (frames--) { - float temp = *src++; - dst[0] = temp; - dst[1] = temp; - dst += 2; - } -} - -size_t nonZeroMono32(const int32_t *samples, size_t count) -{ - size_t nonZero = 0; - while (count-- > 0) { - if (*samples++ != 0) { - nonZero++; - } - } - return nonZero; -} - -size_t nonZeroMono16(const int16_t *samples, size_t count) -{ - size_t nonZero = 0; - while (count-- > 0) { - if (*samples++ != 0) { - nonZero++; - } - } - return nonZero; -} - -size_t nonZeroStereo32(const int32_t *frames, size_t count) -{ - size_t nonZero = 0; - while (count-- > 0) { - if (frames[0] != 0 || frames[1] != 0) { - nonZero++; - } - frames += 2; - } - return nonZero; -} - -size_t nonZeroStereo16(const int16_t *frames, size_t count) -{ - size_t nonZero = 0; - while (count-- > 0) { - if (frames[0] != 0 || frames[1] != 0) { - nonZero++; - } - frames += 2; - } - return nonZero; -} - -/* - * C macro to do channel mask copying independent of dst/src sample type. - * Don't pass in any expressions for the macro arguments here. - */ -#define copy_frame_by_mask(dst, dmask, src, smask, count, zero) \ -{ \ - uint32_t bit, ormask; \ - while ((count)--) { \ - ormask = (dmask) | (smask); \ - while (ormask) { \ - bit = ormask & -ormask; /* get lowest bit */ \ - ormask ^= bit; /* remove lowest bit */ \ - if ((dmask) & bit) { \ - *(dst)++ = (smask) & bit ? *(src)++ : (zero); \ - } else { /* source channel only */ \ - ++(src); \ - } \ - } \ - } \ -} - -void memcpy_by_channel_mask(void *dst, uint32_t dst_mask, - const void *src, uint32_t src_mask, size_t sample_size, size_t count) -{ -#if 0 - /* alternate way of handling memcpy_by_channel_mask by using the idxary */ - int8_t idxary[32]; - uint32_t src_channels = popcount(src_mask); - uint32_t dst_channels = - memcpy_by_index_array_initialization(idxary, 32, dst_mask, src_mask); - - memcpy_by_idxary(dst, dst_channels, src, src_channels, idxary, sample_size, count); -#else - if (dst_mask == src_mask) { - memcpy(dst, src, sample_size * popcount(dst_mask) * count); - return; - } - switch (sample_size) { - case 1: { - uint8_t *udst = (uint8_t*)dst; - const uint8_t *usrc = (const uint8_t*)src; - - copy_frame_by_mask(udst, dst_mask, usrc, src_mask, count, 0); - } break; - case 2: { - uint16_t *udst = (uint16_t*)dst; - const uint16_t *usrc = (const uint16_t*)src; - - copy_frame_by_mask(udst, dst_mask, usrc, src_mask, count, 0); - } break; - case 3: { /* could be slow. use a struct to represent 3 bytes of data. */ - uint8x3_t *udst = (uint8x3_t*)dst; - const uint8x3_t *usrc = (const uint8x3_t*)src; - static const uint8x3_t zero; /* tricky - we use this to zero out a sample */ - - copy_frame_by_mask(udst, dst_mask, usrc, src_mask, count, zero); - } break; - case 4: { - uint32_t *udst = (uint32_t*)dst; - const uint32_t *usrc = (const uint32_t*)src; - - copy_frame_by_mask(udst, dst_mask, usrc, src_mask, count, 0); - } break; - default: - abort(); /* illegal value */ - break; - } -#endif -} - -/* - * C macro to do copying by index array, to rearrange samples - * within a frame. This is independent of src/dst sample type. - * Don't pass in any expressions for the macro arguments here. - */ -#define copy_frame_by_idx(dst, dst_channels, src, src_channels, idxary, count, zero) \ -{ \ - unsigned i; \ - int index; \ - while ((count)--) { \ - for (i = 0; i < (dst_channels); ++i) { \ - index = (idxary)[i]; \ - *(dst)++ = index < 0 ? (zero) : (src)[index]; \ - } \ - (src) += (src_channels); \ - } \ -} - -void memcpy_by_index_array(void *dst, uint32_t dst_channels, - const void *src, uint32_t src_channels, - const int8_t *idxary, size_t sample_size, size_t count) -{ - switch (sample_size) { - case 1: { - uint8_t *udst = (uint8_t*)dst; - const uint8_t *usrc = (const uint8_t*)src; - - copy_frame_by_idx(udst, dst_channels, usrc, src_channels, idxary, count, 0); - } break; - case 2: { - uint16_t *udst = (uint16_t*)dst; - const uint16_t *usrc = (const uint16_t*)src; - - copy_frame_by_idx(udst, dst_channels, usrc, src_channels, idxary, count, 0); - } break; - case 3: { /* could be slow. use a struct to represent 3 bytes of data. */ - uint8x3_t *udst = (uint8x3_t*)dst; - const uint8x3_t *usrc = (const uint8x3_t*)src; - static const uint8x3_t zero; - - copy_frame_by_idx(udst, dst_channels, usrc, src_channels, idxary, count, zero); - } break; - case 4: { - uint32_t *udst = (uint32_t*)dst; - const uint32_t *usrc = (const uint32_t*)src; - - copy_frame_by_idx(udst, dst_channels, usrc, src_channels, idxary, count, 0); - } break; - default: - abort(); /* illegal value */ - break; - } -} - -size_t memcpy_by_index_array_initialization(int8_t *idxary, size_t idxcount, - uint32_t dst_mask, uint32_t src_mask) -{ - size_t n = 0; - int srcidx = 0; - uint32_t bit, ormask = src_mask | dst_mask; - - while (ormask && n < idxcount) { - bit = ormask & -ormask; /* get lowest bit */ - ormask ^= bit; /* remove lowest bit */ - if (src_mask & dst_mask & bit) { /* matching channel */ - idxary[n++] = srcidx++; - } else if (src_mask & bit) { /* source channel only */ - ++srcidx; - } else { /* destination channel only */ - idxary[n++] = -1; - } - } - return n + popcount(ormask & dst_mask); -} - -size_t memcpy_by_index_array_initialization_src_index(int8_t *idxary, size_t idxcount, - uint32_t dst_mask, uint32_t src_mask) { - size_t dst_count = popcount(dst_mask); - if (idxcount == 0) { - return dst_count; - } - if (dst_count > idxcount) { - dst_count = idxcount; - } - - size_t src_idx, dst_idx; - for (src_idx = 0, dst_idx = 0; dst_idx < dst_count; ++dst_idx) { - if (src_mask & 1) { - idxary[dst_idx] = src_idx++; - } else { - idxary[dst_idx] = -1; - } - src_mask >>= 1; - } - return dst_idx; -} - -size_t memcpy_by_index_array_initialization_dst_index(int8_t *idxary, size_t idxcount, - uint32_t dst_mask, uint32_t src_mask) { - size_t src_idx, dst_idx; - size_t dst_count = __builtin_popcount(dst_mask); - size_t src_count = __builtin_popcount(src_mask); - if (idxcount == 0) { - return dst_count; - } - if (dst_count > idxcount) { - dst_count = idxcount; - } - for (src_idx = 0, dst_idx = 0; dst_idx < dst_count; ++src_idx) { - if (dst_mask & 1) { - idxary[dst_idx++] = src_idx < src_count ? (signed)src_idx : -1; - } - dst_mask >>= 1; - } - return dst_idx; -} diff --git a/cocos/audio/android/audio_utils/private/private.h b/cocos/audio/android/audio_utils/private/private.h deleted file mode 100644 index d10d1ea..0000000 --- a/cocos/audio/android/audio_utils/private/private.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_AUDIO_PRIVATE_H -#define ANDROID_AUDIO_PRIVATE_H - -#include - -__BEGIN_DECLS - -/* Defines not necessary for external use but kept here to be common - * to the audio_utils library. - */ - -/* struct representation of 3 bytes for packed PCM 24 bit data. - * The naming follows the ARM NEON convention. - */ -typedef struct {uint8_t c[3];} __attribute__((__packed__)) uint8x3_t; - -__END_DECLS - -#endif /*ANDROID_AUDIO_PRIVATE_H*/ diff --git a/cocos/audio/android/ccdandroidUtils.cpp b/cocos/audio/android/ccdandroidUtils.cpp deleted file mode 100644 index 1146c61..0000000 --- a/cocos/audio/android/ccdandroidUtils.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/**************************************************************************** -Copyright (c) 2010-2012 cocos2d-x.org -Copyright (c) 2013-2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ -#include "audio/android/ccdandroidUtils.h" - -#include -#include -#include "platform/android/jni/JniHelper.h" -#include "platform/CCFileUtils.h" - - -USING_NS_CC; - -namespace CocosDenshion { - namespace android { - std::string getFullPathWithoutAssetsPrefix(const char* pszFilename) { - // Changing file path to full path - std::string fullPath = cocos2d::FileUtils::getInstance()->fullPathForFilename(pszFilename); - // Removing `assets` since it isn't needed for the API of playing sound. - size_t pos = fullPath.find("assets/"); - if (pos == 0) - { - fullPath = fullPath.substr(strlen("assets/")); - } - return fullPath; - } - } -} diff --git a/cocos/audio/android/ccdandroidUtils.h b/cocos/audio/android/ccdandroidUtils.h deleted file mode 100644 index 1edab8d..0000000 --- a/cocos/audio/android/ccdandroidUtils.h +++ /dev/null @@ -1,37 +0,0 @@ -/**************************************************************************** -Copyright (c) 2010-2012 cocos2d-x.org -Copyright (c) 2013-2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ -#ifndef __CCDANDROIDUTILS_H__ -#define __CCDANDROIDUTILS_H__ - -#include - -namespace CocosDenshion { - namespace android { - std::string getFullPathWithoutAssetsPrefix(const char* pszFilename); - } -} - -#endif //__CCDANDROIDUTILS_H__ diff --git a/cocos/audio/android/cutils/bitops.h b/cocos/audio/android/cutils/bitops.h deleted file mode 100644 index 33168b4..0000000 --- a/cocos/audio/android/cutils/bitops.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef COCOS_CUTILS_BITOPS_H -#define COCOS_CUTILS_BITOPS_H - -#include -#include -#include -#include - -__BEGIN_DECLS - -static inline int popcount(unsigned int x) -{ - return __builtin_popcount(x); -} - -static inline int popcountl(unsigned long x) -{ - return __builtin_popcountl(x); -} - -static inline int popcountll(unsigned long long x) -{ - return __builtin_popcountll(x); -} - -__END_DECLS - -#endif /* COCOS_CUTILS_BITOPS_H */ diff --git a/cocos/audio/android/cutils/log.h b/cocos/audio/android/cutils/log.h deleted file mode 100644 index 3e505b0..0000000 --- a/cocos/audio/android/cutils/log.h +++ /dev/null @@ -1,568 +0,0 @@ -/* - * Copyright (C) 2005-2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// -// C/C++ logging functions. See the logging documentation for API details. -// -// We'd like these to be available from C code (in case we import some from -// somewhere), so this has a C interface. -// -// The output will be correct when the log file is shared between multiple -// threads and/or multiple processes so long as the operating system -// supports O_APPEND. These calls have mutex-protected data structures -// and so are NOT reentrant. Do not use LOG in a signal handler. -// -#ifndef COCOS_CUTILS_LOG_H -#define COCOS_CUTILS_LOG_H - -#include -#include -#include -#include -#include -#include - - -#ifdef __cplusplus -extern "C" { -#endif - -// --------------------------------------------------------------------- -/* - * Normally we strip ALOGV (VERBOSE messages) from release builds. - * You can modify this (for example with "#define LOG_NDEBUG 0" - * at the top of your source file) to change that behavior. - */ -#ifndef LOG_NDEBUG -#if defined(COCOS2D_DEBUG) && COCOS2D_DEBUG > 0 -#define LOG_NDEBUG 0 -#else -#define LOG_NDEBUG 1 -#endif -#endif - -/* - * This is the local tag used for the following simplified - * logging macros. You can change this preprocessor definition - * before using the other macros to change the tag. - */ -#ifndef LOG_TAG -#define LOG_TAG NULL -#endif - -// --------------------------------------------------------------------- - -#ifndef __predict_false -#define __predict_false(exp) __builtin_expect((exp) != 0, 0) -#endif - -/* - * -DLINT_RLOG in sources that you want to enforce that all logging - * goes to the radio log buffer. If any logging goes to any of the other - * log buffers, there will be a compile or link error to highlight the - * problem. This is not a replacement for a full audit of the code since - * this only catches compiled code, not ifdef'd debug code. Options to - * defining this, either temporarily to do a spot check, or permanently - * to enforce, in all the communications trees; We have hopes to ensure - * that by supplying just the radio log buffer that the communications - * teams will have their one-stop shop for triaging issues. - */ -#ifndef LINT_RLOG - -/* - * Simplified macro to send a verbose log message using the current LOG_TAG. - */ -#ifndef ALOGV -#define __ALOGV(...) ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) -#if LOG_NDEBUG -#define ALOGV(...) do { if (0) { __ALOGV(__VA_ARGS__); } } while (0) -#else -#define ALOGV(...) __ALOGV(__VA_ARGS__) -#endif -#endif - -#ifndef ALOGV_IF -#if LOG_NDEBUG -#define ALOGV_IF(cond, ...) ((void)0) -#else -#define ALOGV_IF(cond, ...) \ - ( (__predict_false(cond)) \ - ? ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif -#endif - -/* - * Simplified macro to send a debug log message using the current LOG_TAG. - */ -#ifndef ALOGD -#define ALOGD(...) ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef ALOGD_IF -#define ALOGD_IF(cond, ...) \ - ( (__predict_false(cond)) \ - ? ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif - -/* - * Simplified macro to send an info log message using the current LOG_TAG. - */ -#ifndef ALOGI -#define ALOGI(...) ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef ALOGI_IF -#define ALOGI_IF(cond, ...) \ - ( (__predict_false(cond)) \ - ? ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif - -/* - * Simplified macro to send a warning log message using the current LOG_TAG. - */ -#ifndef ALOGW -#define ALOGW(...) ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef ALOGW_IF -#define ALOGW_IF(cond, ...) \ - ( (__predict_false(cond)) \ - ? ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif - -/* - * Simplified macro to send an error log message using the current LOG_TAG. - */ -#ifndef ALOGE -#define ALOGE(...) ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef ALOGE_IF -#define ALOGE_IF(cond, ...) \ - ( (__predict_false(cond)) \ - ? ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif - -// --------------------------------------------------------------------- - -/* - * Conditional based on whether the current LOG_TAG is enabled at - * verbose priority. - */ -#ifndef IF_ALOGV -#if LOG_NDEBUG -#define IF_ALOGV() if (false) -#else -#define IF_ALOGV() IF_ALOG(LOG_VERBOSE, LOG_TAG) -#endif -#endif - -/* - * Conditional based on whether the current LOG_TAG is enabled at - * debug priority. - */ -#ifndef IF_ALOGD -#define IF_ALOGD() IF_ALOG(LOG_DEBUG, LOG_TAG) -#endif - -/* - * Conditional based on whether the current LOG_TAG is enabled at - * info priority. - */ -#ifndef IF_ALOGI -#define IF_ALOGI() IF_ALOG(LOG_INFO, LOG_TAG) -#endif - -/* - * Conditional based on whether the current LOG_TAG is enabled at - * warn priority. - */ -#ifndef IF_ALOGW -#define IF_ALOGW() IF_ALOG(LOG_WARN, LOG_TAG) -#endif - -/* - * Conditional based on whether the current LOG_TAG is enabled at - * error priority. - */ -#ifndef IF_ALOGE -#define IF_ALOGE() IF_ALOG(LOG_ERROR, LOG_TAG) -#endif - - -// --------------------------------------------------------------------- - -/* - * Simplified macro to send a verbose system log message using the current LOG_TAG. - */ -#ifndef SLOGV -#define __SLOGV(...) \ - ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) -#if LOG_NDEBUG -#define SLOGV(...) do { if (0) { __SLOGV(__VA_ARGS__); } } while (0) -#else -#define SLOGV(...) __SLOGV(__VA_ARGS__) -#endif -#endif - -#ifndef SLOGV_IF -#if LOG_NDEBUG -#define SLOGV_IF(cond, ...) ((void)0) -#else -#define SLOGV_IF(cond, ...) \ - ( (__predict_false(cond)) \ - ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif -#endif - -/* - * Simplified macro to send a debug system log message using the current LOG_TAG. - */ -#ifndef SLOGD -#define SLOGD(...) \ - ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef SLOGD_IF -#define SLOGD_IF(cond, ...) \ - ( (__predict_false(cond)) \ - ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif - -/* - * Simplified macro to send an info system log message using the current LOG_TAG. - */ -#ifndef SLOGI -#define SLOGI(...) \ - ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef SLOGI_IF -#define SLOGI_IF(cond, ...) \ - ( (__predict_false(cond)) \ - ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif - -/* - * Simplified macro to send a warning system log message using the current LOG_TAG. - */ -#ifndef SLOGW -#define SLOGW(...) \ - ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef SLOGW_IF -#define SLOGW_IF(cond, ...) \ - ( (__predict_false(cond)) \ - ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif - -/* - * Simplified macro to send an error system log message using the current LOG_TAG. - */ -#ifndef SLOGE -#define SLOGE(...) \ - ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef SLOGE_IF -#define SLOGE_IF(cond, ...) \ - ( (__predict_false(cond)) \ - ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif - -#endif /* !LINT_RLOG */ - -// --------------------------------------------------------------------- - -/* - * Simplified macro to send a verbose radio log message using the current LOG_TAG. - */ -#ifndef RLOGV -#define __RLOGV(...) \ - ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) -#if LOG_NDEBUG -#define RLOGV(...) do { if (0) { __RLOGV(__VA_ARGS__); } } while (0) -#else -#define RLOGV(...) __RLOGV(__VA_ARGS__) -#endif -#endif - -#ifndef RLOGV_IF -#if LOG_NDEBUG -#define RLOGV_IF(cond, ...) ((void)0) -#else -#define RLOGV_IF(cond, ...) \ - ( (__predict_false(cond)) \ - ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif -#endif - -/* - * Simplified macro to send a debug radio log message using the current LOG_TAG. - */ -#ifndef RLOGD -#define RLOGD(...) \ - ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef RLOGD_IF -#define RLOGD_IF(cond, ...) \ - ( (__predict_false(cond)) \ - ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif - -/* - * Simplified macro to send an info radio log message using the current LOG_TAG. - */ -#ifndef RLOGI -#define RLOGI(...) \ - ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef RLOGI_IF -#define RLOGI_IF(cond, ...) \ - ( (__predict_false(cond)) \ - ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif - -/* - * Simplified macro to send a warning radio log message using the current LOG_TAG. - */ -#ifndef RLOGW -#define RLOGW(...) \ - ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef RLOGW_IF -#define RLOGW_IF(cond, ...) \ - ( (__predict_false(cond)) \ - ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif - -/* - * Simplified macro to send an error radio log message using the current LOG_TAG. - */ -#ifndef RLOGE -#define RLOGE(...) \ - ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef RLOGE_IF -#define RLOGE_IF(cond, ...) \ - ( (__predict_false(cond)) \ - ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif - - -// --------------------------------------------------------------------- - -/* - * Log a fatal error. If the given condition fails, this stops program - * execution like a normal assertion, but also generating the given message. - * It is NOT stripped from release builds. Note that the condition test - * is -inverted- from the normal assert() semantics. - */ -#ifndef LOG_ALWAYS_FATAL_IF -#define LOG_ALWAYS_FATAL_IF(cond, ...) \ - ( (__predict_false(cond)) \ - ? ((void)android_printAssert(#cond, LOG_TAG, ## __VA_ARGS__)) \ - : (void)0 ) -#endif - -#ifndef LOG_ALWAYS_FATAL -#define LOG_ALWAYS_FATAL(...) \ - ( ((void)android_printAssert(NULL, LOG_TAG, ## __VA_ARGS__)) ) -#endif - -/* - * Versions of LOG_ALWAYS_FATAL_IF and LOG_ALWAYS_FATAL that - * are stripped out of release builds. - */ -#if LOG_NDEBUG - -#ifndef LOG_FATAL_IF -#define LOG_FATAL_IF(cond, ...) ((void)0) -#endif -#ifndef LOG_FATAL -#define LOG_FATAL(...) ((void)0) -#endif - -#else - -#ifndef LOG_FATAL_IF -#define LOG_FATAL_IF(cond, ...) LOG_ALWAYS_FATAL_IF(cond, ## __VA_ARGS__) -#endif -#ifndef LOG_FATAL -#define LOG_FATAL(...) LOG_ALWAYS_FATAL(__VA_ARGS__) -#endif - -#endif - -/* - * Assertion that generates a log message when the assertion fails. - * Stripped out of release builds. Uses the current LOG_TAG. - */ -#ifndef ALOG_ASSERT -#define ALOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ## __VA_ARGS__) -//#define ALOG_ASSERT(cond) LOG_FATAL_IF(!(cond), "Assertion failed: " #cond) -#endif - -// --------------------------------------------------------------------- - -/* - * Basic log message macro. - * - * Example: - * ALOG(LOG_WARN, NULL, "Failed with error %d", errno); - * - * The second argument may be NULL or "" to indicate the "global" tag. - */ -#ifndef ALOG -#define ALOG(priority, tag, ...) \ - LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__) -#endif - -/* - * Log macro that allows you to specify a number for the priority. - */ -#ifndef LOG_PRI -#define LOG_PRI(priority, tag, ...) \ - android_printLog(priority, tag, __VA_ARGS__) -#endif - -/* - * Log macro that allows you to pass in a varargs ("args" is a va_list). - */ -#ifndef LOG_PRI_VA -#define LOG_PRI_VA(priority, tag, fmt, args) \ - android_vprintLog(priority, NULL, tag, fmt, args) -#endif - -/* - * Conditional given a desired logging priority and tag. - */ -#ifndef IF_ALOG -#define IF_ALOG(priority, tag) \ - if (android_testLog(ANDROID_##priority, tag)) -#endif - -// --------------------------------------------------------------------- - -/* - * =========================================================================== - * - * The stuff in the rest of this file should not be used directly. - */ - -#define android_printLog(prio, tag, ...) \ - __android_log_print(prio, tag, __VA_ARGS__) - -#define android_vprintLog(prio, cond, tag, ...) \ - __android_log_vprint(prio, tag, __VA_ARGS__) - -/* XXX Macros to work around syntax errors in places where format string - * arg is not passed to ALOG_ASSERT, LOG_ALWAYS_FATAL or LOG_ALWAYS_FATAL_IF - * (happens only in debug builds). - */ - -/* Returns 2nd arg. Used to substitute default value if caller's vararg list - * is empty. - */ -#define __android_second(dummy, second, ...) second - -/* If passed multiple args, returns ',' followed by all but 1st arg, otherwise - * returns nothing. - */ -#define __android_rest(first, ...) , ## __VA_ARGS__ - -#define android_printAssert(cond, tag, ...) \ - __android_log_assert(cond, tag, \ - __android_second(0, ## __VA_ARGS__, NULL) __android_rest(__VA_ARGS__)) - -#define android_writeLog(prio, tag, text) \ - __android_log_write(prio, tag, text) - -#define android_bWriteLog(tag, payload, len) \ - __android_log_bwrite(tag, payload, len) -#define android_btWriteLog(tag, type, payload, len) \ - __android_log_btwrite(tag, type, payload, len) - -#define android_errorWriteLog(tag, subTag) \ - __android_log_error_write(tag, subTag, -1, NULL, 0) - -#define android_errorWriteWithInfoLog(tag, subTag, uid, data, dataLen) \ - __android_log_error_write(tag, subTag, uid, data, dataLen) - -/* - * IF_ALOG uses android_testLog, but IF_ALOG can be overridden. - * android_testLog will remain constant in its purpose as a wrapper - * for Android logging filter policy, and can be subject to - * change. It can be reused by the developers that override - * IF_ALOG as a convenient means to reimplement their policy - * over Android. - */ -#if LOG_NDEBUG /* Production */ -#define android_testLog(prio, tag) \ - (__android_log_is_loggable(prio, tag, ANDROID_LOG_DEBUG) != 0) -#else -#define android_testLog(prio, tag) \ - (__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE) != 0) -#endif - -/* - * Use the per-tag properties "log.tag." to generate a runtime - * result of non-zero to expose a log. prio is ANDROID_LOG_VERBOSE to - * ANDROID_LOG_FATAL. default_prio if no property. Undefined behavior if - * any other value. - */ -int __android_log_is_loggable(int prio, const char *tag, int default_prio); - -int __android_log_security(); /* Device Owner is present */ - -int __android_log_error_write(int tag, const char *subTag, int32_t uid, const char *data, - uint32_t dataLen); - -/* - * Send a simple string to the log. - */ -int __android_log_buf_write(int bufID, int prio, const char *tag, const char *text); -int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fmt, ...) -#if defined(__GNUC__) - __attribute__((__format__(printf, 4, 5))) -#endif -; - -#ifdef __cplusplus -} -#endif - -#endif /* COCOS_CUTILS_LOG_H */ diff --git a/cocos/audio/android/mp3reader.cpp b/cocos/audio/android/mp3reader.cpp deleted file mode 100644 index 15a5ef9..0000000 --- a/cocos/audio/android/mp3reader.cpp +++ /dev/null @@ -1,542 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#define LOG_TAG "mp3reader" - -#include -#include -#include -#include -#include -#include "audio/android/cutils/log.h" - -#include "pvmp3decoder_api.h" -#include "audio/android/mp3reader.h" - -using namespace std; - -static uint32_t U32_AT(const uint8_t *ptr) { - return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3]; -} - -static bool parseHeader( - uint32_t header, size_t *frame_size, - uint32_t *out_sampling_rate = NULL, uint32_t *out_channels = NULL , - uint32_t *out_bitrate = NULL, uint32_t *out_num_samples = NULL) { - *frame_size = 0; - - if (out_sampling_rate) { - *out_sampling_rate = 0; - } - - if (out_channels) { - *out_channels = 0; - } - - if (out_bitrate) { - *out_bitrate = 0; - } - - if (out_num_samples) { - *out_num_samples = 1152; - } - - if ((header & 0xffe00000) != 0xffe00000) { - return false; - } - - unsigned version = (header >> 19) & 3; - - if (version == 0x01) { - return false; - } - - unsigned layer = (header >> 17) & 3; - - if (layer == 0x00) { - return false; - } - - unsigned bitrate_index = (header >> 12) & 0x0f; - - if (bitrate_index == 0 || bitrate_index == 0x0f) { - // Disallow "free" bitrate. - return false; - } - - unsigned sampling_rate_index = (header >> 10) & 3; - - if (sampling_rate_index == 3) { - return false; - } - - static const int kSamplingRateV1[] = { 44100, 48000, 32000 }; - int sampling_rate = kSamplingRateV1[sampling_rate_index]; - if (version == 2 /* V2 */) { - sampling_rate /= 2; - } else if (version == 0 /* V2.5 */) { - sampling_rate /= 4; - } - - unsigned padding = (header >> 9) & 1; - - if (layer == 3) { - // layer I - - static const int kBitrateV1[] = { - 32, 64, 96, 128, 160, 192, 224, 256, - 288, 320, 352, 384, 416, 448 - }; - - static const int kBitrateV2[] = { - 32, 48, 56, 64, 80, 96, 112, 128, - 144, 160, 176, 192, 224, 256 - }; - - int bitrate = - (version == 3 /* V1 */) - ? kBitrateV1[bitrate_index - 1] - : kBitrateV2[bitrate_index - 1]; - - if (out_bitrate) { - *out_bitrate = bitrate; - } - - *frame_size = (12000 * bitrate / sampling_rate + padding) * 4; - - if (out_num_samples) { - *out_num_samples = 384; - } - } else { - // layer II or III - - static const int kBitrateV1L2[] = { - 32, 48, 56, 64, 80, 96, 112, 128, - 160, 192, 224, 256, 320, 384 - }; - - static const int kBitrateV1L3[] = { - 32, 40, 48, 56, 64, 80, 96, 112, - 128, 160, 192, 224, 256, 320 - }; - - static const int kBitrateV2[] = { - 8, 16, 24, 32, 40, 48, 56, 64, - 80, 96, 112, 128, 144, 160 - }; - - int bitrate; - if (version == 3 /* V1 */) { - bitrate = (layer == 2 /* L2 */) - ? kBitrateV1L2[bitrate_index - 1] - : kBitrateV1L3[bitrate_index - 1]; - - if (out_num_samples) { - *out_num_samples = 1152; - } - } else { - // V2 (or 2.5) - - bitrate = kBitrateV2[bitrate_index - 1]; - if (out_num_samples) { - *out_num_samples = (layer == 1 /* L3 */) ? 576 : 1152; - } - } - - if (out_bitrate) { - *out_bitrate = bitrate; - } - - if (version == 3 /* V1 */) { - *frame_size = 144000 * bitrate / sampling_rate + padding; - } else { - // V2 or V2.5 - size_t tmp = (layer == 1 /* L3 */) ? 72000 : 144000; - *frame_size = tmp * bitrate / sampling_rate + padding; - } - } - - if (out_sampling_rate) { - *out_sampling_rate = sampling_rate; - } - - if (out_channels) { - int channel_mode = (header >> 6) & 3; - - *out_channels = (channel_mode == 3) ? 1 : 2; - } - - return true; -} - -// Mask to extract the version, layer, sampling rate parts of the MP3 header, -// which should be same for all MP3 frames. -static const uint32_t kMask = 0xfffe0c00; - -static ssize_t sourceReadAt(mp3_callbacks *callback, void* source, off64_t offset, void *data, size_t size) { - int retVal = callback->seek(source, offset, SEEK_SET); - if (retVal != EXIT_SUCCESS) { - return 0; - } else { - return callback->read(data, 1, size, source); - } -} - -// Resync to next valid MP3 frame in the file. -static bool resync( - mp3_callbacks *callback, void* source, uint32_t match_header, - off64_t *inout_pos, uint32_t *out_header) { - - if (*inout_pos == 0) { - // Skip an optional ID3 header if syncing at the very beginning - // of the datasource. - - for (;;) { - uint8_t id3header[10]; - int retVal = sourceReadAt(callback, source, *inout_pos, id3header, - sizeof(id3header)); - if (retVal < (ssize_t)sizeof(id3header)) { - // If we can't even read these 10 bytes, we might as well bail - // out, even if there _were_ 10 bytes of valid mp3 audio data... - return false; - } - - if (memcmp("ID3", id3header, 3)) { - break; - } - - // Skip the ID3v2 header. - - size_t len = - ((id3header[6] & 0x7f) << 21) - | ((id3header[7] & 0x7f) << 14) - | ((id3header[8] & 0x7f) << 7) - | (id3header[9] & 0x7f); - - len += 10; - - *inout_pos += len; - - ALOGV("skipped ID3 tag, new starting offset is %lld (0x%016llx)", - (long long)*inout_pos, (long long)*inout_pos); - } - - } - - off64_t pos = *inout_pos; - bool valid = false; - - const int32_t kMaxReadBytes = 1024; - const int32_t kMaxBytesChecked = 128 * 1024; - uint8_t buf[kMaxReadBytes]; - ssize_t bytesToRead = kMaxReadBytes; - ssize_t totalBytesRead = 0; - ssize_t remainingBytes = 0; - bool reachEOS = false; - uint8_t *tmp = buf; - - do { - if (pos >= (off64_t)(*inout_pos + kMaxBytesChecked)) { - // Don't scan forever. - ALOGV("giving up at offset %lld", (long long)pos); - break; - } - - if (remainingBytes < 4) { - if (reachEOS) { - break; - } else { - memcpy(buf, tmp, remainingBytes); - bytesToRead = kMaxReadBytes - remainingBytes; - - /* - * The next read position should start from the end of - * the last buffer, and thus should include the remaining - * bytes in the buffer. - */ - totalBytesRead = sourceReadAt(callback, source, pos + remainingBytes, - buf + remainingBytes, bytesToRead); - - if (totalBytesRead <= 0) { - break; - } - reachEOS = (totalBytesRead != bytesToRead); - remainingBytes += totalBytesRead; - tmp = buf; - continue; - } - } - - uint32_t header = U32_AT(tmp); - - if (match_header != 0 && (header & kMask) != (match_header & kMask)) { - ++pos; - ++tmp; - --remainingBytes; - continue; - } - - size_t frame_size; - uint32_t sample_rate, num_channels, bitrate; - if (!parseHeader( - header, &frame_size, - &sample_rate, &num_channels, &bitrate)) { - ++pos; - ++tmp; - --remainingBytes; - continue; - } - - // ALOGV("found possible 1st frame at %lld (header = 0x%08x)", (long long)pos, header); - // We found what looks like a valid frame, - // now find its successors. - - off64_t test_pos = pos + frame_size; - - valid = true; - const int FRAME_MATCH_REQUIRED = 3; - for (int j = 0; j < FRAME_MATCH_REQUIRED; ++j) { - uint8_t tmp[4]; - ssize_t retval = sourceReadAt(callback, source, test_pos, tmp, sizeof(tmp)); - if (retval < (ssize_t)sizeof(tmp)) { - valid = false; - break; - } - - uint32_t test_header = U32_AT(tmp); - - ALOGV("subsequent header is %08x", test_header); - - if ((test_header & kMask) != (header & kMask)) { - valid = false; - break; - } - - size_t test_frame_size; - if (!parseHeader(test_header, &test_frame_size)) { - valid = false; - break; - } - - ALOGV("found subsequent frame #%d at %lld", j + 2, (long long)test_pos); - test_pos += test_frame_size; - } - - if (valid) { - *inout_pos = pos; - - if (out_header != NULL) { - *out_header = header; - } - } else { - ALOGV("no dice, no valid sequence of frames found."); - } - - ++pos; - ++tmp; - --remainingBytes; - } while (!valid); - - return valid; -} - -Mp3Reader::Mp3Reader() : mSource(NULL), mCallback(NULL) { -} - -// Initialize the MP3 reader. -bool Mp3Reader::init(mp3_callbacks *callback, void* source) { - - mSource = source; - mCallback = callback; - // Open the file. - // mFp = fopen(file, "rb"); - // if (mFp == NULL) return false; - - // Sync to the first valid frame. - off64_t pos = 0; - uint32_t header; - bool success = resync(callback, source, 0 /*match_header*/, &pos, &header); - if (!success) - { - ALOGE("%s, resync failed", __FUNCTION__); - return false; - } - - mCurrentPos = pos; - mFixedHeader = header; - - size_t frame_size; - return parseHeader(header, &frame_size, &mSampleRate, - &mNumChannels, &mBitrate); -} - -// Get the next valid MP3 frame. -bool Mp3Reader::getFrame(void *buffer, uint32_t *size) { - - size_t frame_size; - uint32_t bitrate; - uint32_t num_samples; - uint32_t sample_rate; - for (;;) { - ssize_t n = sourceReadAt(mCallback, mSource, mCurrentPos, buffer, 4); - if (n < 4) { - return false; - } - - uint32_t header = U32_AT((const uint8_t *)buffer); - - if ((header & kMask) == (mFixedHeader & kMask) - && parseHeader( - header, &frame_size, &sample_rate, NULL /*out_channels*/, - &bitrate, &num_samples)) { - break; - } - - // Lost sync. - off64_t pos = mCurrentPos; - if (!resync(mCallback, mSource, mFixedHeader, &pos, NULL /*out_header*/)) { - // Unable to resync. Signalling end of stream. - return false; - } - - mCurrentPos = pos; - - // Try again with the new position. - } - ssize_t n = sourceReadAt(mCallback, mSource, mCurrentPos, buffer, frame_size); - if (n < (ssize_t)frame_size) { - return false; - } - - *size = frame_size; - mCurrentPos += frame_size; - return true; -} - -// Close the MP3 reader. -void Mp3Reader::close() { - assert(mCallback != NULL); - mCallback->close(mSource); -} - -Mp3Reader::~Mp3Reader() { -} - -enum { - kInputBufferSize = 10 * 1024, - kOutputBufferSize = 4608 * 2, -}; - -int decodeMP3(mp3_callbacks* cb, void* source, std::vector& pcmBuffer, int* numChannels, int* sampleRate, int* numFrames) -{ - // Initialize the config. - tPVMP3DecoderExternal config; - config.equalizerType = flat; - config.crcEnabled = false; - - // Allocate the decoder memory. - uint32_t memRequirements = pvmp3_decoderMemRequirements(); - void *decoderBuf = malloc(memRequirements); - assert(decoderBuf != NULL); - - // Initialize the decoder. - pvmp3_InitDecoder(&config, decoderBuf); - - // Open the input file. - Mp3Reader mp3Reader; - bool success = mp3Reader.init(cb, source); - if (!success) { - ALOGE("mp3Reader.init: Encountered error reading\n"); - free(decoderBuf); - return EXIT_FAILURE; - } - - // Open the output file. - // SF_INFO sfInfo; - // memset(&sfInfo, 0, sizeof(SF_INFO)); - // sfInfo.channels = mp3Reader.getNumChannels(); - // sfInfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16; - // sfInfo.samplerate = mp3Reader.getSampleRate(); - // SNDFILE *handle = sf_open(argv[2], SFM_WRITE, &sfInfo); - // if (handle == NULL) { - // ALOGE("Encountered error writing %s\n", argv[2]); - // mp3Reader.close(); - // free(decoderBuf); - // return EXIT_FAILURE; - // } - - // Allocate input buffer. - uint8_t *inputBuf = static_cast(malloc(kInputBufferSize)); - assert(inputBuf != NULL); - - // Allocate output buffer. - int16_t *outputBuf = static_cast(malloc(kOutputBufferSize)); - assert(outputBuf != NULL); - - // Decode loop. - int retVal = EXIT_SUCCESS; - while (1) { - // Read input from the file. - uint32_t bytesRead; - bool success = mp3Reader.getFrame(inputBuf, &bytesRead); - if (!success) break; - - *numChannels = mp3Reader.getNumChannels(); - *sampleRate = mp3Reader.getSampleRate(); - - // Set the input config. - config.inputBufferCurrentLength = bytesRead; - config.inputBufferMaxLength = 0; - config.inputBufferUsedLength = 0; - config.pInputBuffer = inputBuf; - config.pOutputBuffer = outputBuf; - config.outputFrameSize = kOutputBufferSize / sizeof(int16_t); - - ERROR_CODE decoderErr; - decoderErr = pvmp3_framedecoder(&config, decoderBuf); - if (decoderErr != NO_DECODING_ERROR) { - ALOGE("Decoder encountered error=%d", decoderErr); - retVal = EXIT_FAILURE; - break; - } - - pcmBuffer.insert(pcmBuffer.end(), (char*)outputBuf, ((char*)outputBuf) + config.outputFrameSize * 2); - *numFrames += config.outputFrameSize / mp3Reader.getNumChannels(); - } - - // Close input reader and output writer. - mp3Reader.close(); - // sf_close(handle); - - // Free allocated memory. - free(inputBuf); - free(outputBuf); - free(decoderBuf); - - return retVal; -} diff --git a/cocos/audio/android/mp3reader.h b/cocos/audio/android/mp3reader.h deleted file mode 100644 index 7c9e0a7..0000000 --- a/cocos/audio/android/mp3reader.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef MP3READER_H_ -#define MP3READER_H_ - -typedef struct { - size_t (*read) (void *ptr, size_t size, size_t nmemb, void *datasource); - int (*seek) (void *datasource, int64_t offset, int whence); - int (*close) (void *datasource); - long (*tell) (void *datasource); -} mp3_callbacks; - -class Mp3Reader { -public: - Mp3Reader(); - bool init(mp3_callbacks *callback, void* source); - bool getFrame(void *buffer, uint32_t *size); - uint32_t getSampleRate() { return mSampleRate;} - uint32_t getNumChannels() { return mNumChannels;} - void close(); - ~Mp3Reader(); -private: - void *mSource; - mp3_callbacks* mCallback; - uint32_t mFixedHeader; - off64_t mCurrentPos; - uint32_t mSampleRate; - uint32_t mNumChannels; - uint32_t mBitrate; -}; - -int decodeMP3(mp3_callbacks* cb, void* source, std::vector& pcmBuffer, int* numChannels, int* sampleRate, int* numFrames); - - -#endif /* MP3READER_H_ */ diff --git a/cocos/audio/android/tinysndfile.cpp b/cocos/audio/android/tinysndfile.cpp deleted file mode 100644 index b459166..0000000 --- a/cocos/audio/android/tinysndfile.cpp +++ /dev/null @@ -1,518 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "tinysndfile" - -#include "audio/android/tinysndfile.h" -#include "audio/android/audio_utils/include/audio_utils/primitives.h" -#include "audio/android/cutils/log.h" - -// #ifdef HAVE_STDERR -// #include -// #endif - -#include -#include - -#ifndef HAVE_STDERR -#define HAVE_STDERR -#endif - -#define WAVE_FORMAT_PCM 1 -#define WAVE_FORMAT_IEEE_FLOAT 3 -#define WAVE_FORMAT_EXTENSIBLE 0xFFFE - -static snd_callbacks __defaultCallback; -static int __inited = 0; - -struct SNDFILE_ { - uint8_t *temp; // realloc buffer used for shrinking 16 bits to 8 bits and byte-swapping - void *stream; - size_t bytesPerFrame; - size_t remaining; // frames unread for SFM_READ, frames written for SFM_WRITE - SF_INFO info; - snd_callbacks callback; -}; - -static unsigned little2u(unsigned char *ptr) -{ - return (ptr[1] << 8) + ptr[0]; -} - -static unsigned little4u(unsigned char *ptr) -{ - return (ptr[3] << 24) + (ptr[2] << 16) + (ptr[1] << 8) + ptr[0]; -} - -static int isLittleEndian() -{ - static const short one = 1; - return *((const char *) &one) == 1; -} - -// "swab" conflicts with OS X -static void my_swab(short *ptr, size_t numToSwap) -{ - while (numToSwap > 0) { - *ptr = little2u((unsigned char *) ptr); - --numToSwap; - ++ptr; - } -} - -static void* open_func(const char* path, void* user) -{ - return fopen(path, "rb"); -} - -static size_t read_func(void *ptr, size_t size, size_t nmemb, void* datasource) -{ - return fread(ptr, size, nmemb, (FILE*)datasource); -} - -static int seek_func(void* datasource, long offset, int whence) -{ - return fseek((FILE*)datasource, offset, whence); -} - -static int close_func(void* datasource) -{ - return fclose((FILE*)datasource); -} - -static long tell_func(void* datasource) -{ - return ftell((FILE*)datasource); -} - -static void lazyInit() -{ - if (__inited == 0) - { - __defaultCallback.open = open_func; - __defaultCallback.read = read_func; - __defaultCallback.seek = seek_func; - __defaultCallback.close = close_func; - __defaultCallback.tell = tell_func; - __inited = 1; - } -} - -SNDFILE *sf_open_read(const char *path, SF_INFO *info, snd_callbacks* cb, void* user) -{ - lazyInit(); - - if (path == NULL || info == NULL) { -#ifdef HAVE_STDERR - ALOGE("path=%p info=%p\n", path, info); -#endif - return NULL; - } - - SNDFILE *handle = (SNDFILE *) malloc(sizeof(SNDFILE)); - handle->temp = NULL; - - handle->info.format = SF_FORMAT_WAV; - if (cb != NULL) { - handle->callback = *cb; - } else { - handle->callback = __defaultCallback; - } - - void* stream = handle->callback.open(path, user); - if (stream == NULL) { -#ifdef HAVE_STDERR - ALOGE("fopen %s failed errno %d\n", path, errno); -#endif - free(handle); - return NULL; - } - handle->stream = stream; - - // don't attempt to parse all valid forms, just the most common ones - unsigned char wav[12]; - size_t actual; - unsigned riffSize; - size_t remaining; - int hadFmt = 0; - int hadData = 0; - long dataTell = 0L; - - actual = handle->callback.read(wav, sizeof(char), sizeof(wav), stream); - if (actual < 12) { -#ifdef HAVE_STDERR - ALOGE("actual %zu < 44\n", actual); -#endif - goto close; - } - if (memcmp(wav, "RIFF", 4)) { -#ifdef HAVE_STDERR - ALOGE("wav != RIFF\n"); -#endif - goto close; - } - riffSize = little4u(&wav[4]); - if (riffSize < 4) { -#ifdef HAVE_STDERR - ALOGE("riffSize %u < 4\n", riffSize); -#endif - goto close; - } - if (memcmp(&wav[8], "WAVE", 4)) { -#ifdef HAVE_STDERR - ALOGE("missing WAVE\n"); -#endif - goto close; - } - remaining = riffSize - 4; - - while (remaining >= 8) { - unsigned char chunk[8]; - actual = handle->callback.read(chunk, sizeof(char), sizeof(chunk), stream); - if (actual != sizeof(chunk)) { -#ifdef HAVE_STDERR - ALOGE("actual %zu != %zu\n", actual, sizeof(chunk)); -#endif - goto close; - } - remaining -= 8; - unsigned chunkSize = little4u(&chunk[4]); - if (chunkSize > remaining) { -#ifdef HAVE_STDERR - ALOGE("chunkSize %u > remaining %zu\n", chunkSize, remaining); -#endif - goto close; - } - if (!memcmp(&chunk[0], "fmt ", 4)) { - if (hadFmt) { -#ifdef HAVE_STDERR - ALOGE("multiple fmt\n"); -#endif - goto close; - } - if (chunkSize < 2) { -#ifdef HAVE_STDERR - ALOGE("chunkSize %u < 2\n", chunkSize); -#endif - goto close; - } - unsigned char fmt[40]; - actual = handle->callback.read(fmt, sizeof(char), 2, stream); - if (actual != 2) { -#ifdef HAVE_STDERR - ALOGE("actual %zu != 2\n", actual); -#endif - goto close; - } - unsigned format = little2u(&fmt[0]); - size_t minSize = 0; - switch (format) { - case WAVE_FORMAT_PCM: - case WAVE_FORMAT_IEEE_FLOAT: - minSize = 16; - break; - case WAVE_FORMAT_EXTENSIBLE: - minSize = 40; - break; - default: -#ifdef HAVE_STDERR - ALOGE("unsupported format %u\n", format); -#endif - goto close; - } - if (chunkSize < minSize) { -#ifdef HAVE_STDERR - ALOGE("chunkSize %u < minSize %zu\n", chunkSize, minSize); -#endif - goto close; - } - actual = handle->callback.read(&fmt[2], sizeof(char), minSize - 2, stream); - if (actual != minSize - 2) { -#ifdef HAVE_STDERR - ALOGE("actual %zu != %zu\n", actual, minSize - 16); -#endif - goto close; - } - if (chunkSize > minSize) { - handle->callback.seek(stream, (long) (chunkSize - minSize), SEEK_CUR); - } - unsigned channels = little2u(&fmt[2]); - // FIXME FCC_8 - if (channels != 1 && channels != 2 && channels != 4 && channels != 6 && channels != 8) { -#ifdef HAVE_STDERR - ALOGE("unsupported channels %u\n", channels); -#endif - goto close; - } - unsigned samplerate = little4u(&fmt[4]); - if (samplerate == 0) { -#ifdef HAVE_STDERR - ALOGE("samplerate %u == 0\n", samplerate); -#endif - goto close; - } - // ignore byte rate - // ignore block alignment - unsigned bitsPerSample = little2u(&fmt[14]); - if (bitsPerSample != 8 && bitsPerSample != 16 && bitsPerSample != 24 && - bitsPerSample != 32) { -#ifdef HAVE_STDERR - ALOGE("bitsPerSample %u != 8 or 16 or 24 or 32\n", bitsPerSample); -#endif - goto close; - } - unsigned bytesPerFrame = (bitsPerSample >> 3) * channels; - handle->bytesPerFrame = bytesPerFrame; - handle->info.samplerate = samplerate; - handle->info.channels = channels; - switch (bitsPerSample) { - case 8: - handle->info.format |= SF_FORMAT_PCM_U8; - break; - case 16: - handle->info.format |= SF_FORMAT_PCM_16; - break; - case 24: - handle->info.format |= SF_FORMAT_PCM_24; - break; - case 32: - if (format == WAVE_FORMAT_IEEE_FLOAT) - handle->info.format |= SF_FORMAT_FLOAT; - else - handle->info.format |= SF_FORMAT_PCM_32; - break; - } - hadFmt = 1; - } else if (!memcmp(&chunk[0], "data", 4)) { - if (!hadFmt) { -#ifdef HAVE_STDERR - ALOGE("data not preceded by fmt\n"); -#endif - goto close; - } - if (hadData) { -#ifdef HAVE_STDERR - ALOGE("multiple data\n"); -#endif - goto close; - } - handle->remaining = chunkSize / handle->bytesPerFrame; - handle->info.frames = handle->remaining; - dataTell = handle->callback.tell(stream); - if (chunkSize > 0) { - handle->callback.seek(stream, (long) chunkSize, SEEK_CUR); - } - hadData = 1; - } else if (!memcmp(&chunk[0], "fact", 4)) { - // ignore fact - if (chunkSize > 0) { - handle->callback.seek(stream, (long) chunkSize, SEEK_CUR); - } - } else { - // ignore unknown chunk -#ifdef HAVE_STDERR - ALOGE("ignoring unknown chunk %c%c%c%c\n", - chunk[0], chunk[1], chunk[2], chunk[3]); -#endif - if (chunkSize > 0) { - handle->callback.seek(stream, (long) chunkSize, SEEK_CUR); - } - } - remaining -= chunkSize; - } - if (remaining > 0) { -#ifdef HAVE_STDERR - ALOGE("partial chunk at end of RIFF, remaining %zu\n", remaining); -#endif - goto close; - } - if (!hadData) { -#ifdef HAVE_STDERR - ALOGE("missing data\n"); -#endif - goto close; - } - (void) handle->callback.seek(stream, dataTell, SEEK_SET); - *info = handle->info; - return handle; - -close: - free(handle); - handle->callback.close(stream); - return NULL; -} - -void sf_close(SNDFILE *handle) -{ - if (handle == NULL) - return; - free(handle->temp); - (void) handle->callback.close(handle->stream); - free(handle); -} - -sf_count_t sf_readf_short(SNDFILE *handle, short *ptr, sf_count_t desiredFrames) -{ - if (handle == NULL || ptr == NULL || !handle->remaining || - desiredFrames <= 0) { - return 0; - } - if (handle->remaining < (size_t) desiredFrames) { - desiredFrames = handle->remaining; - } - // does not check for numeric overflow - size_t desiredBytes = desiredFrames * handle->bytesPerFrame; - size_t actualBytes; - void *temp = NULL; - unsigned format = handle->info.format & SF_FORMAT_SUBMASK; - if (format == SF_FORMAT_PCM_32 || format == SF_FORMAT_FLOAT || format == SF_FORMAT_PCM_24) { - temp = malloc(desiredBytes); - actualBytes = handle->callback.read(temp, sizeof(char), desiredBytes, handle->stream); - } else { - actualBytes = handle->callback.read(ptr, sizeof(char), desiredBytes, handle->stream); - } - size_t actualFrames = actualBytes / handle->bytesPerFrame; - handle->remaining -= actualFrames; - switch (format) { - case SF_FORMAT_PCM_U8: - memcpy_to_i16_from_u8(ptr, (unsigned char *) ptr, actualFrames * handle->info.channels); - break; - case SF_FORMAT_PCM_16: - if (!isLittleEndian()) - my_swab(ptr, actualFrames * handle->info.channels); - break; - case SF_FORMAT_PCM_32: - memcpy_to_i16_from_i32(ptr, (const int *) temp, actualFrames * handle->info.channels); - free(temp); - break; - case SF_FORMAT_FLOAT: - memcpy_to_i16_from_float(ptr, (const float *) temp, actualFrames * handle->info.channels); - free(temp); - break; - case SF_FORMAT_PCM_24: - memcpy_to_i16_from_p24(ptr, (const uint8_t *) temp, actualFrames * handle->info.channels); - free(temp); - break; - default: - memset(ptr, 0, actualFrames * handle->info.channels * sizeof(short)); - break; - } - return actualFrames; -} - -/* -sf_count_t sf_readf_float(SNDFILE *handle, float *ptr, sf_count_t desiredFrames) -{ - if (handle == NULL || ptr == NULL || !handle->remaining || - desiredFrames <= 0) { - return 0; - } - if (handle->remaining < (size_t) desiredFrames) { - desiredFrames = handle->remaining; - } - // does not check for numeric overflow - size_t desiredBytes = desiredFrames * handle->bytesPerFrame; - size_t actualBytes; - void *temp = NULL; - unsigned format = handle->info.format & SF_FORMAT_SUBMASK; - if (format == SF_FORMAT_PCM_16 || format == SF_FORMAT_PCM_U8 || format == SF_FORMAT_PCM_24) { - temp = malloc(desiredBytes); - actualBytes = handle->callback.read(temp, sizeof(char), desiredBytes, handle->stream); - } else { - actualBytes = handle->callback.read(ptr, sizeof(char), desiredBytes, handle->stream); - } - size_t actualFrames = actualBytes / handle->bytesPerFrame; - handle->remaining -= actualFrames; - switch (format) { - case SF_FORMAT_PCM_U8: -#if 0 - // TODO - implement - memcpy_to_float_from_u8(ptr, (const unsigned char *) temp, - actualFrames * handle->info.channels); -#endif - free(temp); - break; - case SF_FORMAT_PCM_16: - memcpy_to_float_from_i16(ptr, (const short *) temp, actualFrames * handle->info.channels); - free(temp); - break; - case SF_FORMAT_PCM_32: - memcpy_to_float_from_i32(ptr, (const int *) ptr, actualFrames * handle->info.channels); - break; - case SF_FORMAT_FLOAT: - break; - case SF_FORMAT_PCM_24: - memcpy_to_float_from_p24(ptr, (const uint8_t *) temp, actualFrames * handle->info.channels); - free(temp); - break; - default: - memset(ptr, 0, actualFrames * handle->info.channels * sizeof(float)); - break; - } - return actualFrames; -} - -sf_count_t sf_readf_int(SNDFILE *handle, int *ptr, sf_count_t desiredFrames) -{ - if (handle == NULL || ptr == NULL || !handle->remaining || - desiredFrames <= 0) { - return 0; - } - if (handle->remaining < (size_t) desiredFrames) { - desiredFrames = handle->remaining; - } - // does not check for numeric overflow - size_t desiredBytes = desiredFrames * handle->bytesPerFrame; - void *temp = NULL; - unsigned format = handle->info.format & SF_FORMAT_SUBMASK; - size_t actualBytes; - if (format == SF_FORMAT_PCM_16 || format == SF_FORMAT_PCM_U8 || format == SF_FORMAT_PCM_24) { - temp = malloc(desiredBytes); - actualBytes = handle->callback.read(temp, sizeof(char), desiredBytes, handle->stream); - } else { - actualBytes = handle->callback.read(ptr, sizeof(char), desiredBytes, handle->stream); - } - size_t actualFrames = actualBytes / handle->bytesPerFrame; - handle->remaining -= actualFrames; - switch (format) { - case SF_FORMAT_PCM_U8: -#if 0 - // TODO - implement - memcpy_to_i32_from_u8(ptr, (const unsigned char *) temp, - actualFrames * handle->info.channels); -#endif - free(temp); - break; - case SF_FORMAT_PCM_16: - memcpy_to_i32_from_i16(ptr, (const short *) temp, actualFrames * handle->info.channels); - free(temp); - break; - case SF_FORMAT_PCM_32: - break; - case SF_FORMAT_FLOAT: - memcpy_to_i32_from_float(ptr, (const float *) ptr, actualFrames * handle->info.channels); - break; - case SF_FORMAT_PCM_24: - memcpy_to_i32_from_p24(ptr, (const uint8_t *) temp, actualFrames * handle->info.channels); - free(temp); - break; - default: - memset(ptr, 0, actualFrames * handle->info.channels * sizeof(int)); - break; - } - return actualFrames; -} - */ diff --git a/cocos/audio/android/tinysndfile.h b/cocos/audio/android/tinysndfile.h deleted file mode 100644 index ca7e765..0000000 --- a/cocos/audio/android/tinysndfile.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -// This is a C library for reading and writing PCM .wav files. It is -// influenced by other libraries such as libsndfile and audiofile, except is -// much smaller and has an Apache 2.0 license. -// The API should be familiar to clients of similar libraries, but there is -// no guarantee that it will stay exactly source-code compatible with other libraries. - -#include -#include - -__BEGIN_DECLS - -// visible to clients -typedef int sf_count_t; - -typedef struct { - sf_count_t frames; - int samplerate; - int channels; - int format; -} SF_INFO; - -// opaque to clients -typedef struct SNDFILE_ SNDFILE; - -// Format -#define SF_FORMAT_TYPEMASK 1 -#define SF_FORMAT_WAV 1 -#define SF_FORMAT_SUBMASK 14 -#define SF_FORMAT_PCM_16 2 -#define SF_FORMAT_PCM_U8 4 -#define SF_FORMAT_FLOAT 6 -#define SF_FORMAT_PCM_32 8 -#define SF_FORMAT_PCM_24 10 - -typedef struct { - void* (*open)(const char* path, void* user); - size_t (*read) (void* ptr, size_t size, size_t nmemb, void* datasource); - int (*seek) (void* datasource, long offset, int whence); - int (*close) (void* datasource); - long (*tell) (void* datasource); -} snd_callbacks; - -// Open stream -SNDFILE *sf_open_read(const char *path, SF_INFO *info, snd_callbacks* cb, void* user); - -// Close stream -void sf_close(SNDFILE *handle); - -// Read interleaved frames and return actual number of frames read -sf_count_t sf_readf_short(SNDFILE *handle, short *ptr, sf_count_t desired); -/* -sf_count_t sf_readf_float(SNDFILE *handle, float *ptr, sf_count_t desired); -sf_count_t sf_readf_int(SNDFILE *handle, int *ptr, sf_count_t desired); -*/ - -__END_DECLS diff --git a/cocos/audio/android/utils/Compat.h b/cocos/audio/android/utils/Compat.h deleted file mode 100644 index 512090e..0000000 --- a/cocos/audio/android/utils/Compat.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef COCOS_LIB_UTILS_COMPAT_H -#define COCOS_LIB_UTILS_COMPAT_H - -#include - -#if defined(__APPLE__) - -/* Mac OS has always had a 64-bit off_t, so it doesn't have off64_t. */ - -typedef off_t off64_t; - -static inline off64_t lseek64(int fd, off64_t offset, int whence) { - return lseek(fd, offset, whence); -} - -static inline ssize_t pread64(int fd, void* buf, size_t nbytes, off64_t offset) { - return pread(fd, buf, nbytes, offset); -} - -static inline ssize_t pwrite64(int fd, const void* buf, size_t nbytes, off64_t offset) { - return pwrite(fd, buf, nbytes, offset); -} - -#endif /* __APPLE__ */ - -#if defined(_WIN32) -#define O_CLOEXEC O_NOINHERIT -#define O_NOFOLLOW 0 -#define DEFFILEMODE 0666 -#endif /* _WIN32 */ - -#if defined(_WIN32) -#define ZD "%ld" -#define ZD_TYPE long -#else -#define ZD "%zd" -#define ZD_TYPE ssize_t -#endif - -/* - * Needed for cases where something should be constexpr if possible, but not - * being constexpr is fine if in pre-C++11 code (such as a const static float - * member variable). - */ -#if __cplusplus >= 201103L -#define CONSTEXPR constexpr -#else -#define CONSTEXPR -#endif - -/* - * TEMP_FAILURE_RETRY is defined by some, but not all, versions of - * . (Alas, it is not as standard as we'd hoped!) So, if it's - * not already defined, then define it here. - */ -#ifndef TEMP_FAILURE_RETRY -/* Used to retry syscalls that can return EINTR. */ -#define TEMP_FAILURE_RETRY(exp) ({ \ - typeof (exp) _rc; \ - do { \ - _rc = (exp); \ - } while (_rc == -1 && errno == EINTR); \ - _rc; }) -#endif - -#if defined(_WIN32) -#define OS_PATH_SEPARATOR '\\' -#else -#define OS_PATH_SEPARATOR '/' -#endif - -#endif /* COCOS_LIB_UTILS_COMPAT_H */ diff --git a/cocos/audio/android/utils/Errors.h b/cocos/audio/android/utils/Errors.h deleted file mode 100644 index da8c7e6..0000000 --- a/cocos/audio/android/utils/Errors.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef COCOS_ERRORS_H -#define COCOS_ERRORS_H - -#include -#include - -namespace cocos2d { - -// use this type to return error codes -#ifdef _WIN32 -typedef int status_t; -#else -typedef int32_t status_t; -#endif - -/* the MS C runtime lacks a few error codes */ - -/* - * Error codes. - * All error codes are negative values. - */ - -// Win32 #defines NO_ERROR as well. It has the same value, so there's no -// real conflict, though it's a bit awkward. -#ifdef _WIN32 -# undef NO_ERROR -#endif - -enum { - OK = 0, // Everything's swell. - NO_ERROR = 0, // No errors. - - UNKNOWN_ERROR = (-2147483647-1), // INT32_MIN value - - NO_MEMORY = -ENOMEM, - INVALID_OPERATION = -ENOSYS, - BAD_VALUE = -EINVAL, - BAD_TYPE = (UNKNOWN_ERROR + 1), - NAME_NOT_FOUND = -ENOENT, - PERMISSION_DENIED = -EPERM, - NO_INIT = -ENODEV, - ALREADY_EXISTS = -EEXIST, - DEAD_OBJECT = -EPIPE, - FAILED_TRANSACTION = (UNKNOWN_ERROR + 2), -#if !defined(_WIN32) - BAD_INDEX = -EOVERFLOW, - NOT_ENOUGH_DATA = -ENODATA, - WOULD_BLOCK = -EWOULDBLOCK, - TIMED_OUT = -ETIMEDOUT, - UNKNOWN_TRANSACTION = -EBADMSG, -#else - BAD_INDEX = -E2BIG, - NOT_ENOUGH_DATA = (UNKNOWN_ERROR + 3), - WOULD_BLOCK = (UNKNOWN_ERROR + 4), - TIMED_OUT = (UNKNOWN_ERROR + 5), - UNKNOWN_TRANSACTION = (UNKNOWN_ERROR + 6), -#endif - FDS_NOT_ALLOWED = (UNKNOWN_ERROR + 7), - UNEXPECTED_NULL = (UNKNOWN_ERROR + 8), -}; - -// Restore define; enumeration is in "android" namespace, so the value defined -// there won't work for Win32 code in a different namespace. -#ifdef _WIN32 -# define NO_ERROR 0L -#endif - -} // namespace cocos2d { - -// --------------------------------------------------------------------------- - -#endif // COCOS_ERRORS_H diff --git a/cocos/audio/android/utils/Utils.cpp b/cocos/audio/android/utils/Utils.cpp deleted file mode 100644 index 7a40ae2..0000000 --- a/cocos/audio/android/utils/Utils.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ -#include "audio/android/utils/Utils.h" -#include "platform/android/jni/JniHelper.h" - -namespace cocos2d { - -int getSDKVersion() -{ - return JniHelper::callStaticIntMethod("org.cocos2dx.lib.Cocos2dxHelper", "getSDKVersion"); -} - -} // end of namespace cocos2d diff --git a/cocos/audio/android/utils/Utils.h b/cocos/audio/android/utils/Utils.h deleted file mode 100644 index b48558b..0000000 --- a/cocos/audio/android/utils/Utils.h +++ /dev/null @@ -1,30 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ - -#include - -namespace cocos2d { - extern int getSDKVersion(); -} diff --git a/cocos/audio/apple/AudioCache.h b/cocos/audio/apple/AudioCache.h deleted file mode 100644 index 3052e8b..0000000 --- a/cocos/audio/apple/AudioCache.h +++ /dev/null @@ -1,109 +0,0 @@ -/**************************************************************************** - Copyright (c) 2014-2016 Chukong Technologies Inc. - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -#pragma once - -#import - -#include -#include -#include - -#include "platform/CCPlatformMacros.h" -#include "audio/apple/AudioMacros.h" - -NS_CC_BEGIN - -class AudioEngineImpl; -class AudioPlayer; - -class AudioCache -{ -public: - - enum class State - { - INITIAL, - LOADING, - READY, - FAILED - }; - - AudioCache(); - ~AudioCache(); - - void addPlayCallback(const std::function& callback); - - void addLoadCallback(const std::function& callback); - -protected: - void setSkipReadDataTask(bool isSkip) { _isSkipReadDataTask = isSkip; }; - void readDataTask(unsigned int selfId); - - void invokingPlayCallbacks(); - - void invokingLoadCallbacks(); - - //pcm data related stuff - ALenum _format; - ALsizei _sampleRate; - float _duration; - uint32_t _totalFrames; - uint32_t _framesRead; - - /*Cache related stuff; - * Cache pcm data when sizeInBytes less than PCMDATA_CACHEMAXSIZE - */ - ALuint _alBufferId; - char* _pcmData; - - /*Queue buffer related stuff - * Streaming in openal when sizeInBytes greater then PCMDATA_CACHEMAXSIZE - */ - char* _queBuffers[QUEUEBUFFER_NUM]; - ALsizei _queBufferSize[QUEUEBUFFER_NUM]; - uint32_t _queBufferFrames; - - std::mutex _playCallbackMutex; - std::vector< std::function > _playCallbacks; - - // loadCallbacks doesn't need mutex since it's invoked only in Cocos thread. - std::vector< std::function > _loadCallbacks; - - std::mutex _readDataTaskMutex; - - State _state; - - std::shared_ptr _isDestroyed; - std::string _fileFullPath; - unsigned int _id; - bool _isLoadingFinished; - bool _isSkipReadDataTask; - - friend class AudioEngineImpl; - friend class AudioPlayer; -}; - -} diff --git a/cocos/audio/apple/AudioCache.mm b/cocos/audio/apple/AudioCache.mm deleted file mode 100644 index fac5a1b..0000000 --- a/cocos/audio/apple/AudioCache.mm +++ /dev/null @@ -1,403 +0,0 @@ -/**************************************************************************** - Copyright (c) 2014-2016 Chukong Technologies Inc. - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -#define LOG_TAG "AudioCache" - -#include "audio/apple/AudioCache.h" - -#import -#import -#include -#include "base/CCDirector.h" -#include "base/CCScheduler.h" - -#include "audio/apple/AudioDecoder.h" - -#ifdef VERY_VERY_VERBOSE_LOGGING -#define ALOGVV ALOGV -#else -#define ALOGVV(...) do{} while(false) -#endif - -namespace { -unsigned int __idIndex = 0; -} - -#define INVALID_AL_BUFFER_ID 0xFFFFFFFF -#define PCMDATA_CACHEMAXSIZE 1048576 - -@interface NSTimerWrapper : NSObject -{ - std::function _timeoutCallback; -} - -@end - -@implementation NSTimerWrapper - --(id) initWithTimeInterval:(double) seconds callback:(const std::function&) cb -{ - if (self = [super init]) - { - _timeoutCallback = cb; - NSTimer* timer = [NSTimer timerWithTimeInterval:seconds target: self selector:@selector(onTimeoutCallback:) userInfo:nil repeats:NO]; - [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; - } - - return self; -} - --(void) onTimeoutCallback: (NSTimer*) timer -{ - if (_timeoutCallback != nullptr) - { - _timeoutCallback(); - _timeoutCallback = nullptr; - } -} - --(void) dealloc -{ - [super dealloc]; -} - -@end - -using namespace cocos2d; - -AudioCache::AudioCache() -: _format(-1) -, _duration(0.0f) -, _totalFrames(0) -, _framesRead(0) -, _alBufferId(INVALID_AL_BUFFER_ID) -, _pcmData(nullptr) -, _queBufferFrames(0) -, _state(State::INITIAL) -, _isDestroyed(std::make_shared(false)) -, _id(++__idIndex) -, _isLoadingFinished(false) -, _isSkipReadDataTask(false) -{ - ALOGVV("AudioCache() %p, id=%u", this, _id); - for (int i = 0; i < QUEUEBUFFER_NUM; ++i) - { - _queBuffers[i] = nullptr; - _queBufferSize[i] = 0; - } -} - -AudioCache::~AudioCache() -{ - ALOGVV("~AudioCache() %p, id=%u, begin", this, _id); - *_isDestroyed = true; - while (!_isLoadingFinished) - { - if (_isSkipReadDataTask) - { - ALOGV("id=%u, Skip read data task, don't continue to wait!", _id); - break; - } - ALOGVV("id=%u, waiting readData thread to finish ...", _id); - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - } - //wait for the 'readDataTask' task to exit - _readDataTaskMutex.lock(); - - if (_state == State::READY) - { - if (_alBufferId != INVALID_AL_BUFFER_ID && alIsBuffer(_alBufferId)) - { - ALOGV("~AudioCache(id=%u), delete buffer: %u", _id, _alBufferId); - alDeleteBuffers(1, &_alBufferId); - _alBufferId = INVALID_AL_BUFFER_ID; - } - } - else - { - ALOGW("AudioCache (%p), id=%u, buffer isn't ready, state=%d", this, _id, _state); - } - - if (_queBufferFrames > 0) - { - for (int index = 0; index < QUEUEBUFFER_NUM; ++index) - { - free(_queBuffers[index]); - } - } - ALOGVV("~AudioCache() %p, id=%u, end", this, _id); - _readDataTaskMutex.unlock(); -} - -void AudioCache::readDataTask(unsigned int selfId) -{ - //Note: It's in sub thread - ALOGVV("readDataTask, cache id=%u", selfId); - - _readDataTaskMutex.lock(); - _state = State::LOADING; - - AudioDecoder decoder; - do - { - if (!decoder.open(_fileFullPath.c_str())) - break; - - const uint32_t originalTotalFrames = decoder.getTotalFrames(); - const uint32_t bytesPerFrame = decoder.getBytesPerFrame(); - const uint32_t sampleRate = decoder.getSampleRate(); - const uint32_t channelCount = decoder.getChannelCount(); - - uint32_t totalFrames = originalTotalFrames; - uint32_t dataSize = totalFrames * bytesPerFrame; - uint32_t remainingFrames = totalFrames; - uint32_t adjustFrames = 0; - - _format = channelCount > 1 ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16; - _sampleRate = (ALsizei)sampleRate; - _duration = 1.0f * totalFrames / sampleRate; - _totalFrames = totalFrames; - - if (dataSize <= PCMDATA_CACHEMAXSIZE) - { - uint32_t framesRead = 0; - const uint32_t framesToReadOnce = std::min(totalFrames, static_cast(sampleRate * QUEUEBUFFER_TIME_STEP * QUEUEBUFFER_NUM)); - - BREAK_IF_ERR_LOG(!decoder.seek(totalFrames), "AudioDecoder::seek(%u) error", totalFrames); - - char* tmpBuf = (char*)malloc(framesToReadOnce * bytesPerFrame); - std::vector adjustFrameBuf; - adjustFrameBuf.reserve(framesToReadOnce * bytesPerFrame); - - // Adjust total frames by setting position to the end of frames and try to read more data. - // This is a workaround for https://github.com/cocos2d/cocos2d-x/issues/16938 - do - { - framesRead = decoder.read(framesToReadOnce, tmpBuf); - if (framesRead > 0) - { - adjustFrames += framesRead; - adjustFrameBuf.insert(adjustFrameBuf.end(), tmpBuf, tmpBuf + framesRead * bytesPerFrame); - } - - } while (framesRead > 0); - - if (adjustFrames > 0) - { - ALOGV("Orignal total frames: %u, adjust frames: %u, current total frames: %u", totalFrames, adjustFrames, totalFrames + adjustFrames); - totalFrames += adjustFrames; - _totalFrames = remainingFrames = totalFrames; - } - - // Reset dataSize - dataSize = totalFrames * bytesPerFrame; - - free(tmpBuf); - - // Reset to frame 0 - BREAK_IF_ERR_LOG(!decoder.seek(0), "AudioDecoder::seek(0) failed!"); - - _pcmData = (char*)malloc(dataSize); - memset(_pcmData, 0x00, dataSize); - ALOGV(" id=%u _pcmData alloc: %p", selfId, _pcmData); - - if (adjustFrames > 0) - { - memcpy(_pcmData + (dataSize - adjustFrameBuf.size()), adjustFrameBuf.data(), adjustFrameBuf.size()); - } - - if (*_isDestroyed) - break; - - framesRead = decoder.readFixedFrames(std::min(framesToReadOnce, remainingFrames), _pcmData + _framesRead * bytesPerFrame); - _framesRead += framesRead; - remainingFrames -= framesRead; - - if (*_isDestroyed) - break; - - uint32_t frames = 0; - while (!*_isDestroyed && _framesRead < originalTotalFrames) - { - frames = std::min(framesToReadOnce, remainingFrames); - if (_framesRead + frames > originalTotalFrames) - { - frames = originalTotalFrames - _framesRead; - } - framesRead = decoder.read(frames, _pcmData + _framesRead * bytesPerFrame); - if (framesRead == 0) - break; - _framesRead += framesRead; - remainingFrames -= framesRead; - } - - if (_framesRead < originalTotalFrames) - { - memset(_pcmData + _framesRead * bytesPerFrame, 0x00, (totalFrames - _framesRead) * bytesPerFrame); - } - - ALOGV("pcm buffer was loaded successfully, total frames: %u, total read frames: %u, adjust frames: %u, remainingFrames: %u", totalFrames, _framesRead, adjustFrames, remainingFrames); - _framesRead += adjustFrames; - - alGenBuffers(1, &_alBufferId); - auto alError = alGetError(); - if (alError != AL_NO_ERROR) { - ALOGE("%s: attaching audio to buffer fail: %x", __PRETTY_FUNCTION__, alError); - break; - } - ALOGV(" id=%u generated alGenBuffers: %u for _pcmData: %p", selfId, _alBufferId, _pcmData); - ALOGV(" id=%u _pcmData alBufferData: %p", selfId, _pcmData); - alBufferData(_alBufferId, _format, _pcmData, (ALsizei)dataSize, (ALsizei)sampleRate); - _state = State::READY; - invokingPlayCallbacks(); - - } - else - { - _queBufferFrames = sampleRate * QUEUEBUFFER_TIME_STEP; - BREAK_IF_ERR_LOG(_queBufferFrames == 0, "_queBufferFrames == 0"); - - const uint32_t queBufferBytes = _queBufferFrames * bytesPerFrame; - - for (int index = 0; index < QUEUEBUFFER_NUM; ++index) - { - _queBuffers[index] = (char*)malloc(queBufferBytes); - _queBufferSize[index] = queBufferBytes; - - decoder.readFixedFrames(_queBufferFrames, _queBuffers[index]); - } - - _state = State::READY; - } - - } while (false); - - if (_pcmData != nullptr){ - CC_SAFE_FREE(_pcmData); - } - - decoder.close(); - - //FIXME: Why to invoke play callback first? Should it be after 'load' callback? - invokingPlayCallbacks(); - invokingLoadCallbacks(); - - _isLoadingFinished = true; - if (_state != State::READY) - { - _state = State::FAILED; - if (_alBufferId != INVALID_AL_BUFFER_ID && alIsBuffer(_alBufferId)) - { - ALOGV(" id=%u readDataTask failed, delete buffer: %u", selfId, _alBufferId); - alDeleteBuffers(1, &_alBufferId); - _alBufferId = INVALID_AL_BUFFER_ID; - } - } - - _readDataTaskMutex.unlock(); -} - -void AudioCache::addPlayCallback(const std::function& callback) -{ - std::lock_guard lk(_playCallbackMutex); - switch (_state) - { - case State::INITIAL: - case State::LOADING: - _playCallbacks.push_back(callback); - break; - - case State::READY: - // If state is failure, we still need to invoke the callback - // since the callback will set the 'AudioPlayer::_removeByAudioEngine' flag to true. - case State::FAILED: - callback(); - break; - - default: - ALOGE("Invalid state: %d", _state); - break; - } -} - -void AudioCache::invokingPlayCallbacks() -{ - std::lock_guard lk(_playCallbackMutex); - - for (auto&& cb : _playCallbacks) - { - cb(); - } - - _playCallbacks.clear(); -} - -void AudioCache::addLoadCallback(const std::function& callback) -{ - switch (_state) - { - case State::INITIAL: - case State::LOADING: - _loadCallbacks.push_back(callback); - break; - - case State::READY: - callback(true); - break; - case State::FAILED: - callback(false); - break; - - default: - ALOGE("Invalid state: %d", _state); - break; - } -} - -void AudioCache::invokingLoadCallbacks() -{ - if (*_isDestroyed) - { - ALOGV("AudioCache (%p) was destroyed, don't invoke preload callback ...", this); - return; - } - - auto isDestroyed = _isDestroyed; - auto scheduler = Director::getInstance()->getScheduler(); - scheduler->performFunctionInCocosThread([&, isDestroyed](){ - if (*isDestroyed) - { - ALOGV("invokingLoadCallbacks perform in cocos thread, AudioCache (%p) was destroyed!", this); - return; - } - - for (auto&& cb : _loadCallbacks) - { - cb(_state == State::READY); - } - - _loadCallbacks.clear(); - }); -} diff --git a/cocos/audio/apple/AudioDecoder.h b/cocos/audio/apple/AudioDecoder.h deleted file mode 100644 index 1739bbb..0000000 --- a/cocos/audio/apple/AudioDecoder.h +++ /dev/null @@ -1,120 +0,0 @@ -/**************************************************************************** - Copyright (c) 2016 Chukong Technologies Inc. - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -#pragma once - -#include -#import - -namespace cocos2d { - -/** - * @brief The class for decoding compressed audio file to PCM buffer. - */ -class AudioDecoder -{ -public: - static const uint32_t INVALID_FRAME_INDEX = UINT32_MAX; - - AudioDecoder(); - ~AudioDecoder(); - - /** - * @brief Opens an audio file specified by a file path. - * @return true if succeed, otherwise false. - */ - bool open(const char* path); - - /** - * @brief Checks whether decoder has opened file successfully. - * @return true if succeed, otherwise false. - */ - bool isOpened() const; - - /** - * @brief Closes opened audio file. - * @note The method will also be automatically invoked in the destructor. - */ - void close(); - - /** - * @brief Reads audio frames of PCM format. - * @param framesToRead The number of frames excepted to be read. - * @param pcmBuf The buffer to hold the frames to be read, its size should be >= |framesToRead| * _bytesPerFrame. - * @return The number of frames actually read, it's probably less than 'framesToRead'. Returns 0 means reach the end of file. - */ - uint32_t read(uint32_t framesToRead, char* pcmBuf); - - /** - * @brief Reads fixed audio frames of PCM format. - * @param framesToRead The number of frames excepted to be read. - * @param pcmBuf The buffer to hold the frames to be read, its size should be >= |framesToRead| * _bytesPerFrame. - * @return The number of frames actually read, it's probably less than |framesToRead|. Returns 0 means reach the end of file. - * @note The different between |read| and |readFixedFrames| is |readFixedFrames| will do multiple reading operations if |framesToRead| frames - * isn't filled entirely, while |read| just does reading operation once whatever |framesToRead| is or isn't filled entirely. - * If current position reaches the end of frames, the return value may smaller than |framesToRead| and the remaining - * buffer in |pcmBuf| will be set with silence data (0x00). - */ - uint32_t readFixedFrames(uint32_t framesToRead, char* pcmBuf); - - /** - * @brief Sets frame offest to be read. - * @param frameOffset The frame offest to be set. - * @return true if succeed, otherwise false - */ - bool seek(uint32_t frameOffset); - - /** - * @brief Tells the current frame offset. - * @return The current frame offset. - */ - uint32_t tell() const; - - /** Gets total frames of current audio.*/ - uint32_t getTotalFrames() const; - - /** Gets bytes per frame of current audio.*/ - uint32_t getBytesPerFrame() const; - - /** Gets sample rate of current audio.*/ - uint32_t getSampleRate() const; - - /** Gets the channel count of current audio. - * @note Currently we only support 1 or 2 channels. - */ - uint32_t getChannelCount() const; - -private: - bool _isOpened; - ExtAudioFileRef _extRef; - uint32_t _totalFrames; - uint32_t _bytesPerFrame; - uint32_t _sampleRate; - uint32_t _channelCount; - - AudioStreamBasicDescription _outputFormat; -}; - -} // namespace cocos2d { diff --git a/cocos/audio/apple/AudioDecoder.mm b/cocos/audio/apple/AudioDecoder.mm deleted file mode 100644 index 96e495e..0000000 --- a/cocos/audio/apple/AudioDecoder.mm +++ /dev/null @@ -1,229 +0,0 @@ -/**************************************************************************** - Copyright (c) 2016 Chukong Technologies Inc. - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -#include "audio/apple/AudioDecoder.h" -#include "audio/apple/AudioMacros.h" - -#import - -#define LOG_TAG "AudioDecoder" - -namespace cocos2d { - - AudioDecoder::AudioDecoder() - : _isOpened(false) - , _extRef(nullptr) - , _totalFrames(0) - , _bytesPerFrame(0) - , _sampleRate(0) - , _channelCount(0) - { - memset(&_outputFormat, 0, sizeof(_outputFormat)); - } - - AudioDecoder::~AudioDecoder() - { - close(); - } - - bool AudioDecoder::open(const char* path) - { - bool ret = false; - CFURLRef fileURL = nil; - do - { - BREAK_IF_ERR_LOG(path == nullptr || strlen(path) == 0, "Invalid path!"); - - NSString *fileFullPath = [[NSString alloc] initWithCString:path encoding:NSUTF8StringEncoding]; - fileURL = (CFURLRef)[[NSURL alloc] initFileURLWithPath:fileFullPath]; - [fileFullPath release]; - BREAK_IF_ERR_LOG(fileURL == nil, "Converting path to CFURLRef failed!"); - - OSStatus status = ExtAudioFileOpenURL(fileURL, &_extRef); - BREAK_IF_ERR_LOG(status != noErr, "ExtAudioFileOpenURL FAILED, Error = %d", status); - - AudioStreamBasicDescription fileFormat; - UInt32 propertySize = sizeof(fileFormat); - - // Get the audio data format - status = ExtAudioFileGetProperty(_extRef, kExtAudioFileProperty_FileDataFormat, &propertySize, &fileFormat); - BREAK_IF_ERR_LOG(status != noErr, "ExtAudioFileGetProperty(kExtAudioFileProperty_FileDataFormat) FAILED, Error = %d", status); - BREAK_IF_ERR_LOG(fileFormat.mChannelsPerFrame > 2, "Unsupported Format, channel count is greater than stereo!"); - - // Set the client format to 16 bit signed integer (native-endian) data - // Maintain the channel count and sample rate of the original source format - _outputFormat.mSampleRate = fileFormat.mSampleRate; - _outputFormat.mChannelsPerFrame = fileFormat.mChannelsPerFrame; - _outputFormat.mFormatID = kAudioFormatLinearPCM; - _outputFormat.mFramesPerPacket = 1; - _outputFormat.mBitsPerChannel = 16; - _outputFormat.mFormatFlags = kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger; - - _sampleRate = _outputFormat.mSampleRate; - _channelCount = _outputFormat.mChannelsPerFrame; - _bytesPerFrame = 2 * _outputFormat.mChannelsPerFrame; - - _outputFormat.mBytesPerPacket = _bytesPerFrame; - _outputFormat.mBytesPerFrame = _bytesPerFrame; - - status = ExtAudioFileSetProperty(_extRef, kExtAudioFileProperty_ClientDataFormat, sizeof(_outputFormat), &_outputFormat); - BREAK_IF_ERR_LOG(status != noErr, "ExtAudioFileSetProperty FAILED, Error = %d", status); - - // Get the total frame count - SInt64 totalFrames = 0; - propertySize = sizeof(totalFrames); - status = ExtAudioFileGetProperty(_extRef, kExtAudioFileProperty_FileLengthFrames, &propertySize, &totalFrames); - BREAK_IF_ERR_LOG(status != noErr, "ExtAudioFileGetProperty(kExtAudioFileProperty_FileLengthFrames) FAILED, Error = %d", status); - BREAK_IF_ERR_LOG(totalFrames <= 0, "Total frames is 0, it's an invalid audio file: %s", path); - _totalFrames = static_cast(totalFrames); - _isOpened = true; - - ret = true; - } while (false); - - if (fileURL != nil) - CFRelease(fileURL); - - if (!ret) - { - close(); - } - - return ret; - } - - void AudioDecoder::close() - { - if (_extRef != nullptr) - { - ExtAudioFileDispose(_extRef); - _extRef = nullptr; - - _totalFrames = 0; - _bytesPerFrame = 0; - _sampleRate = 0; - _channelCount = 0; - } - } - - uint32_t AudioDecoder::read(uint32_t framesToRead, char* pcmBuf) - { - uint32_t ret = 0; - do - { - BREAK_IF_ERR_LOG(!isOpened(), "decoder isn't openned"); - BREAK_IF_ERR_LOG(framesToRead == INVALID_FRAME_INDEX, "frameToRead is INVALID_FRAME_INDEX"); - BREAK_IF_ERR_LOG(framesToRead == 0, "frameToRead is 0"); - BREAK_IF_ERR_LOG(pcmBuf == nullptr, "pcmBuf is nullptr"); - - AudioBufferList bufferList; - bufferList.mNumberBuffers = 1; - bufferList.mBuffers[0].mDataByteSize = framesToRead * _bytesPerFrame; - bufferList.mBuffers[0].mNumberChannels = _outputFormat.mChannelsPerFrame; - bufferList.mBuffers[0].mData = pcmBuf; - - UInt32 frames = framesToRead; - OSStatus status = ExtAudioFileRead(_extRef, &frames, &bufferList); - BREAK_IF(status != noErr); - ret = frames; - } while (false); - - return ret; - } - - uint32_t AudioDecoder::readFixedFrames(uint32_t framesToRead, char* pcmBuf) - { - uint32_t framesRead = 0; - uint32_t framesReadOnce = 0; - do - { - framesReadOnce = read(framesToRead - framesRead, pcmBuf + framesRead * _bytesPerFrame); - framesRead += framesReadOnce; - } while (framesReadOnce != 0 && framesRead < framesToRead); - - if (framesRead < framesToRead) - { - memset(pcmBuf + framesRead * _bytesPerFrame, 0x00, (framesToRead - framesRead) * _bytesPerFrame); - } - - return framesRead; - } - - bool AudioDecoder::seek(uint32_t frameOffset) - { - bool ret = false; - do - { - BREAK_IF_ERR_LOG(!isOpened(), "decoder isn't openned"); - BREAK_IF_ERR_LOG(frameOffset == INVALID_FRAME_INDEX, "frameIndex is INVALID_FRAME_INDEX"); - - OSStatus status = ExtAudioFileSeek(_extRef, frameOffset); - BREAK_IF(status != noErr); - ret = true; - } while(false); - return ret; - } - - uint32_t AudioDecoder::tell() const - { - uint32_t ret = INVALID_FRAME_INDEX; - do - { - BREAK_IF_ERR_LOG(!isOpened(), "decoder isn't openned"); - SInt64 frameIndex = INVALID_FRAME_INDEX; - OSStatus status = ExtAudioFileTell(_extRef, &frameIndex); - BREAK_IF(status != noErr); - ret = static_cast(frameIndex); - } while(false); - - return ret; - } - - uint32_t AudioDecoder::getTotalFrames() const - { - return _totalFrames; - } - - uint32_t AudioDecoder::getBytesPerFrame() const - { - return _bytesPerFrame; - } - - uint32_t AudioDecoder::getSampleRate() const - { - return _sampleRate; - } - - uint32_t AudioDecoder::getChannelCount() const - { - return _channelCount; - } - - bool AudioDecoder::isOpened() const - { - return _isOpened; - } - -} // namespace cocos2d { diff --git a/cocos/audio/apple/AudioEngine-inl.h b/cocos/audio/apple/AudioEngine-inl.h deleted file mode 100644 index 31e5b69..0000000 --- a/cocos/audio/apple/AudioEngine-inl.h +++ /dev/null @@ -1,86 +0,0 @@ -/**************************************************************************** - Copyright (c) 2014-2016 Chukong Technologies Inc. - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ -#pragma once - -#include -#include - -#include "base/CCRef.h" -#include "audio/apple/AudioCache.h" -#include "audio/apple/AudioPlayer.h" - -NS_CC_BEGIN -class Scheduler; - -#define MAX_AUDIOINSTANCES 24 - -class AudioEngineImpl : public cocos2d::Ref -{ -public: - AudioEngineImpl(); - ~AudioEngineImpl(); - - bool init(); - int play2d(const std::string &fileFullPath ,bool loop ,float volume); - void setVolume(int audioID,float volume); - void setLoop(int audioID, bool loop); - bool pause(int audioID); - bool resume(int audioID); - void stop(int audioID); - void stopAll(); - float getDuration(int audioID); - float getCurrentTime(int audioID); - bool setCurrentTime(int audioID, float time); - void setFinishCallback(int audioID, const std::function &callback); - - void uncache(const std::string& filePath); - void uncacheAll(); - AudioCache* preload(const std::string& filePath, std::function callback); - void update(float dt); - -private: - void _play2d(AudioCache *cache, int audioID); - ALuint findValidSource(); - - static ALvoid myAlSourceNotificationCallback(ALuint sid, ALuint notificationID, ALvoid* userData); - - ALuint _alSources[MAX_AUDIOINSTANCES]; - - //source,used - std::list _unusedSourcesPool; - - //filePath,bufferInfo - std::unordered_map _audioCaches; - - //audioID,AudioInfo - std::unordered_map _audioPlayers; - std::mutex _threadMutex; - - bool _lazyInitLoop; - - int _currentAudioID; - Scheduler* _scheduler; -}; -NS_CC_END diff --git a/cocos/audio/apple/AudioEngine-inl.mm b/cocos/audio/apple/AudioEngine-inl.mm deleted file mode 100644 index 9345957..0000000 --- a/cocos/audio/apple/AudioEngine-inl.mm +++ /dev/null @@ -1,709 +0,0 @@ -/**************************************************************************** - Copyright (c) 2014-2016 Chukong Technologies Inc. - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -#define LOG_TAG "AudioEngine-inl.mm" - -#include "audio/apple/AudioEngine-inl.h" - -#import -#import - -#include "audio/include/AudioEngine.h" -#include "platform/CCFileUtils.h" -#include "base/CCDirector.h" -#include "base/CCScheduler.h" -#include "base/ccUtils.h" - -#if CC_TARGET_PLATFORM == CC_PLATFORM_IOS -#import -#endif - -using namespace cocos2d; - -static ALCdevice* s_ALDevice = nullptr; -static ALCcontext* s_ALContext = nullptr; -static AudioEngineImpl* s_instance = nullptr; - -typedef ALvoid (*alSourceNotificationProc)(ALuint sid, ALuint notificationID, ALvoid* userData); -typedef ALenum (*alSourceAddNotificationProcPtr)(ALuint sid, ALuint notificationID, alSourceNotificationProc notifyProc, ALvoid* userData); -static ALenum alSourceAddNotificationExt(ALuint sid, ALuint notificationID, alSourceNotificationProc notifyProc, ALvoid* userData) -{ - static alSourceAddNotificationProcPtr proc = nullptr; - - if (proc == nullptr) - { - proc = (alSourceAddNotificationProcPtr)alcGetProcAddress(nullptr, "alSourceAddNotification"); - } - - if (proc) - { - return proc(sid, notificationID, notifyProc, userData); - } - return AL_INVALID_VALUE; -} - -#if CC_TARGET_PLATFORM == CC_PLATFORM_IOS -@interface AudioEngineSessionHandler : NSObject -{ -} - --(id) init; --(void)handleInterruption:(NSNotification*)notification; - -@end - -@implementation AudioEngineSessionHandler - -// only enable it on iOS. Disable it on tvOS -#if !defined(CC_TARGET_OS_TVOS) -void AudioEngineInterruptionListenerCallback(void* user_data, UInt32 interruption_state) -{ - if (kAudioSessionBeginInterruption == interruption_state) - { - alcMakeContextCurrent(nullptr); - } - else if (kAudioSessionEndInterruption == interruption_state) - { - OSStatus result = AudioSessionSetActive(true); - if (result) NSLog(@"Error setting audio session active! %d\n", static_cast(result)); - - alcMakeContextCurrent(s_ALContext); - } -} -#endif - --(id) init -{ - if (self = [super init]) - { - if ([[[UIDevice currentDevice] systemVersion] intValue] > 5) { - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleInterruption:) name:AVAudioSessionInterruptionNotification object:[AVAudioSession sharedInstance]]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleInterruption:) name:UIApplicationDidBecomeActiveNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleInterruption:) name:UIApplicationWillResignActiveNotification object:nil]; - } - // only enable it on iOS. Disable it on tvOS - // AudioSessionInitialize removed from tvOS -#if !defined(CC_TARGET_OS_TVOS) - else { - AudioSessionInitialize(NULL, NULL, AudioEngineInterruptionListenerCallback, self); - } -#endif - - BOOL success = [[AVAudioSession sharedInstance] - setCategory: AVAudioSessionCategoryAmbient - error: nil]; - if (!success) - ALOGE("Fail to set audio session."); - } - return self; -} - --(void)handleInterruption:(NSNotification*)notification -{ - static bool isAudioSessionInterrupted = false; - static bool resumeOnBecomingActive = false; - static bool pauseOnResignActive = false; - - if ([notification.name isEqualToString:AVAudioSessionInterruptionNotification]) - { - NSInteger reason = [[[notification userInfo] objectForKey:AVAudioSessionInterruptionTypeKey] integerValue]; - if (reason == AVAudioSessionInterruptionTypeBegan) - { - isAudioSessionInterrupted = true; - - if ([UIApplication sharedApplication].applicationState != UIApplicationStateActive) - { - ALOGD("AVAudioSessionInterruptionTypeBegan, application != UIApplicationStateActive, alcMakeContextCurrent(nullptr)"); - alcMakeContextCurrent(nullptr); - } - else - { - ALOGD("AVAudioSessionInterruptionTypeBegan, application == UIApplicationStateActive, pauseOnResignActive = true"); - pauseOnResignActive = true; - } - } - - if (reason == AVAudioSessionInterruptionTypeEnded) - { - isAudioSessionInterrupted = false; - - if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) - { - ALOGD("AVAudioSessionInterruptionTypeEnded, application == UIApplicationStateActive, alcMakeContextCurrent(s_ALContext)"); - NSError *error = nil; - [[AVAudioSession sharedInstance] setActive:YES error:&error]; - if(error != nil){ - ALOGE("AVAudioSessionInterruptionTypeEnded, AVAudioSession setActive fail, %d",(int)error.code); - return; - } - - alcMakeContextCurrent(s_ALContext); - if (Director::getInstance()->isPaused()) - { - ALOGD("AVAudioSessionInterruptionTypeEnded, director was paused, try to resume it."); - Director::getInstance()->resume(); - } - } - else - { - ALOGD("AVAudioSessionInterruptionTypeEnded, application != UIApplicationStateActive, resumeOnBecomingActive = true"); - resumeOnBecomingActive = true; - } - } - } - else if ([notification.name isEqualToString:UIApplicationWillResignActiveNotification]) - { - ALOGD("UIApplicationWillResignActiveNotification"); - if (pauseOnResignActive) - { - pauseOnResignActive = false; - ALOGD("UIApplicationWillResignActiveNotification, alcMakeContextCurrent(nullptr)"); - alcMakeContextCurrent(nullptr); - } - } - else if ([notification.name isEqualToString:UIApplicationDidBecomeActiveNotification]) - { - ALOGD("UIApplicationDidBecomeActiveNotification"); - if (resumeOnBecomingActive) - { - resumeOnBecomingActive = false; - ALOGD("UIApplicationDidBecomeActiveNotification, alcMakeContextCurrent(s_ALContext)"); - NSError *error = nil; - BOOL success = [[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryAmbient error: &error]; - if (!success) { - ALOGE("Fail to set audio session."); - return; - } - [[AVAudioSession sharedInstance] setActive:YES error:&error]; - if(error != nil){ - ALOGE("UIApplicationDidBecomeActiveNotification, AVAudioSession setActive fail, %d",(int)error.code); - return; - } - alcMakeContextCurrent(s_ALContext); - } - else if (isAudioSessionInterrupted) - { - ALOGD("Audio session is still interrupted, pause director!"); - Director::getInstance()->pause(); - } - } -} - --(void) dealloc -{ - [[NSNotificationCenter defaultCenter] removeObserver:self name:AVAudioSessionInterruptionNotification object:nil]; - [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil]; - [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillResignActiveNotification object:nil]; - - [super dealloc]; -} -@end - -static id s_AudioEngineSessionHandler = nullptr; -#endif - -ALvoid AudioEngineImpl::myAlSourceNotificationCallback(ALuint sid, ALuint notificationID, ALvoid* userData) -{ - // Currently, we only care about AL_BUFFERS_PROCESSED event - if (notificationID != AL_BUFFERS_PROCESSED) - return; - - AudioPlayer* player = nullptr; - s_instance->_threadMutex.lock(); - for (const auto& e : s_instance->_audioPlayers) - { - player = e.second; - if (player->_alSource == sid && player->_streamingSource) - { - player->wakeupRotateThread(); - } - } - s_instance->_threadMutex.unlock(); -} - -AudioEngineImpl::AudioEngineImpl() -: _lazyInitLoop(true) -, _currentAudioID(0) -, _scheduler(nullptr) -{ - s_instance = this; -} - -AudioEngineImpl::~AudioEngineImpl() -{ - if (_scheduler != nullptr) - { - _scheduler->unschedule(CC_SCHEDULE_SELECTOR(AudioEngineImpl::update), this); - } - - if (s_ALContext) { - alDeleteSources(MAX_AUDIOINSTANCES, _alSources); - - _audioCaches.clear(); - - alcMakeContextCurrent(nullptr); - alcDestroyContext(s_ALContext); - } - if (s_ALDevice) { - alcCloseDevice(s_ALDevice); - } - -#if CC_TARGET_PLATFORM == CC_PLATFORM_IOS - [s_AudioEngineSessionHandler release]; -#endif - s_instance = nullptr; -} - -bool AudioEngineImpl::init() -{ - bool ret = false; - do{ -#if CC_TARGET_PLATFORM == CC_PLATFORM_IOS - s_AudioEngineSessionHandler = [[AudioEngineSessionHandler alloc] init]; -#endif - - s_ALDevice = alcOpenDevice(nullptr); - - if (s_ALDevice) { - s_ALContext = alcCreateContext(s_ALDevice, nullptr); - alcMakeContextCurrent(s_ALContext); - - alGenSources(MAX_AUDIOINSTANCES, _alSources); - auto alError = alGetError(); - if(alError != AL_NO_ERROR) - { - ALOGE("%s:generating sources failed! error = %x", __PRETTY_FUNCTION__, alError); - break; - } - - for (int i = 0; i < MAX_AUDIOINSTANCES; ++i) { - _unusedSourcesPool.push_back(_alSources[i]); - alSourceAddNotificationExt(_alSources[i], AL_BUFFERS_PROCESSED, myAlSourceNotificationCallback, nullptr); - } - - // fixed #16170: Random crash in alGenBuffers(AudioCache::readDataTask) at startup - // Please note that, as we know the OpenAL operation is atomic (threadsafe), - // 'alGenBuffers' may be invoked by different threads. But in current implementation of 'alGenBuffers', - // When the first time it's invoked, application may crash!!! - // Why? OpenAL is opensource by Apple and could be found at - // http://opensource.apple.com/source/OpenAL/OpenAL-48.7/Source/OpenAL/oalImp.cpp . - /* - - void InitializeBufferMap() - { - if (gOALBufferMap == NULL) // Position 1 - { - gOALBufferMap = new OALBufferMap (); // Position 2 - - // Position Gap - - gBufferMapLock = new CAGuard("OAL:BufferMapLock"); // Position 3 - gDeadOALBufferMap = new OALBufferMap (); - - OALBuffer *newBuffer = new OALBuffer (AL_NONE); - gOALBufferMap->Add(AL_NONE, &newBuffer); - } - } - - AL_API ALvoid AL_APIENTRY alGenBuffers(ALsizei n, ALuint *bids) - { - ... - - try { - if (n < 0) - throw ((OSStatus) AL_INVALID_VALUE); - - InitializeBufferMap(); - if (gOALBufferMap == NULL) - throw ((OSStatus) AL_INVALID_OPERATION); - - CAGuard::Locker locked(*gBufferMapLock); // Position 4 - ... - ... - } - - */ - // 'gBufferMapLock' will be initialized in the 'InitializeBufferMap' function, - // that's the problem. It means that 'InitializeBufferMap' may be invoked in different threads. - // It will be very dangerous in multi-threads environment. - // Imagine there're two threads (Thread A, Thread B), they call 'alGenBuffers' simultaneously. - // While A goto 'Position Gap', 'gOALBufferMap' was assigned, then B goto 'Position 1' and find - // that 'gOALBufferMap' isn't NULL, B just jump over 'InitialBufferMap' and goto 'Position 4'. - // Meanwhile, A is still at 'Position Gap', B will crash at '*gBufferMapLock' since 'gBufferMapLock' - // is still a null pointer. Oops, how could Apple implemented this method in this fucking way? - - // Workaround is do an unused invocation in the mainthread right after OpenAL is initialized successfully - // as bellow. - // ================ Workaround begin ================ // - - ALuint unusedAlBufferId = 0; - alGenBuffers(1, &unusedAlBufferId); - alDeleteBuffers(1, &unusedAlBufferId); - - // ================ Workaround end ================ // - - _scheduler = Director::getInstance()->getScheduler(); - ret = true; - ALOGI("OpenAL was initialized successfully!"); - } - }while (false); - - return ret; -} - -AudioCache* AudioEngineImpl::preload(const std::string& filePath, std::function callback) -{ - AudioCache* audioCache = nullptr; - - auto it = _audioCaches.find(filePath); - if (it == _audioCaches.end()) { - audioCache = &_audioCaches[filePath]; - audioCache->_fileFullPath = FileUtils::getInstance()->fullPathForFilename(filePath); - unsigned int cacheId = audioCache->_id; - auto isCacheDestroyed = audioCache->_isDestroyed; - AudioEngine::addTask([audioCache, cacheId, isCacheDestroyed](){ - if (*isCacheDestroyed) - { - ALOGV("AudioCache (id=%u) was destroyed, no need to launch readDataTask.", cacheId); - audioCache->setSkipReadDataTask(true); - return; - } - audioCache->readDataTask(cacheId); - }); - } - else { - audioCache = &it->second; - } - - if (audioCache && callback) - { - audioCache->addLoadCallback(callback); - } - return audioCache; -} - -int AudioEngineImpl::play2d(const std::string &filePath ,bool loop ,float volume) -{ - if (s_ALDevice == nullptr) { - return AudioEngine::INVALID_AUDIO_ID; - } - - ALuint alSource = findValidSource(); - if (alSource == AL_INVALID) - { - return AudioEngine::INVALID_AUDIO_ID; - } - - auto player = new (std::nothrow) AudioPlayer; - if (player == nullptr) { - return AudioEngine::INVALID_AUDIO_ID; - } - - player->_alSource = alSource; - player->_loop = loop; - player->_volume = volume; - - auto audioCache = preload(filePath, nullptr); - if (audioCache == nullptr) { - delete player; - return AudioEngine::INVALID_AUDIO_ID; - } - - player->setCache(audioCache); - _threadMutex.lock(); - _audioPlayers[_currentAudioID] = player; - _threadMutex.unlock(); - - audioCache->addPlayCallback(std::bind(&AudioEngineImpl::_play2d,this,audioCache,_currentAudioID)); - - if (_lazyInitLoop) { - _lazyInitLoop = false; - _scheduler->schedule(CC_SCHEDULE_SELECTOR(AudioEngineImpl::update), this, 0.05f, false); - } - - return _currentAudioID++; -} - -void AudioEngineImpl::_play2d(AudioCache *cache, int audioID) -{ - //Note: It maybe in sub thread or main thread :( - if (!*cache->_isDestroyed && cache->_state == AudioCache::State::READY) - { - _threadMutex.lock(); - auto playerIt = _audioPlayers.find(audioID); - if (playerIt != _audioPlayers.end() && playerIt->second->play2d()) { - _scheduler->performFunctionInCocosThread([audioID](){ - - if (AudioEngine::_audioIDInfoMap.find(audioID) != AudioEngine::_audioIDInfoMap.end()) { - AudioEngine::_audioIDInfoMap[audioID].state = AudioEngine::AudioState::PLAYING; - } - }); - } - _threadMutex.unlock(); - } - else - { - ALOGD("AudioEngineImpl::_play2d, cache was destroyed or not ready!"); - auto iter = _audioPlayers.find(audioID); - if (iter != _audioPlayers.end()) - { - iter->second->_removeByAudioEngine = true; - } - } -} - -ALuint AudioEngineImpl::findValidSource() -{ - ALuint sourceId = AL_INVALID; - if (!_unusedSourcesPool.empty()) - { - sourceId = _unusedSourcesPool.front(); - _unusedSourcesPool.pop_front(); - } - - return sourceId; -} - -void AudioEngineImpl::setVolume(int audioID,float volume) -{ - auto player = _audioPlayers[audioID]; - player->_volume = volume; - - if (player->_ready) { - alSourcef(_audioPlayers[audioID]->_alSource, AL_GAIN, volume); - - auto error = alGetError(); - if (error != AL_NO_ERROR) { - ALOGE("%s: audio id = %d, error = %x", __PRETTY_FUNCTION__,audioID,error); - } - } -} - -void AudioEngineImpl::setLoop(int audioID, bool loop) -{ - auto player = _audioPlayers[audioID]; - - if (player->_ready) { - if (player->_streamingSource) { - player->setLoop(loop); - } else { - if (loop) { - alSourcei(player->_alSource, AL_LOOPING, AL_TRUE); - } else { - alSourcei(player->_alSource, AL_LOOPING, AL_FALSE); - } - - auto error = alGetError(); - if (error != AL_NO_ERROR) { - ALOGE("%s: audio id = %d, error = %x", __PRETTY_FUNCTION__,audioID,error); - } - } - } - else { - player->_loop = loop; - } -} - -bool AudioEngineImpl::pause(int audioID) -{ - bool ret = true; - alSourcePause(_audioPlayers[audioID]->_alSource); - - auto error = alGetError(); - if (error != AL_NO_ERROR) { - ret = false; - ALOGE("%s: audio id = %d, error = %x", __PRETTY_FUNCTION__,audioID,error); - } - - return ret; -} - -bool AudioEngineImpl::resume(int audioID) -{ - bool ret = true; - alSourcePlay(_audioPlayers[audioID]->_alSource); - - auto error = alGetError(); - if (error != AL_NO_ERROR) { - ret = false; - ALOGE("%s: audio id = %d, error = %x", __PRETTY_FUNCTION__,audioID,error); - } - - return ret; -} - -void AudioEngineImpl::stop(int audioID) -{ - auto player = _audioPlayers[audioID]; - player->destroy(); - - // Call 'update' method to cleanup immediately since the schedule may be cancelled without any notification. - update(0.0f); -} - -void AudioEngineImpl::stopAll() -{ - for(auto&& player : _audioPlayers) - { - player.second->destroy(); - } - - // Call 'update' method to cleanup immediately since the schedule may be cancelled without any notification. - update(0.0f); -} - -float AudioEngineImpl::getDuration(int audioID) -{ - auto player = _audioPlayers[audioID]; - if(player->_ready){ - return player->_audioCache->_duration; - } else { - return AudioEngine::TIME_UNKNOWN; - } -} - -float AudioEngineImpl::getCurrentTime(int audioID) -{ - float ret = 0.0f; - auto player = _audioPlayers[audioID]; - if(player->_ready){ - if (player->_streamingSource) { - ret = player->getTime(); - } else { - alGetSourcef(player->_alSource, AL_SEC_OFFSET, &ret); - - auto error = alGetError(); - if (error != AL_NO_ERROR) { - ALOGE("%s, audio id:%d,error code:%x", __PRETTY_FUNCTION__,audioID,error); - } - } - } - - return ret; -} - -bool AudioEngineImpl::setCurrentTime(int audioID, float time) -{ - bool ret = false; - auto player = _audioPlayers[audioID]; - - do { - if (!player->_ready) { - break; - } - - if (player->_streamingSource) { - ret = player->setTime(time); - break; - } - else { - if (player->_audioCache->_framesRead != player->_audioCache->_totalFrames && - (time * player->_audioCache->_sampleRate) > player->_audioCache->_framesRead) { - ALOGE("%s: audio id = %d", __PRETTY_FUNCTION__,audioID); - break; - } - - alSourcef(player->_alSource, AL_SEC_OFFSET, time); - - auto error = alGetError(); - if (error != AL_NO_ERROR) { - ALOGE("%s: audio id = %d, error = %x", __PRETTY_FUNCTION__,audioID,error); - } - ret = true; - } - } while (0); - - return ret; -} - -void AudioEngineImpl::setFinishCallback(int audioID, const std::function &callback) -{ - _audioPlayers[audioID]->_finishCallbak = callback; -} - -void AudioEngineImpl::update(float dt) -{ - ALint sourceState; - int audioID; - AudioPlayer* player; - ALuint alSource; - -// ALOGV("AudioPlayer count: %d", (int)_audioPlayers.size()); - - for (auto it = _audioPlayers.begin(); it != _audioPlayers.end(); ) { - audioID = it->first; - player = it->second; - alSource = player->_alSource; - alGetSourcei(alSource, AL_SOURCE_STATE, &sourceState); - - if (player->_removeByAudioEngine) - { - AudioEngine::remove(audioID); - _threadMutex.lock(); - it = _audioPlayers.erase(it); - _threadMutex.unlock(); - delete player; - _unusedSourcesPool.push_back(alSource); - } - else if (player->_ready && sourceState == AL_STOPPED) { - - std::string filePath; - if (player->_finishCallbak) { - auto& audioInfo = AudioEngine::_audioIDInfoMap[audioID]; - filePath = audioInfo.filePath; - } - - AudioEngine::remove(audioID); - _threadMutex.lock(); - it = _audioPlayers.erase(it); - _threadMutex.unlock(); - - if (player->_finishCallbak) { - player->_finishCallbak(audioID, filePath); //FIXME: callback will delay 50ms - } - - delete player; - _unusedSourcesPool.push_back(alSource); - } - else{ - ++it; - } - } - - if(_audioPlayers.empty()){ - _lazyInitLoop = true; - _scheduler->unschedule(CC_SCHEDULE_SELECTOR(AudioEngineImpl::update), this); - } -} - -void AudioEngineImpl::uncache(const std::string &filePath) -{ - _audioCaches.erase(filePath); -} - -void AudioEngineImpl::uncacheAll() -{ - _audioCaches.clear(); -} diff --git a/cocos/audio/apple/AudioMacros.h b/cocos/audio/apple/AudioMacros.h deleted file mode 100644 index 6e623f0..0000000 --- a/cocos/audio/apple/AudioMacros.h +++ /dev/null @@ -1,65 +0,0 @@ -/**************************************************************************** - Copyright (c) 2016 Chukong Technologies Inc. - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -#pragma once - -#define QUEUEBUFFER_NUM (3) -#define QUEUEBUFFER_TIME_STEP (0.05f) - -#define QUOTEME_(x) #x -#define QUOTEME(x) QUOTEME_(x) - -#if defined(COCOS2D_DEBUG) && COCOS2D_DEBUG > 0 -#define ALOGV(fmt, ...) printf("V/" LOG_TAG " (" QUOTEME(__LINE__) "): " fmt "\n", ##__VA_ARGS__) -#else -#define ALOGV(fmt, ...) do {} while(false) -#endif -#define ALOGD(fmt, ...) printf("D/" LOG_TAG " (" QUOTEME(__LINE__) "): " fmt "\n", ##__VA_ARGS__) -#define ALOGI(fmt, ...) printf("I/" LOG_TAG " (" QUOTEME(__LINE__) "): " fmt "\n", ##__VA_ARGS__) -#define ALOGW(fmt, ...) printf("W/" LOG_TAG " (" QUOTEME(__LINE__) "): " fmt "\n", ##__VA_ARGS__) -#define ALOGE(fmt, ...) printf("E/" LOG_TAG " (" QUOTEME(__LINE__) "): " fmt "\n", ##__VA_ARGS__) - -#if defined(COCOS2D_DEBUG) && COCOS2D_DEBUG > 0 -#define CHECK_AL_ERROR_DEBUG() \ -do { \ - auto __error = alGetError(); \ - if (__error) { \ - ALOGE("OpenAL error 0x%04X in %s %s %d\n", __error, __FILE__, __FUNCTION__, __LINE__); \ - } \ -} while (false) -#else -#define CHECK_AL_ERROR_DEBUG() -#endif - -#define BREAK_IF(condition) \ - if (!!(condition)) { \ - break; \ - } - -#define BREAK_IF_ERR_LOG(condition, fmt, ...) \ - if (!!(condition)) { \ - ALOGE("(" QUOTEME(condition) ") failed, message: " fmt, ##__VA_ARGS__); \ - break; \ - } diff --git a/cocos/audio/apple/AudioPlayer.h b/cocos/audio/apple/AudioPlayer.h deleted file mode 100644 index b88cf3f..0000000 --- a/cocos/audio/apple/AudioPlayer.h +++ /dev/null @@ -1,90 +0,0 @@ -/**************************************************************************** - Copyright (c) 2014-2016 Chukong Technologies Inc. - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -#pragma once - -#include "platform/CCPlatformMacros.h" -#include "audio/apple/AudioMacros.h" - -#include -#include -#include -#include -#include - -NS_CC_BEGIN - -class AudioCache; -class AudioEngineImpl; - -class AudioPlayer -{ -public: - AudioPlayer(); - ~AudioPlayer(); - - void destroy(); - - //queue buffer related stuff - bool setTime(float time); - float getTime() { return _currTime;} - bool setLoop(bool loop); - -protected: - void setCache(AudioCache* cache); - void rotateBufferThread(int offsetFrame); - bool play2d(); - void wakeupRotateThread(); - - AudioCache* _audioCache; - - float _volume; - bool _loop; - std::function _finishCallbak; - - bool _isDestroyed; - bool _removeByAudioEngine; - bool _ready; - ALuint _alSource; - - //play by circular buffer - float _currTime; - bool _streamingSource; - ALuint _bufferIds[QUEUEBUFFER_NUM]; - std::thread* _rotateBufferThread; - std::condition_variable _sleepCondition; - std::mutex _sleepMutex; - bool _timeDirty; - bool _isRotateThreadExited; - std::atomic_bool _needWakeupRotateThread; - - std::mutex _play2dMutex; - - unsigned int _id; - - friend class AudioEngineImpl; -}; - -NS_CC_END diff --git a/cocos/audio/apple/AudioPlayer.mm b/cocos/audio/apple/AudioPlayer.mm deleted file mode 100644 index cd97915..0000000 --- a/cocos/audio/apple/AudioPlayer.mm +++ /dev/null @@ -1,369 +0,0 @@ -/**************************************************************************** - Copyright (c) 2014-2016 Chukong Technologies Inc. - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -#define LOG_TAG "AudioPlayer" - -#import - -#include "audio/apple/AudioPlayer.h" -#include "audio/apple/AudioCache.h" -#include "platform/CCFileUtils.h" -#include "audio/apple/AudioDecoder.h" - -#ifdef VERY_VERY_VERBOSE_LOGGING -#define ALOGVV ALOGV -#else -#define ALOGVV(...) do{} while(false) -#endif - -using namespace cocos2d; - -namespace { -unsigned int __idIndex = 0; -} - -AudioPlayer::AudioPlayer() -: _audioCache(nullptr) -, _finishCallbak(nullptr) -, _isDestroyed(false) -, _removeByAudioEngine(false) -, _ready(false) -, _currTime(0.0f) -, _streamingSource(false) -, _rotateBufferThread(nullptr) -, _timeDirty(false) -, _isRotateThreadExited(false) -, _needWakeupRotateThread(false) -, _id(++__idIndex) -{ - memset(_bufferIds, 0, sizeof(_bufferIds)); -} - -AudioPlayer::~AudioPlayer() -{ - ALOGVV("~AudioPlayer() (%p), id=%u", this, _id); - destroy(); - - if (_streamingSource) - { - alDeleteBuffers(QUEUEBUFFER_NUM, _bufferIds); - } -} - -void AudioPlayer::destroy() -{ - if (_isDestroyed) - return; - - ALOGVV("AudioPlayer::destroy begin, id=%u", _id); - - _isDestroyed = true; - - do - { - if (_audioCache != nullptr) - { - if (_audioCache->_state == AudioCache::State::INITIAL) - { - ALOGV("AudioPlayer::destroy, id=%u, cache isn't ready!", _id); - break; - } - - while (!_audioCache->_isLoadingFinished) - { - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - } - } - - // Wait for play2d to be finished. - _play2dMutex.lock(); - _play2dMutex.unlock(); - - if (_streamingSource) - { - if (_rotateBufferThread != nullptr) - { - while (!_isRotateThreadExited) - { - _sleepCondition.notify_one(); - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - } - - if (_rotateBufferThread->joinable()) { - _rotateBufferThread->join(); - } - - delete _rotateBufferThread; - _rotateBufferThread = nullptr; - ALOGVV("rotateBufferThread exited!"); - -#if CC_TARGET_PLATFORM == CC_PLATFORM_IOS - // some specific OpenAL implement defects existed on iOS platform - // refer to: https://github.com/cocos2d/cocos2d-x/issues/18597 - ALint sourceState; - ALint bufferProcessed = 0; - alGetSourcei(_alSource, AL_SOURCE_STATE, &sourceState); - if (sourceState == AL_PLAYING) { - alGetSourcei(_alSource, AL_BUFFERS_PROCESSED, &bufferProcessed); - while (bufferProcessed < QUEUEBUFFER_NUM) { - std::this_thread::sleep_for(std::chrono::milliseconds(2)); - alGetSourcei(_alSource, AL_BUFFERS_PROCESSED, &bufferProcessed); - } - alSourceUnqueueBuffers(_alSource, QUEUEBUFFER_NUM, _bufferIds); CHECK_AL_ERROR_DEBUG(); - } - ALOGVV("UnqueueBuffers Before alSourceStop"); -#endif - } - } - } while(false); - - ALOGVV("Before alSourceStop"); - alSourceStop(_alSource); CHECK_AL_ERROR_DEBUG(); - ALOGVV("Before alSourcei"); - alSourcei(_alSource, AL_BUFFER, 0); CHECK_AL_ERROR_DEBUG(); - - _removeByAudioEngine = true; - - _ready = false; - ALOGVV("AudioPlayer::destroy end, id=%u", _id); -} - -void AudioPlayer::setCache(AudioCache* cache) -{ - _audioCache = cache; -} - -bool AudioPlayer::play2d() -{ - _play2dMutex.lock(); - ALOGVV("AudioPlayer::play2d, _alSource: %u", _alSource); - - /*********************************************************************/ - /* Note that it may be in sub thread or in main thread. **/ - /*********************************************************************/ - bool ret = false; - do - { - if (_audioCache->_state != AudioCache::State::READY) - { - ALOGE("alBuffer isn't ready for play!"); - break; - } - - alSourcei(_alSource, AL_BUFFER, 0);CHECK_AL_ERROR_DEBUG(); - alSourcef(_alSource, AL_PITCH, 1.0f);CHECK_AL_ERROR_DEBUG(); - alSourcef(_alSource, AL_GAIN, _volume);CHECK_AL_ERROR_DEBUG(); - alSourcei(_alSource, AL_LOOPING, AL_FALSE);CHECK_AL_ERROR_DEBUG(); - - if (_audioCache->_queBufferFrames == 0) - { - if (_loop) { - alSourcei(_alSource, AL_LOOPING, AL_TRUE); - CHECK_AL_ERROR_DEBUG(); - } - } - else - { - alGenBuffers(QUEUEBUFFER_NUM, _bufferIds); - - auto alError = alGetError(); - if (alError == AL_NO_ERROR) - { - for (int index = 0; index < QUEUEBUFFER_NUM; ++index) - { - alBufferData(_bufferIds[index], _audioCache->_format, _audioCache->_queBuffers[index], _audioCache->_queBufferSize[index], _audioCache->_sampleRate); - } - CHECK_AL_ERROR_DEBUG(); - } - else - { - ALOGE("%s:alGenBuffers error code:%x", __PRETTY_FUNCTION__,alError); - break; - } - _streamingSource = true; - } - - { - std::unique_lock lk(_sleepMutex); - if (_isDestroyed) - break; - - if (_streamingSource) - { - // To continuously stream audio from a source without interruption, buffer queuing is required. - alSourceQueueBuffers(_alSource, QUEUEBUFFER_NUM, _bufferIds); - CHECK_AL_ERROR_DEBUG(); - _rotateBufferThread = new std::thread(&AudioPlayer::rotateBufferThread, this, _audioCache->_queBufferFrames * QUEUEBUFFER_NUM + 1); - } - else - { - alSourcei(_alSource, AL_BUFFER, _audioCache->_alBufferId); - CHECK_AL_ERROR_DEBUG(); - } - - alSourcePlay(_alSource); - } - - auto alError = alGetError(); - if (alError != AL_NO_ERROR) - { - ALOGE("%s:alSourcePlay error code:%x", __PRETTY_FUNCTION__,alError); - break; - } - - ALint state; - alGetSourcei(_alSource, AL_SOURCE_STATE, &state); - assert(state == AL_PLAYING); - _ready = true; - ret = true; - } while (false); - - if (!ret) - { - _removeByAudioEngine = true; - } - - _play2dMutex.unlock(); - return ret; -} - -// rotateBufferThread is used to rotate alBufferData for _alSource when playing big audio file -void AudioPlayer::rotateBufferThread(int offsetFrame) -{ - char* tmpBuffer = nullptr; - AudioDecoder decoder; - long long rotateSleepTime = static_cast(QUEUEBUFFER_TIME_STEP * 1000) / 2; - do - { - BREAK_IF(!decoder.open(_audioCache->_fileFullPath.c_str())); - - uint32_t framesRead = 0; - const uint32_t framesToRead = _audioCache->_queBufferFrames; - const uint32_t bufferSize = framesToRead * decoder.getBytesPerFrame(); - tmpBuffer = (char*)malloc(bufferSize); - memset(tmpBuffer, 0, bufferSize); - - if (offsetFrame != 0) { - decoder.seek(offsetFrame); - } - - ALint sourceState; - ALint bufferProcessed = 0; - bool needToExitThread = false; - - while (!_isDestroyed) { - alGetSourcei(_alSource, AL_SOURCE_STATE, &sourceState); - if (sourceState == AL_PLAYING) { - alGetSourcei(_alSource, AL_BUFFERS_PROCESSED, &bufferProcessed); - while (bufferProcessed > 0) { - bufferProcessed--; - if (_timeDirty) { - _timeDirty = false; - offsetFrame = _currTime * decoder.getSampleRate(); - decoder.seek(offsetFrame); - } - else { - _currTime += QUEUEBUFFER_TIME_STEP; - if (_currTime > _audioCache->_duration) { - if (_loop) { - _currTime = 0.0f; - } else { - _currTime = _audioCache->_duration; - } - } - } - - framesRead = decoder.readFixedFrames(framesToRead, tmpBuffer); - - if (framesRead == 0) { - if (_loop) { - decoder.seek(0); - framesRead = decoder.readFixedFrames(framesToRead, tmpBuffer); - } else { - needToExitThread = true; - break; - } - } - /* - While the source is playing, alSourceUnqueueBuffers can be called to remove buffers which have - already played. Those buffers can then be filled with new data or discarded. New or refilled - buffers can then be attached to the playing source using alSourceQueueBuffers. As long as there is - always a new buffer to play in the queue, the source will continue to play. - */ - ALuint bid; - alSourceUnqueueBuffers(_alSource, 1, &bid); - alBufferData(bid, _audioCache->_format, tmpBuffer, framesRead * decoder.getBytesPerFrame(), decoder.getSampleRate()); - alSourceQueueBuffers(_alSource, 1, &bid); - } - } - - std::unique_lock lk(_sleepMutex); - if (_isDestroyed || needToExitThread) { - break; - } - - if (!_needWakeupRotateThread) - { - _sleepCondition.wait_for(lk,std::chrono::milliseconds(rotateSleepTime)); - } - - _needWakeupRotateThread = false; - } - - } while(false); - - ALOGVV("Exit rotate buffer thread ..."); - decoder.close(); - free(tmpBuffer); - _isRotateThreadExited = true; -} - -void AudioPlayer::wakeupRotateThread() -{ - _needWakeupRotateThread = true; - _sleepCondition.notify_all(); -} - -bool AudioPlayer::setLoop(bool loop) -{ - if (!_isDestroyed ) { - _loop = loop; - return true; - } - - return false; -} - -bool AudioPlayer::setTime(float time) -{ - if (!_isDestroyed && time >= 0.0f && time < _audioCache->_duration) { - - _currTime = time; - _timeDirty = true; - - return true; - } - return false; -} diff --git a/cocos/audio/include/AudioEngine.h b/cocos/audio/include/AudioEngine.h deleted file mode 100644 index f72eb59..0000000 --- a/cocos/audio/include/AudioEngine.h +++ /dev/null @@ -1,372 +0,0 @@ -/**************************************************************************** - Copyright (c) 2014-2016 Chukong Technologies Inc. - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ -#pragma once - -#include -#include -#include -#include - -#include "platform/CCPlatformConfig.h" -#include "platform/CCPlatformMacros.h" -#include "audio/include/Export.h" - -#ifdef ERROR -#undef ERROR -#endif // ERROR - -/** - * @addtogroup audio - * @{ - */ - -NS_CC_BEGIN -/** - * @class AudioProfile - * - * @brief - * @js NA - */ -class EXPORT_DLL AudioProfile -{ -public: - //Profile name can't be empty. - std::string name; - //The maximum number of simultaneous audio instance. - unsigned int maxInstances; - - /* Minimum delay in between sounds */ - double minDelay; - - /** - * Default constructor - * - * @lua new - */ - AudioProfile() - : maxInstances(0) - , minDelay(0.0) - { - - } -}; - -class AudioEngineImpl; - -/** - * @class AudioEngine - * - * @brief Offers a interface to play audio. - * - * @note Make sure to call AudioEngine::end() when the audio engine is not needed anymore to release resources. - * @js NA - */ - -class EXPORT_DLL AudioEngine -{ -public: - /** AudioState enum,all possible states of an audio instance.*/ - enum class AudioState - { - ERROR = -1, - INITIALIZING, - PLAYING, - PAUSED - }; - - static const int INVALID_AUDIO_ID; - - static const float TIME_UNKNOWN; - - static bool lazyInit(); - - /** - * Release objects relating to AudioEngine. - * - * @warning It must be called before the application exit. - * @lua endToLua - */ - static void end(); - - /** - * Gets the default profile of audio instances. - * - * @return The default profile of audio instances. - */ - static AudioProfile* getDefaultProfile(); - - /** - * Play 2d sound. - * - * @param filePath The path of an audio file. - * @param loop Whether audio instance loop or not. - * @param volume Volume value (range from 0.0 to 1.0). - * @param profile A profile for audio instance. When profile is not specified, default profile will be used. - * @return An audio ID. It allows you to dynamically change the behavior of an audio instance on the fly. - * - * @see `AudioProfile` - */ - static int play2d(const std::string& filePath, bool loop = false, float volume = 1.0f, const AudioProfile *profile = nullptr); - - /** - * Sets whether an audio instance loop or not. - * - * @param audioID An audioID returned by the play2d function. - * @param loop Whether audio instance loop or not. - */ - static void setLoop(int audioID, bool loop); - - /** - * Checks whether an audio instance is loop. - * - * @param audioID An audioID returned by the play2d function. - * @return Whether or not an audio instance is loop. - */ - static bool isLoop(int audioID); - - /** - * Sets volume for an audio instance. - * - * @param audioID An audioID returned by the play2d function. - * @param volume Volume value (range from 0.0 to 1.0). - */ - static void setVolume(int audioID, float volume); - - /** - * Gets the volume value of an audio instance. - * - * @param audioID An audioID returned by the play2d function. - * @return Volume value (range from 0.0 to 1.0). - */ - static float getVolume(int audioID); - - /** - * Pause an audio instance. - * - * @param audioID An audioID returned by the play2d function. - */ - static void pause(int audioID); - - /** Pause all playing audio instances. */ - static void pauseAll(); - - /** - * Resume an audio instance. - * - * @param audioID An audioID returned by the play2d function. - */ - static void resume(int audioID); - - /** Resume all suspended audio instances. */ - static void resumeAll(); - - /** - * Stop an audio instance. - * - * @param audioID An audioID returned by the play2d function. - */ - static void stop(int audioID); - - /** Stop all audio instances. */ - static void stopAll(); - - /** - * Sets the current playback position of an audio instance. - * - * @param audioID An audioID returned by the play2d function. - * @param sec The offset in seconds from the start to seek to. - * @return - */ - static bool setCurrentTime(int audioID, float sec); - - /** - * Gets the current playback position of an audio instance. - * - * @param audioID An audioID returned by the play2d function. - * @return The current playback position of an audio instance. - */ - static float getCurrentTime(int audioID); - - /** - * Gets the duration of an audio instance. - * - * @param audioID An audioID returned by the play2d function. - * @return The duration of an audio instance. - */ - static float getDuration(int audioID); - - /** - * Returns the state of an audio instance. - * - * @param audioID An audioID returned by the play2d function. - * @return The status of an audio instance. - */ - static AudioState getState(int audioID); - - /** - * Register a callback to be invoked when an audio instance has completed playing. - * - * @param audioID An audioID returned by the play2d function. - * @param callback - */ - static void setFinishCallback(int audioID, const std::function& callback); - - /** - * Gets the maximum number of simultaneous audio instance of AudioEngine. - */ - static int getMaxAudioInstance() {return _maxInstances;} - - /** - * Sets the maximum number of simultaneous audio instance for AudioEngine. - * - * @param maxInstances The maximum number of simultaneous audio instance. - */ - static bool setMaxAudioInstance(int maxInstances); - - /** - * Uncache the audio data from internal buffer. - * AudioEngine cache audio data on ios,mac, and win32 platform. - * - * @warning This can lead to stop related audio first. - * @param filePath Audio file path. - */ - static void uncache(const std::string& filePath); - - /** - * Uncache all audio data from internal buffer. - * - * @warning All audio will be stopped first. - */ - static void uncacheAll(); - - /** - * Gets the audio profile by id of audio instance. - * - * @param audioID An audioID returned by the play2d function. - * @return The audio profile. - */ - static AudioProfile* getProfile(int audioID); - - /** - * Gets an audio profile by name. - * - * @param profileName A name of audio profile. - * @return The audio profile. - */ - static AudioProfile* getProfile(const std::string &profileName); - - /** - * Preload audio file. - * @param filePath The file path of an audio. - */ - static void preload(const std::string& filePath) { preload(filePath, nullptr); } - - /** - * Preload audio file. - * @param filePath The file path of an audio. - * @param callback A callback which will be called after loading is finished. - */ - static void preload(const std::string& filePath, std::function callback); - - /** - * Gets playing audio count. - */ - static int getPlayingAudioCount(); - - /** - * Whether to enable playing audios - * @note If it's disabled, current playing audios will be stopped and the later 'preload', 'play2d' methods will take no effects. - */ - static void setEnabled(bool isEnabled); - /** - * Check whether AudioEngine is enabled. - */ - static bool isEnabled(); - -protected: - static void addTask(const std::function& task); - static void remove(int audioID); - - struct ProfileHelper - { - AudioProfile profile; - - std::list audioIDs; - - double lastPlayTime; - - ProfileHelper() - : lastPlayTime(0.0) - { - - } - }; - - struct AudioInfo - { - std::string filePath; - ProfileHelper* profileHelper; - - float volume; - bool loop; - float duration; - AudioState state; - - AudioInfo(); - ~AudioInfo(); - private: - AudioInfo(const AudioInfo& info); - AudioInfo(AudioInfo&& info); - AudioInfo& operator=(const AudioInfo& info); - AudioInfo& operator=(AudioInfo&& info); - }; - - //audioID,audioAttribute - static std::unordered_map _audioIDInfoMap; - - //audio file path,audio IDs - static std::unordered_map> _audioPathIDMap; - - //profileName,ProfileHelper - static std::unordered_map _audioPathProfileHelperMap; - - static unsigned int _maxInstances; - - static ProfileHelper* _defaultProfileHelper; - - static AudioEngineImpl* _audioEngineImpl; - - class AudioEngineThreadPool; - static AudioEngineThreadPool* s_threadPool; - - static bool _isEnabled; - - friend class AudioEngineImpl; -}; - -NS_CC_END - -// end group -/// @} diff --git a/cocos/audio/include/Export.h b/cocos/audio/include/Export.h deleted file mode 100644 index 5ac04cd..0000000 --- a/cocos/audio/include/Export.h +++ /dev/null @@ -1,52 +0,0 @@ -/**************************************************************************** -Copyright (c) 2010-2012 cocos2d-x.org -Copyright (c) 2013-2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ -#ifndef __EXPORT_COMMON__ -#define __EXPORT_COMMON__ - -#if defined(SHP) - #include - #define EXPORT_DLL _EXPORT_ -#elif defined(_WIN32) - #if defined(CC_STATIC) - #define EXPORT_DLL - #else - #if defined(_EXPORT_DLL_) - #define EXPORT_DLL __declspec(dllexport) - #else /* use a DLL library */ - #define EXPORT_DLL __declspec(dllimport) - #endif - #endif -#else - #if defined(_SHARED_) - #define EXPORT_DLL __attribute__((visibility("default"))) - #elif defined(IGNORE_EXPORT) - #define EXPORT_DLL - #else - #define EXPORT_DLL - #endif -#endif - -#endif // end of __EXPORT_COMMON__ diff --git a/cocos/audio/linux/AudioEngine-linux.cpp b/cocos/audio/linux/AudioEngine-linux.cpp deleted file mode 100644 index 80b886d..0000000 --- a/cocos/audio/linux/AudioEngine-linux.cpp +++ /dev/null @@ -1,357 +0,0 @@ -/**************************************************************************** - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -/** - * @author cesarpachon - */ -#include -#include -#include "audio/linux/AudioEngine-linux.h" - -#include "base/CCDirector.h" -#include "base/CCScheduler.h" -#include "platform/CCFileUtils.h" - -using namespace cocos2d; - -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->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(CC_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; - // channel is null here. Don't dereference it. It's only set in resume(id). - //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(static_cast(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 &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(reinterpret_cast(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::const_iterator it = mapSound.find(fullPath); - if (it!=mapSound.end()) { - FMOD::Sound * sound = it->second; - if (sound) { - sound->release(); - } - mapSound.erase(it); - } - 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 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(mapChannelInfo.size()) + 1; - // std::map::insert returns std::pair - auto channelInfoIter = mapId.insert({filePath, id}); - id = channelInfoIter.first->second; - - 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(static_cast(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::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(reinterpret_cast(data)); - return mapChannelInfo[id].channel; -} diff --git a/cocos/audio/linux/AudioEngine-linux.h b/cocos/audio/linux/AudioEngine-linux.h deleted file mode 100644 index 06c5659..0000000 --- a/cocos/audio/linux/AudioEngine-linux.h +++ /dev/null @@ -1,109 +0,0 @@ -/**************************************************************************** - Copyright (c) 2015-2016 Chukong Technologies Inc. - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ -#include "platform/CCPlatformConfig.h" - -#if CC_TARGET_PLATFORM == CC_PLATFORM_LINUX - -#ifndef __AUDIO_ENGINE_LINUX_H_ -#define __AUDIO_ENGINE_LINUX_H_ - -#include -#include -#include -#include "fmod.hpp" -#include "fmod_errors.h" -#include "audio/include/AudioEngine.h" - -#include "base/CCRef.h" - -NS_CC_BEGIN - -#define MAX_AUDIOINSTANCES 32 - -class CC_DLL AudioEngineImpl : public cocos2d::Ref -{ -public: - AudioEngineImpl(); - ~AudioEngineImpl(); - - bool init(); - int play2d(const std::string &fileFullPath ,bool loop ,float volume); - void setVolume(int audioID,float volume); - void setLoop(int audioID, bool loop); - bool pause(int audioID); - bool resume(int audioID); - bool stop(int audioID); - void stopAll(); - float getDuration(int audioID); - float getCurrentTime(int audioID); - bool setCurrentTime(int audioID, float time); - void setFinishCallback(int audioID, const std::function &callback); - - void uncache(const std::string& filePath); - void uncacheAll(); - - - int preload(const std::string& filePath, std::function callback); - - void update(float dt); - - /** - * used internally by ffmod callback - */ - void onSoundFinished(FMOD::Channel * channel); - -private: - - /** - * returns null if a sound with the given path is not found - */ - FMOD::Sound * findSound(const std::string &path); - - FMOD::Channel * getChannel(FMOD::Sound *); - - struct ChannelInfo{ - int id; - std::string path; - FMOD::Sound * sound; - FMOD::Channel * channel; - bool loop; - float volume; - std::function callback; - }; - - std::map mapChannelInfo; - - std::map mapId; - - std::map mapSound; - - FMOD::System* pSystem; - -}; - -NS_CC_END -#endif // __AUDIO_ENGINE_LINUX_H_ -#endif - diff --git a/cocos/audio/win32/AudioCache.cpp b/cocos/audio/win32/AudioCache.cpp deleted file mode 100644 index 702b6b6..0000000 --- a/cocos/audio/win32/AudioCache.cpp +++ /dev/null @@ -1,379 +0,0 @@ -/**************************************************************************** - Copyright (c) 2014-2016 Chukong Technologies Inc. - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -#define LOG_TAG "AudioCache" - -#include "platform/CCPlatformConfig.h" - -#if CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 - -#include "audio/win32/AudioCache.h" -#include -#include "base/CCDirector.h" -#include "base/CCScheduler.h" - -#include "audio/win32/AudioDecoderManager.h" -#include "audio/win32/AudioDecoder.h" - -#define VERY_VERY_VERBOSE_LOGGING -#ifdef VERY_VERY_VERBOSE_LOGGING -#define ALOGVV ALOGV -#else -#define ALOGVV(...) do{} while(false) -#endif - -namespace { -unsigned int __idIndex = 0; -} - -#define INVALID_AL_BUFFER_ID 0xFFFFFFFF -#define PCMDATA_CACHEMAXSIZE 1048576 - -using namespace cocos2d; - -AudioCache::AudioCache() -: _totalFrames(0) -, _framesRead(0) -, _format(-1) -, _duration(0.0f) -, _alBufferId(INVALID_AL_BUFFER_ID) -, _pcmData(nullptr) -, _queBufferFrames(0) -, _state(State::INITIAL) -, _isDestroyed(std::make_shared(false)) -, _id(++__idIndex) -, _isLoadingFinished(false) -, _isSkipReadDataTask(false) -{ - ALOGVV("AudioCache() %p, id=%u", this, _id); - for (int i = 0; i < QUEUEBUFFER_NUM; ++i) - { - _queBuffers[i] = nullptr; - _queBufferSize[i] = 0; - } -} - -AudioCache::~AudioCache() -{ - ALOGVV("~AudioCache() %p, id=%u, begin", this, _id); - *_isDestroyed = true; - while (!_isLoadingFinished) - { - if (_isSkipReadDataTask) - { - ALOGV("id=%u, Skip read data task, don't continue to wait!", _id); - break; - } - ALOGVV("id=%u, waiting readData thread to finish ...", _id); - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - } - //wait for the 'readDataTask' task to exit - _readDataTaskMutex.lock(); - _readDataTaskMutex.unlock(); - - if (_pcmData) - { - if (_state == State::READY) - { - if (_alBufferId != INVALID_AL_BUFFER_ID && alIsBuffer(_alBufferId)) - { - ALOGV("~AudioCache(id=%u), delete buffer: %u", _id, _alBufferId); - alDeleteBuffers(1, &_alBufferId); - _alBufferId = INVALID_AL_BUFFER_ID; - } - } - else - { - ALOGW("AudioCache (%p), id=%u, buffer isn't ready, state=%d", this, _id, _state); - } - - free(_pcmData); - } - - if (_queBufferFrames > 0) - { - for (int index = 0; index < QUEUEBUFFER_NUM; ++index) - { - free(_queBuffers[index]); - } - } - ALOGVV("~AudioCache() %p, id=%u, end", this, _id); -} - -void AudioCache::readDataTask(unsigned int selfId) -{ - //Note: It's in sub thread - ALOGVV("readDataTask begin, cache id=%u", selfId); - - _readDataTaskMutex.lock(); - _state = State::LOADING; - - AudioDecoder* decoder = AudioDecoderManager::createDecoder(_fileFullPath.c_str()); - do - { - if (decoder == nullptr || !decoder->open(_fileFullPath.c_str())) - break; - - const uint32_t originalTotalFrames = decoder->getTotalFrames(); - const uint32_t bytesPerFrame = decoder->getBytesPerFrame(); - const uint32_t sampleRate = decoder->getSampleRate(); - const uint32_t channelCount = decoder->getChannelCount(); - - uint32_t totalFrames = originalTotalFrames; - uint32_t dataSize = totalFrames * bytesPerFrame; - uint32_t remainingFrames = totalFrames; - uint32_t adjustFrames = 0; - - _format = channelCount > 1 ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16; - _sampleRate = (ALsizei)sampleRate; - _duration = 1.0f * totalFrames / sampleRate; - _totalFrames = totalFrames; - - if (dataSize <= PCMDATA_CACHEMAXSIZE) - { - uint32_t framesRead = 0; - const uint32_t framesToReadOnce = std::min(totalFrames, static_cast(sampleRate * QUEUEBUFFER_TIME_STEP * QUEUEBUFFER_NUM)); - - std::vector adjustFrameBuf; - - if (decoder->seek(totalFrames)) - { - char* tmpBuf = (char*)malloc(framesToReadOnce * bytesPerFrame); - adjustFrameBuf.reserve(framesToReadOnce * bytesPerFrame); - - // Adjust total frames by setting position to the end of frames and try to read more data. - // This is a workaround for https://github.com/cocos2d/cocos2d-x/issues/16938 - do - { - framesRead = decoder->read(framesToReadOnce, tmpBuf); - if (framesRead > 0) - { - adjustFrames += framesRead; - adjustFrameBuf.insert(adjustFrameBuf.end(), tmpBuf, tmpBuf + framesRead * bytesPerFrame); - } - - } while (framesRead > 0); - - if (adjustFrames > 0) - { - ALOGV("Orignal total frames: %u, adjust frames: %u, current total frames: %u", totalFrames, adjustFrames, totalFrames + adjustFrames); - totalFrames += adjustFrames; - _totalFrames = remainingFrames = totalFrames; - } - - // Reset dataSize - dataSize = totalFrames * bytesPerFrame; - - free(tmpBuf); - } - // Reset to frame 0 - BREAK_IF_ERR_LOG(!decoder->seek(0), "AudioDecoder::seek(0) failed!"); - - _pcmData = (char*)malloc(dataSize); - memset(_pcmData, 0x00, dataSize); - - if (adjustFrames > 0) - { - memcpy(_pcmData + (dataSize - adjustFrameBuf.size()), adjustFrameBuf.data(), adjustFrameBuf.size()); - } - - alGenBuffers(1, &_alBufferId); - auto alError = alGetError(); - if (alError != AL_NO_ERROR) { - ALOGE("%s: attaching audio to buffer fail: %x", __FUNCTION__, alError); - break; - } - - if (*_isDestroyed) - break; - - framesRead = decoder->readFixedFrames(std::min(framesToReadOnce, remainingFrames), _pcmData + _framesRead * bytesPerFrame); - _framesRead += framesRead; - remainingFrames -= framesRead; - - if (*_isDestroyed) - break; - - uint32_t frames = 0; - while (!*_isDestroyed && _framesRead < originalTotalFrames) - { - frames = std::min(framesToReadOnce, remainingFrames); - if (_framesRead + frames > originalTotalFrames) - { - frames = originalTotalFrames - _framesRead; - } - framesRead = decoder->read(frames, _pcmData + _framesRead * bytesPerFrame); - if (framesRead == 0) - break; - _framesRead += framesRead; - remainingFrames -= framesRead; - } - - if (*_isDestroyed) - break; - - if (_framesRead < originalTotalFrames) - { - memset(_pcmData + _framesRead * bytesPerFrame, 0x00, (totalFrames - _framesRead) * bytesPerFrame); - } - ALOGV("pcm buffer was loaded successfully, total frames: %u, total read frames: %u, adjust frames: %u, remainingFrames: %u", totalFrames, _framesRead, adjustFrames, remainingFrames); - - _framesRead += adjustFrames; - - alBufferData(_alBufferId, _format, _pcmData, (ALsizei)dataSize, (ALsizei)sampleRate); - - _state = State::READY; - } - else - { - _queBufferFrames = static_cast(sampleRate * QUEUEBUFFER_TIME_STEP); - BREAK_IF_ERR_LOG(_queBufferFrames == 0, "_queBufferFrames == 0"); - - const uint32_t queBufferBytes = _queBufferFrames * bytesPerFrame; - - for (int index = 0; index < QUEUEBUFFER_NUM; ++index) - { - _queBuffers[index] = (char*)malloc(queBufferBytes); - _queBufferSize[index] = queBufferBytes; - - decoder->readFixedFrames(_queBufferFrames, _queBuffers[index]); - } - - _state = State::READY; - } - - } while (false); - - if (decoder != nullptr) - { - decoder->close(); - } - - AudioDecoderManager::destroyDecoder(decoder); - - if (_state != State::READY) - { - _state = State::FAILED; - if (_alBufferId != INVALID_AL_BUFFER_ID && alIsBuffer(_alBufferId)) - { - ALOGV("readDataTask failed, delete buffer: %u", _alBufferId); - alDeleteBuffers(1, &_alBufferId); - _alBufferId = INVALID_AL_BUFFER_ID; - } - } - - //FIXME: Why to invoke play callback first? Should it be after 'load' callback? - invokingPlayCallbacks(); - invokingLoadCallbacks(); - - _isLoadingFinished = true; - _readDataTaskMutex.unlock(); - ALOGVV("readDataTask end, cache id=%u", selfId); -} - -void AudioCache::addPlayCallback(const std::function& callback) -{ - std::lock_guard lk(_playCallbackMutex); - switch (_state) - { - case State::INITIAL: - case State::LOADING: - _playCallbacks.push_back(callback); - break; - - case State::READY: - // If state is failure, we still need to invoke the callback - // since the callback will set the 'AudioPlayer::_removeByAudioEngine' flag to true. - case State::FAILED: - callback(); - break; - - default: - ALOGE("Invalid state: %d", _state); - break; - } -} - -void AudioCache::invokingPlayCallbacks() -{ - std::lock_guard lk(_playCallbackMutex); - - for (auto&& cb : _playCallbacks) - { - cb(); - } - - _playCallbacks.clear(); -} - -void AudioCache::addLoadCallback(const std::function& callback) -{ - switch (_state) - { - case State::INITIAL: - case State::LOADING: - _loadCallbacks.push_back(callback); - break; - - case State::READY: - callback(true); - break; - case State::FAILED: - callback(false); - break; - - default: - ALOGE("Invalid state: %d", _state); - break; - } -} - -void AudioCache::invokingLoadCallbacks() -{ - if (*_isDestroyed) - { - ALOGV("AudioCache (%p) was destroyed, don't invoke preload callback ...", this); - return; - } - - auto isDestroyed = _isDestroyed; - auto scheduler = Director::getInstance()->getScheduler(); - scheduler->performFunctionInCocosThread([&, isDestroyed](){ - if (*isDestroyed) - { - ALOGV("invokingLoadCallbacks perform in cocos thread, AudioCache (%p) was destroyed!", this); - return; - } - - for (auto&& cb : _loadCallbacks) - { - cb(_state == State::READY); - } - - _loadCallbacks.clear(); - }); -} - -#endif diff --git a/cocos/audio/win32/AudioCache.h b/cocos/audio/win32/AudioCache.h deleted file mode 100644 index cb75fe9..0000000 --- a/cocos/audio/win32/AudioCache.h +++ /dev/null @@ -1,119 +0,0 @@ -/**************************************************************************** - Copyright (c) 2014-2016 Chukong Technologies Inc. - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -#pragma once - -#include "platform/CCPlatformConfig.h" - -#if CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 - -#include -#include -#include -#include -#include -#ifdef OPENAL_PLAIN_INCLUDES -#include -#else -#include -#endif -#include "platform/CCPlatformMacros.h" -#include "audio/win32/AudioMacros.h" - -NS_CC_BEGIN - -class AudioEngineImpl; -class AudioPlayer; - -class CC_DLL AudioCache -{ -public: - - enum class State - { - INITIAL, - LOADING, - READY, - FAILED - }; - - AudioCache(); - ~AudioCache(); - - void addPlayCallback(const std::function& callback); - - void addLoadCallback(const std::function& callback); - -protected: - void setSkipReadDataTask(bool isSkip) { _isSkipReadDataTask = isSkip; }; - void readDataTask(unsigned int selfId); - - void invokingPlayCallbacks(); - - void invokingLoadCallbacks(); - - //pcm data related stuff - ALenum _format; - ALsizei _sampleRate; - float _duration; - uint32_t _totalFrames; - uint32_t _framesRead; - - /*Cache related stuff; - * Cache pcm data when sizeInBytes less than PCMDATA_CACHEMAXSIZE - */ - ALuint _alBufferId; - char* _pcmData; - - /*Queue buffer related stuff - * Streaming in OpenAL when sizeInBytes greater then PCMDATA_CACHEMAXSIZE - */ - char* _queBuffers[QUEUEBUFFER_NUM]; - ALsizei _queBufferSize[QUEUEBUFFER_NUM]; - uint32_t _queBufferFrames; - - std::mutex _playCallbackMutex; - std::vector< std::function > _playCallbacks; - - // loadCallbacks doesn't need mutex since it's invoked only in Cocos thread. - std::vector< std::function > _loadCallbacks; - - std::mutex _readDataTaskMutex; - - State _state; - - std::shared_ptr _isDestroyed; - std::string _fileFullPath; - unsigned int _id; - bool _isLoadingFinished; - bool _isSkipReadDataTask; - - friend class AudioEngineImpl; - friend class AudioPlayer; -}; - -NS_CC_END - -#endif diff --git a/cocos/audio/win32/AudioDecoder.cpp b/cocos/audio/win32/AudioDecoder.cpp deleted file mode 100644 index e05d1f9..0000000 --- a/cocos/audio/win32/AudioDecoder.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/**************************************************************************** - Copyright (c) 2016 Chukong Technologies Inc. - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -#include "audio/win32/AudioDecoder.h" -#include "audio/win32/AudioMacros.h" -#include "platform/CCFileUtils.h" - -#define LOG_TAG "AudioDecoder" - -namespace cocos2d { - -AudioDecoder::AudioDecoder() - : _isOpened(false) - , _totalFrames(0) - , _bytesPerFrame(0) - , _sampleRate(0) - , _channelCount(0) - { - - } - - AudioDecoder::~AudioDecoder() - { - } - - - bool AudioDecoder::isOpened() const - { - return _isOpened; - } - - uint32_t AudioDecoder::readFixedFrames(uint32_t framesToRead, char* pcmBuf) - { - uint32_t framesRead = 0; - uint32_t framesReadOnce = 0; - do - { - framesReadOnce = read(framesToRead - framesRead, pcmBuf + framesRead * _bytesPerFrame); - framesRead += framesReadOnce; - } while (framesReadOnce != 0 && framesRead < framesToRead); - - if (framesRead < framesToRead) - { - memset(pcmBuf + framesRead * _bytesPerFrame, 0x00, (framesToRead - framesRead) * _bytesPerFrame); - } - - return framesRead; - } - - uint32_t AudioDecoder::getTotalFrames() const - { - return _totalFrames; - } - - uint32_t AudioDecoder::getBytesPerFrame() const - { - return _bytesPerFrame; - } - - uint32_t AudioDecoder::getSampleRate() const - { - return _sampleRate; - } - - uint32_t AudioDecoder::getChannelCount() const - { - return _channelCount; - } - -} // namespace cocos2d { diff --git a/cocos/audio/win32/AudioDecoder.h b/cocos/audio/win32/AudioDecoder.h deleted file mode 100644 index ca466c9..0000000 --- a/cocos/audio/win32/AudioDecoder.h +++ /dev/null @@ -1,120 +0,0 @@ -/**************************************************************************** - Copyright (c) 2016 Chukong Technologies Inc. - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -#pragma once - -#include - -#include "vorbis/vorbisfile.h" - -namespace cocos2d { - -/** - * @brief The class for decoding compressed audio file to PCM buffer. - */ -class AudioDecoder -{ -public: - static const uint32_t INVALID_FRAME_INDEX = UINT32_MAX; - - /** - * @brief Opens an audio file specified by a file path. - * @return true if succeed, otherwise false. - */ - virtual bool open(const char* path) = 0; - - /** - * @brief Checks whether decoder has opened file successfully. - * @return true if succeed, otherwise false. - */ - virtual bool isOpened() const; - - /** - * @brief Closes opened audio file. - * @note The method will also be automatically invoked in the destructor. - */ - virtual void close() = 0; - - /** - * @brief Reads audio frames of PCM format. - * @param framesToRead The number of frames excepted to be read. - * @param pcmBuf The buffer to hold the frames to be read, its size should be >= |framesToRead| * _bytesPerFrame. - * @return The number of frames actually read, it's probably less than 'framesToRead'. Returns 0 means reach the end of file. - */ - virtual uint32_t read(uint32_t framesToRead, char* pcmBuf) = 0; - - /** - * @brief Reads fixed audio frames of PCM format. - * @param framesToRead The number of frames excepted to be read. - * @param pcmBuf The buffer to hold the frames to be read, its size should be >= |framesToRead| * _bytesPerFrame. - * @return The number of frames actually read, it's probably less than |framesToRead|. Returns 0 means reach the end of file. - * @note The different between |read| and |readFixedFrames| is |readFixedFrames| will do multiple reading operations if |framesToRead| frames - * isn't filled entirely, while |read| just does reading operation once whatever |framesToRead| is or isn't filled entirely. - * If current position reaches the end of frames, the return value may smaller than |framesToRead| and the remaining - * buffer in |pcmBuf| will be set with silence data (0x00). - */ - virtual uint32_t readFixedFrames(uint32_t framesToRead, char* pcmBuf); - - /** - * @brief Sets frame offest to be read. - * @param frameOffset The frame offest to be set. - * @return true if succeed, otherwise false - */ - virtual bool seek(uint32_t frameOffset) = 0; - - /** - * @brief Tells the current frame offset. - * @return The current frame offset. - */ - virtual uint32_t tell() const = 0; - - /** Gets total frames of current audio.*/ - virtual uint32_t getTotalFrames() const; - - /** Gets bytes per frame of current audio.*/ - virtual uint32_t getBytesPerFrame() const; - - /** Gets sample rate of current audio.*/ - virtual uint32_t getSampleRate() const; - - /** Gets the channel count of current audio. - * @note Currently we only support 1 or 2 channels. - */ - virtual uint32_t getChannelCount() const; - -protected: - AudioDecoder(); - virtual ~AudioDecoder(); - - bool _isOpened; - uint32_t _totalFrames; - uint32_t _bytesPerFrame; - uint32_t _sampleRate; - uint32_t _channelCount; - - friend class AudioDecoderManager; -}; - -} // namespace cocos2d { diff --git a/cocos/audio/win32/AudioDecoderManager.cpp b/cocos/audio/win32/AudioDecoderManager.cpp deleted file mode 100644 index 950c305..0000000 --- a/cocos/audio/win32/AudioDecoderManager.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ - -#define LOG_TAG "AudioDecoderManager" - -#include "audio/win32/AudioDecoderManager.h" -#include "audio/win32/AudioDecoderOgg.h" -#include "audio/win32/AudioDecoderMp3.h" -#include "audio/win32/AudioMacros.h" -#include "platform/CCFileUtils.h" -#include "base/CCConsole.h" -#include "mpg123.h" - -namespace cocos2d { - -static bool __mp3Inited = false; - -bool AudioDecoderManager::init() -{ - return true; -} - -void AudioDecoderManager::destroy() -{ - AudioDecoderMp3::destroy(); -} - -AudioDecoder* AudioDecoderManager::createDecoder(const char* path) -{ - std::string suffix = FileUtils::getInstance()->getFileExtension(path); - if (suffix == ".ogg") - { - return new (std::nothrow) AudioDecoderOgg(); - } - else if (suffix == ".mp3") - { - return new (std::nothrow) AudioDecoderMp3(); - } - - return nullptr; -} - -void AudioDecoderManager::destroyDecoder(AudioDecoder* decoder) -{ - delete decoder; -} - -} // namespace cocos2d { - diff --git a/cocos/audio/win32/AudioDecoderManager.h b/cocos/audio/win32/AudioDecoderManager.h deleted file mode 100644 index d529582..0000000 --- a/cocos/audio/win32/AudioDecoderManager.h +++ /dev/null @@ -1,42 +0,0 @@ -/**************************************************************************** -Copyright (c) 2016 Chukong Technologies Inc. -Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - -http://www.cocos2d-x.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -****************************************************************************/ - -#pragma once - -namespace cocos2d { - -class AudioDecoder; - -class AudioDecoderManager -{ -public: - static bool init(); - static void destroy(); - static AudioDecoder* createDecoder(const char* path); - static void destroyDecoder(AudioDecoder* decoder); -}; - -} // namespace cocos2d { - diff --git a/cocos/audio/win32/AudioDecoderMp3.cpp b/cocos/audio/win32/AudioDecoderMp3.cpp deleted file mode 100644 index e6d5b3a..0000000 --- a/cocos/audio/win32/AudioDecoderMp3.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/**************************************************************************** - Copyright (c) 2016 Chukong Technologies Inc. - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -#include "audio/win32/AudioDecoderMp3.h" -#include "audio/win32/AudioMacros.h" -#include "platform/CCFileUtils.h" - -#include "base/CCConsole.h" -#include "mpg123.h" - -#define LOG_TAG "AudioDecoderMp3" - -namespace cocos2d { - - static bool __mp3Inited = false; - - bool AudioDecoderMp3::lazyInit() - { - bool ret = true; - if (!__mp3Inited) - { - int error = mpg123_init(); - if (error == MPG123_OK) - { - __mp3Inited = true; - } - else - { - ALOGE("Basic setup goes wrong: %s", mpg123_plain_strerror(error)); - ret = false; - } - } - return ret; - } - - void AudioDecoderMp3::destroy() - { - if (__mp3Inited) - { - mpg123_exit(); - __mp3Inited = false; - } - } - - AudioDecoderMp3::AudioDecoderMp3() - : _mpg123handle(nullptr) - { - lazyInit(); - } - - AudioDecoderMp3::~AudioDecoderMp3() - { - close(); - } - - bool AudioDecoderMp3::open(const char* path) - { - std::string fullPath = FileUtils::getInstance()->fullPathForFilename(path); - - long rate = 0; - int error = MPG123_OK; - int mp3Encoding = 0; - int channel = 0; - do - { - _mpg123handle = mpg123_new(nullptr, &error); - if (nullptr == _mpg123handle) - { - ALOGE("Basic setup goes wrong: %s", mpg123_plain_strerror(error)); - break; - } - - if (mpg123_open(_mpg123handle, FileUtils::getInstance()->getSuitableFOpen(fullPath).c_str()) != MPG123_OK - || mpg123_getformat(_mpg123handle, &rate, &channel, &mp3Encoding) != MPG123_OK) - { - ALOGE("Trouble with mpg123: %s\n", mpg123_strerror(_mpg123handle) ); - break; - } - - _channelCount = channel; - _sampleRate = rate; - - if (mp3Encoding == MPG123_ENC_SIGNED_16) - { - _bytesPerFrame = 2 * _channelCount; - } - else if (mp3Encoding == MPG123_ENC_FLOAT_32) - { - _bytesPerFrame = 4 * _channelCount; - } - else - { - ALOGE("Bad encoding: 0x%x!\n", mp3Encoding); - break; - } - - /* Ensure that this output format will not change (it could, when we allow it). */ - mpg123_format_none(_mpg123handle); - mpg123_format(_mpg123handle, rate, channel, mp3Encoding); - /* Ensure that we can get accurate length by call mpg123_length */ - mpg123_scan(_mpg123handle); - - _totalFrames = mpg123_length(_mpg123handle); - - _isOpened = true; - return true; - } while (false); - - if (_mpg123handle != nullptr) - { - mpg123_close(_mpg123handle); - mpg123_delete(_mpg123handle); - _mpg123handle = nullptr; - } - return false; - } - - void AudioDecoderMp3::close() - { - if (isOpened()) - { - if (_mpg123handle != nullptr) - { - mpg123_close(_mpg123handle); - mpg123_delete(_mpg123handle); - _mpg123handle = nullptr; - } - _isOpened = false; - } - } - - uint32_t AudioDecoderMp3::read(uint32_t framesToRead, char* pcmBuf) - { - int bytesToRead = framesToRead * _bytesPerFrame; - size_t bytesRead = 0; - int err = mpg123_read(_mpg123handle, (unsigned char*)pcmBuf, bytesToRead, &bytesRead); - if (err == MPG123_ERR) - { - ALOGE("Trouble with mpg123: %s\n", mpg123_strerror(_mpg123handle) ); - return 0; - } - - return static_cast(bytesRead / _bytesPerFrame); - } - - bool AudioDecoderMp3::seek(uint32_t frameOffset) - { - off_t offset = mpg123_seek(_mpg123handle, frameOffset, SEEK_SET); - //ALOGD("mpg123_seek return: %d", (int)offset); - if (offset >= 0 && offset == frameOffset) - { - return true; - } - return false; - } - - uint32_t AudioDecoderMp3::tell() const - { - return static_cast(mpg123_tell(_mpg123handle)); - } - -} // namespace cocos2d { diff --git a/cocos/audio/win32/AudioDecoderMp3.h b/cocos/audio/win32/AudioDecoderMp3.h deleted file mode 100644 index 41b642b..0000000 --- a/cocos/audio/win32/AudioDecoderMp3.h +++ /dev/null @@ -1,86 +0,0 @@ -/**************************************************************************** - Copyright (c) 2016 Chukong Technologies Inc. - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -#pragma once - -#include "audio/win32/AudioDecoder.h" - -struct mpg123_handle_struct; - -namespace cocos2d { - -/** - * @brief The class for decoding compressed audio file to PCM buffer. - */ -class AudioDecoderMp3 : public AudioDecoder -{ -public: - /** - * @brief Opens an audio file specified by a file path. - * @return true if succeed, otherwise false. - */ - virtual bool open(const char* path) override; - - /** - * @brief Closes opened audio file. - * @note The method will also be automatically invoked in the destructor. - */ - virtual void close() override; - - /** - * @brief Reads audio frames of PCM format. - * @param framesToRead The number of frames excepted to be read. - * @param pcmBuf The buffer to hold the frames to be read, its size should be >= |framesToRead| * _bytesPerFrame. - * @return The number of frames actually read, it's probably less than 'framesToRead'. Returns 0 means reach the end of file. - */ - virtual uint32_t read(uint32_t framesToRead, char* pcmBuf) override; - - /** - * @brief Sets frame offest to be read. - * @param frameOffset The frame offest to be set. - * @return true if succeed, otherwise false - */ - virtual bool seek(uint32_t frameOffset) override; - - /** - * @brief Tells the current frame offset. - * @return The current frame offset. - */ - virtual uint32_t tell() const override; - -protected: - - AudioDecoderMp3(); - ~AudioDecoderMp3(); - - static bool lazyInit(); - static void destroy(); - - struct mpg123_handle_struct* _mpg123handle; - - friend class AudioDecoderManager; -}; - -} // namespace cocos2d { diff --git a/cocos/audio/win32/AudioDecoderOgg.cpp b/cocos/audio/win32/AudioDecoderOgg.cpp deleted file mode 100644 index a5c5c7c..0000000 --- a/cocos/audio/win32/AudioDecoderOgg.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/**************************************************************************** - Copyright (c) 2016 Chukong Technologies Inc. - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -#include "audio/win32/AudioDecoderOgg.h" -#include "audio/win32/AudioMacros.h" -#include "platform/CCFileUtils.h" - -#define LOG_TAG "AudioDecoderOgg" - -namespace cocos2d { - - AudioDecoderOgg::AudioDecoderOgg() - { - } - - AudioDecoderOgg::~AudioDecoderOgg() - { - close(); - } - - bool AudioDecoderOgg::open(const char* path) - { - std::string fullPath = FileUtils::getInstance()->fullPathForFilename(path); - if (0 == ov_fopen(FileUtils::getInstance()->getSuitableFOpen(fullPath).c_str(), &_vf)) - { - // header - vorbis_info* vi = ov_info(&_vf, -1); - _sampleRate = static_cast(vi->rate); - _channelCount = vi->channels; - _bytesPerFrame = vi->channels * sizeof(short); - _totalFrames = static_cast(ov_pcm_total(&_vf, -1)); - _isOpened = true; - return true; - } - return false; - } - - void AudioDecoderOgg::close() - { - if (isOpened()) - { - ov_clear(&_vf); - _isOpened = false; - } - } - - uint32_t AudioDecoderOgg::read(uint32_t framesToRead, char* pcmBuf) - { - int currentSection = 0; - int bytesToRead = framesToRead * _bytesPerFrame; - long bytesRead = ov_read(&_vf, pcmBuf, bytesToRead, 0, 2, 1, ¤tSection); - return static_cast(bytesRead / _bytesPerFrame); - } - - bool AudioDecoderOgg::seek(uint32_t frameOffset) - { - return 0 == ov_pcm_seek(&_vf, frameOffset); - } - - uint32_t AudioDecoderOgg::tell() const - { - return static_cast(ov_pcm_tell(const_cast(&_vf))); - } - -} // namespace cocos2d { diff --git a/cocos/audio/win32/AudioDecoderOgg.h b/cocos/audio/win32/AudioDecoderOgg.h deleted file mode 100644 index 1315067..0000000 --- a/cocos/audio/win32/AudioDecoderOgg.h +++ /dev/null @@ -1,82 +0,0 @@ -/**************************************************************************** - Copyright (c) 2016 Chukong Technologies Inc. - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -#pragma once - -#include "audio/win32/AudioDecoder.h" - -#include "vorbis/vorbisfile.h" - -namespace cocos2d { - -/** - * @brief The class for decoding compressed audio file to PCM buffer. - */ -class AudioDecoderOgg : public AudioDecoder -{ -public: - /** - * @brief Opens an audio file specified by a file path. - * @return true if succeed, otherwise false. - */ - virtual bool open(const char* path) override; - - /** - * @brief Closes opened audio file. - * @note The method will also be automatically invoked in the destructor. - */ - virtual void close() override; - - /** - * @brief Reads audio frames of PCM format. - * @param framesToRead The number of frames excepted to be read. - * @param pcmBuf The buffer to hold the frames to be read, its size should be >= |framesToRead| * _bytesPerFrame. - * @return The number of frames actually read, it's probably less than 'framesToRead'. Returns 0 means reach the end of file. - */ - virtual uint32_t read(uint32_t framesToRead, char* pcmBuf) override; - - /** - * @brief Sets frame offest to be read. - * @param frameOffset The frame offest to be set. - * @return true if succeed, otherwise false - */ - virtual bool seek(uint32_t frameOffset) override; - - /** - * @brief Tells the current frame offset. - * @return The current frame offset. - */ - virtual uint32_t tell() const override; - -protected: - AudioDecoderOgg(); - ~AudioDecoderOgg(); - - OggVorbis_File _vf; - - friend class AudioDecoderManager; -}; - -} // namespace cocos2d { diff --git a/cocos/audio/win32/AudioEngine-win32.cpp b/cocos/audio/win32/AudioEngine-win32.cpp deleted file mode 100644 index 2460594..0000000 --- a/cocos/audio/win32/AudioEngine-win32.cpp +++ /dev/null @@ -1,513 +0,0 @@ -/**************************************************************************** - Copyright (c) 2014-2016 Chukong Technologies Inc. - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ -#include "audio/win32/AudioEngine-win32.h" - -#ifdef OPENAL_PLAIN_INCLUDES -#include "alc.h" -#include "alext.h" -#else -#include "AL/alc.h" -#include "AL/alext.h" -#endif -#include "audio/include/AudioEngine.h" -#include "base/CCDirector.h" -#include "base/CCScheduler.h" -#include "platform/CCFileUtils.h" -#include "audio/win32/AudioDecoderManager.h" - -#include - -#define LOG_TAG "AudioEngine-Win32" - -// log, CCLOG aren't threadsafe, since we uses sub threads for parsing pcm data, threadsafe log output -// is needed. Define the following macros (ALOGV, ALOGD, ALOGI, ALOGW, ALOGE) for threadsafe log output. - -//FIXME: Move _winLog, winLog to a separated file -static void _winLog(const char *format, va_list args) -{ - static const int MAX_LOG_LENGTH = 16 * 1024; - int bufferSize = MAX_LOG_LENGTH; - char* buf = nullptr; - - do - { - buf = new (std::nothrow) char[bufferSize]; - if (buf == nullptr) - return; // not enough memory - - int ret = vsnprintf(buf, bufferSize - 3, format, args); - if (ret < 0) - { - bufferSize *= 2; - - delete[] buf; - } - else - break; - - } while (true); - - strcat(buf, "\n"); - - int pos = 0; - int len = strlen(buf); - char tempBuf[MAX_LOG_LENGTH + 1] = { 0 }; - WCHAR wszBuf[MAX_LOG_LENGTH + 1] = { 0 }; - - do - { - std::copy(buf + pos, buf + pos + MAX_LOG_LENGTH, tempBuf); - - tempBuf[MAX_LOG_LENGTH] = 0; - - MultiByteToWideChar(CP_UTF8, 0, tempBuf, -1, wszBuf, sizeof(wszBuf)); - OutputDebugStringW(wszBuf); - - pos += MAX_LOG_LENGTH; - - } while (pos < len); - - delete[] buf; -} - -void audioLog(const char * format, ...) -{ - va_list args; - va_start(args, format); - _winLog(format, args); - va_end(args); -} - -using namespace cocos2d; - -static ALCdevice *s_ALDevice = nullptr; -static ALCcontext *s_ALContext = nullptr; - -AudioEngineImpl::AudioEngineImpl() -: _lazyInitLoop(true) -, _currentAudioID(0) -, _scheduler(nullptr) -{ - -} - -AudioEngineImpl::~AudioEngineImpl() -{ - if (_scheduler != nullptr) - { - _scheduler->unschedule(CC_SCHEDULE_SELECTOR(AudioEngineImpl::update), this); - } - - if (s_ALContext) { - alDeleteSources(MAX_AUDIOINSTANCES, _alSources); - - _audioCaches.clear(); - - alcMakeContextCurrent(nullptr); - alcDestroyContext(s_ALContext); - s_ALContext = nullptr; - } - - if (s_ALDevice) { - alcCloseDevice(s_ALDevice); - s_ALDevice = nullptr; - } - - AudioDecoderManager::destroy(); -} - -bool AudioEngineImpl::init() -{ - bool ret = false; - do{ - s_ALDevice = alcOpenDevice(nullptr); - - if (s_ALDevice) { - alGetError(); - s_ALContext = alcCreateContext(s_ALDevice, nullptr); - alcMakeContextCurrent(s_ALContext); - - alGenSources(MAX_AUDIOINSTANCES, _alSources); - auto alError = alGetError(); - if(alError != AL_NO_ERROR) - { - ALOGE("%s:generating sources failed! error = %x\n", __FUNCTION__, alError); - break; - } - - for (int i = 0; i < MAX_AUDIOINSTANCES; ++i) { - _alSourceUsed[_alSources[i]] = false; - } - - _scheduler = Director::getInstance()->getScheduler(); - ret = AudioDecoderManager::init(); - ALOGI("OpenAL was initialized successfully!"); - } - }while (false); - - return ret; -} - -AudioCache* AudioEngineImpl::preload(const std::string& filePath, std::function callback) -{ - AudioCache* audioCache = nullptr; - - auto it = _audioCaches.find(filePath); - if (it == _audioCaches.end()) { - audioCache = &_audioCaches[filePath]; - audioCache->_fileFullPath = FileUtils::getInstance()->fullPathForFilename(filePath); - unsigned int cacheId = audioCache->_id; - auto isCacheDestroyed = audioCache->_isDestroyed; - AudioEngine::addTask([audioCache, cacheId, isCacheDestroyed](){ - if (*isCacheDestroyed) - { - ALOGV("AudioCache (id=%u) was destroyed, no need to launch readDataTask.", cacheId); - audioCache->setSkipReadDataTask(true); - return; - } - audioCache->readDataTask(cacheId); - }); - } - else { - audioCache = &it->second; - } - - if (audioCache && callback) - { - audioCache->addLoadCallback(callback); - } - return audioCache; -} - -int AudioEngineImpl::play2d(const std::string &filePath ,bool loop ,float volume) -{ - if (s_ALDevice == nullptr) { - return AudioEngine::INVALID_AUDIO_ID; - } - - bool sourceFlag = false; - ALuint alSource = 0; - for (int i = 0; i < MAX_AUDIOINSTANCES; ++i) { - alSource = _alSources[i]; - - if ( !_alSourceUsed[alSource]) { - sourceFlag = true; - break; - } - } - if(!sourceFlag){ - return AudioEngine::INVALID_AUDIO_ID; - } - - auto player = new (std::nothrow) AudioPlayer; - if (player == nullptr) { - return AudioEngine::INVALID_AUDIO_ID; - } - - player->_alSource = alSource; - player->_loop = loop; - player->_volume = volume; - - auto audioCache = preload(filePath, nullptr); - if (audioCache == nullptr) { - delete player; - return AudioEngine::INVALID_AUDIO_ID; - } - - player->setCache(audioCache); - _threadMutex.lock(); - _audioPlayers[_currentAudioID] = player; - _threadMutex.unlock(); - - _alSourceUsed[alSource] = true; - - audioCache->addPlayCallback(std::bind(&AudioEngineImpl::_play2d,this,audioCache,_currentAudioID)); - - if (_lazyInitLoop) { - _lazyInitLoop = false; - _scheduler->schedule(CC_SCHEDULE_SELECTOR(AudioEngineImpl::update), this, 0.05f, false); - } - - return _currentAudioID++; -} - -void AudioEngineImpl::_play2d(AudioCache *cache, int audioID) -{ - //Note: It may bn in sub thread or main thread :( - if (!*cache->_isDestroyed && cache->_state == AudioCache::State::READY) - { - _threadMutex.lock(); - auto playerIt = _audioPlayers.find(audioID); - if (playerIt != _audioPlayers.end() && playerIt->second->play2d()) { - _scheduler->performFunctionInCocosThread([audioID](){ - - if (AudioEngine::_audioIDInfoMap.find(audioID) != AudioEngine::_audioIDInfoMap.end()) { - AudioEngine::_audioIDInfoMap[audioID].state = AudioEngine::AudioState::PLAYING; - } - }); - } - _threadMutex.unlock(); - } - else - { - ALOGD("AudioEngineImpl::_play2d, cache was destroyed or not ready!"); - auto iter = _audioPlayers.find(audioID); - if (iter != _audioPlayers.end()) - { - iter->second->_removeByAudioEngine = true; - } - } -} - -void AudioEngineImpl::setVolume(int audioID,float volume) -{ - auto player = _audioPlayers[audioID]; - player->_volume = volume; - - if (player->_ready) { - alSourcef(_audioPlayers[audioID]->_alSource, AL_GAIN, volume); - - auto error = alGetError(); - if (error != AL_NO_ERROR) { - ALOGE("%s: audio id = %d, error = %x", __FUNCTION__,audioID,error); - } - } -} - -void AudioEngineImpl::setLoop(int audioID, bool loop) -{ - auto player = _audioPlayers[audioID]; - - if (player->_ready) { - if (player->_streamingSource) { - player->setLoop(loop); - } else { - if (loop) { - alSourcei(player->_alSource, AL_LOOPING, AL_TRUE); - } else { - alSourcei(player->_alSource, AL_LOOPING, AL_FALSE); - } - - auto error = alGetError(); - if (error != AL_NO_ERROR) { - ALOGE("%s: audio id = %d, error = %x", __FUNCTION__,audioID,error); - } - } - } - else { - player->_loop = loop; - } -} - -bool AudioEngineImpl::pause(int audioID) -{ - bool ret = true; - alSourcePause(_audioPlayers[audioID]->_alSource); - - auto error = alGetError(); - if (error != AL_NO_ERROR) { - ret = false; - ALOGE("%s: audio id = %d, error = %x\n", __FUNCTION__,audioID,error); - } - - return ret; -} - -bool AudioEngineImpl::resume(int audioID) -{ - bool ret = true; - alSourcePlay(_audioPlayers[audioID]->_alSource); - - auto error = alGetError(); - if (error != AL_NO_ERROR) { - ret = false; - ALOGE("%s: audio id = %d, error = %x\n", __FUNCTION__,audioID,error); - } - - return ret; -} - -void AudioEngineImpl::stop(int audioID) -{ - auto player = _audioPlayers[audioID]; - player->destroy(); - //Note: Don't set the flag to false here, it should be set in 'update' function. - // Otherwise, the state got from alSourceState may be wrong -// _alSourceUsed[player->_alSource] = false; - - // Call 'update' method to cleanup immediately since the schedule may be cancelled without any notification. - update(0.0f); -} - -void AudioEngineImpl::stopAll() -{ - for(auto&& player : _audioPlayers) - { - player.second->destroy(); - } - //Note: Don't set the flag to false here, it should be set in 'update' function. - // Otherwise, the state got from alSourceState may be wrong -// for(int index = 0; index < MAX_AUDIOINSTANCES; ++index) -// { -// _alSourceUsed[_alSources[index]] = false; -// } - - // Call 'update' method to cleanup immediately since the schedule may be cancelled without any notification. - update(0.0f); -} - -float AudioEngineImpl::getDuration(int audioID) -{ - auto player = _audioPlayers[audioID]; - if(player->_ready){ - return player->_audioCache->_duration; - } else { - return AudioEngine::TIME_UNKNOWN; - } -} - -float AudioEngineImpl::getCurrentTime(int audioID) -{ - float ret = 0.0f; - auto player = _audioPlayers[audioID]; - if(player->_ready){ - if (player->_streamingSource) { - ret = player->getTime(); - } else { - alGetSourcef(player->_alSource, AL_SEC_OFFSET, &ret); - - auto error = alGetError(); - if (error != AL_NO_ERROR) { - ALOGE("%s, audio id:%d,error code:%x", __FUNCTION__,audioID,error); - } - } - } - - return ret; -} - -bool AudioEngineImpl::setCurrentTime(int audioID, float time) -{ - bool ret = false; - auto player = _audioPlayers[audioID]; - - do { - if (!player->_ready) { - break; - } - - if (player->_streamingSource) { - ret = player->setTime(time); - break; - } - else { - if (player->_audioCache->_framesRead != player->_audioCache->_totalFrames && - (time * player->_audioCache->_sampleRate) > player->_audioCache->_framesRead) { - ALOGE("%s: audio id = %d", __FUNCTION__,audioID); - break; - } - - alSourcef(player->_alSource, AL_SEC_OFFSET, time); - - auto error = alGetError(); - if (error != AL_NO_ERROR) { - ALOGE("%s: audio id = %d, error = %x", __FUNCTION__,audioID,error); - } - ret = true; - } - } while (0); - - return ret; -} - -void AudioEngineImpl::setFinishCallback(int audioID, const std::function &callback) -{ - _audioPlayers[audioID]->_finishCallbak = callback; -} - -void AudioEngineImpl::update(float dt) -{ - ALint sourceState; - int audioID; - AudioPlayer* player; - ALuint alSource; - -// ALOGV("AudioPlayer count: %d", (int)_audioPlayers.size()); - - for (auto it = _audioPlayers.begin(); it != _audioPlayers.end(); ) { - audioID = it->first; - player = it->second; - alSource = player->_alSource; - alGetSourcei(alSource, AL_SOURCE_STATE, &sourceState); - - if (player->_removeByAudioEngine) - { - AudioEngine::remove(audioID); - _threadMutex.lock(); - it = _audioPlayers.erase(it); - _threadMutex.unlock(); - delete player; - _alSourceUsed[alSource] = false; - } - else if (player->_ready && sourceState == AL_STOPPED) { - - std::string filePath; - if (player->_finishCallbak) { - auto& audioInfo = AudioEngine::_audioIDInfoMap[audioID]; - filePath = audioInfo.filePath; - } - - AudioEngine::remove(audioID); - - _threadMutex.lock(); - it = _audioPlayers.erase(it); - _threadMutex.unlock(); - - if (player->_finishCallbak) { - player->_finishCallbak(audioID, filePath); //FIXME: callback will delay 50ms - } - delete player; - _alSourceUsed[alSource] = false; - } - else{ - ++it; - } - } - - if(_audioPlayers.empty()){ - _lazyInitLoop = true; - _scheduler->unschedule(CC_SCHEDULE_SELECTOR(AudioEngineImpl::update), this); - } -} - -void AudioEngineImpl::uncache(const std::string &filePath) -{ - _audioCaches.erase(filePath); -} - -void AudioEngineImpl::uncacheAll() -{ - _audioCaches.clear(); -} diff --git a/cocos/audio/win32/AudioEngine-win32.h b/cocos/audio/win32/AudioEngine-win32.h deleted file mode 100644 index 9cfd0f5..0000000 --- a/cocos/audio/win32/AudioEngine-win32.h +++ /dev/null @@ -1,84 +0,0 @@ -/**************************************************************************** - Copyright (c) 2014-2016 Chukong Technologies Inc. - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ -#pragma once - -#include - -#include "base/CCRef.h" -#include "audio/win32/AudioCache.h" -#include "audio/win32/AudioPlayer.h" - -NS_CC_BEGIN - -class Scheduler; - -#define MAX_AUDIOINSTANCES 32 - -class CC_DLL AudioEngineImpl : public cocos2d::Ref -{ -public: - AudioEngineImpl(); - ~AudioEngineImpl(); - - bool init(); - int play2d(const std::string &fileFullPath ,bool loop ,float volume); - void setVolume(int audioID,float volume); - void setLoop(int audioID, bool loop); - bool pause(int audioID); - bool resume(int audioID); - void stop(int audioID); - void stopAll(); - float getDuration(int audioID); - float getCurrentTime(int audioID); - bool setCurrentTime(int audioID, float time); - void setFinishCallback(int audioID, const std::function &callback); - - void uncache(const std::string& filePath); - void uncacheAll(); - AudioCache* preload(const std::string& filePath, std::function callback); - void update(float dt); - -private: - void _play2d(AudioCache *cache, int audioID); - - ALuint _alSources[MAX_AUDIOINSTANCES]; - - //source,used - std::unordered_map _alSourceUsed; - - //filePath,bufferInfo - std::unordered_map _audioCaches; - - //audioID,AudioInfo - std::unordered_map _audioPlayers; - std::mutex _threadMutex; - - bool _lazyInitLoop; - - int _currentAudioID; - Scheduler* _scheduler; -}; - -NS_CC_END diff --git a/cocos/audio/win32/AudioMacros.h b/cocos/audio/win32/AudioMacros.h deleted file mode 100644 index 77fb7b5..0000000 --- a/cocos/audio/win32/AudioMacros.h +++ /dev/null @@ -1,72 +0,0 @@ -/**************************************************************************** - Copyright (c) 2016 Chukong Technologies Inc. - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -#pragma once - -#define QUEUEBUFFER_NUM (3) -#define QUEUEBUFFER_TIME_STEP (0.1f) - -// log, CCLOG aren't threadsafe, since we uses sub threads for parsing pcm data, threadsafe log output -// is needed. Define the following macros (ALOGV, ALOGD, ALOGI, ALOGW, ALOGE) for threadsafe log output. - -//FIXME:Move the definition of the following macros to a separated file. - -void audioLog(const char * format, ...); - -#define QUOTEME_(x) #x -#define QUOTEME(x) QUOTEME_(x) - -#if defined(COCOS2D_DEBUG) && COCOS2D_DEBUG > 0 -#define ALOGV(fmt, ...) audioLog("V/" LOG_TAG " (" QUOTEME(__LINE__) "): " fmt "", ##__VA_ARGS__) -#else -#define ALOGV(fmt, ...) do {} while(false) -#endif -#define ALOGD(fmt, ...) audioLog("D/" LOG_TAG " (" QUOTEME(__LINE__) "): " fmt "", ##__VA_ARGS__) -#define ALOGI(fmt, ...) audioLog("I/" LOG_TAG " (" QUOTEME(__LINE__) "): " fmt "", ##__VA_ARGS__) -#define ALOGW(fmt, ...) audioLog("W/" LOG_TAG " (" QUOTEME(__LINE__) "): " fmt "", ##__VA_ARGS__) -#define ALOGE(fmt, ...) audioLog("E/" LOG_TAG " (" QUOTEME(__LINE__) "): " fmt "", ##__VA_ARGS__) - -#if defined(COCOS2D_DEBUG) && COCOS2D_DEBUG > 0 -#define CHECK_AL_ERROR_DEBUG() \ -do { \ - GLenum __error = alGetError(); \ - if (__error) { \ - ALOGE("OpenAL error 0x%04X in %s %s %d\n", __error, __FILE__, __FUNCTION__, __LINE__); \ - } \ -} while (false) -#else -#define CHECK_AL_ERROR_DEBUG() -#endif - -#define BREAK_IF(condition) \ - if (!!(condition)) { \ - break; \ - } - -#define BREAK_IF_ERR_LOG(condition, fmt, ...) \ - if (!!(condition)) { \ - ALOGE("(" QUOTEME(condition) ") failed, message: " fmt, ##__VA_ARGS__); \ - break; \ - } diff --git a/cocos/audio/win32/AudioPlayer.cpp b/cocos/audio/win32/AudioPlayer.cpp deleted file mode 100644 index 370c015..0000000 --- a/cocos/audio/win32/AudioPlayer.cpp +++ /dev/null @@ -1,340 +0,0 @@ -/**************************************************************************** - Copyright (c) 2014-2016 Chukong Technologies Inc. - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ -#include "audio/win32/AudioPlayer.h" -#include "audio/win32/AudioCache.h" -#include "platform/CCFileUtils.h" -#include "audio/win32/AudioDecoderManager.h" -#include "audio/win32/Audiodecoder.h" - -#define VERY_VERY_VERBOSE_LOGGING -#ifdef VERY_VERY_VERBOSE_LOGGING -#define ALOGVV ALOGV -#else -#define ALOGVV(...) do{} while(false) -#endif - -#define LOG_TAG "AudioPlayer" - -using namespace cocos2d; - -namespace { -unsigned int __idIndex = 0; -} - -AudioPlayer::AudioPlayer() -: _audioCache(nullptr) -, _finishCallbak(nullptr) -, _isDestroyed(false) -, _removeByAudioEngine(false) -, _ready(false) -, _currTime(0.0f) -, _streamingSource(false) -, _rotateBufferThread(nullptr) -, _timeDirty(false) -, _isRotateThreadExited(false) -, _id(++__idIndex) -{ - memset(_bufferIds, 0, sizeof(_bufferIds)); -} - -AudioPlayer::~AudioPlayer() -{ - ALOGVV("~AudioPlayer() (%p), id=%u", this, _id); - destroy(); - - if (_streamingSource) - { - alDeleteBuffers(3, _bufferIds); - } -} - -void AudioPlayer::destroy() -{ - if (_isDestroyed) - return; - - ALOGVV("AudioPlayer::destroy begin, id=%u", _id); - - _isDestroyed = true; - - do - { - if (_audioCache != nullptr) - { - if (_audioCache->_state == AudioCache::State::INITIAL) - { - ALOGV("AudioPlayer::destroy, id=%u, cache isn't ready!", _id); - break; - } - - while (!_audioCache->_isLoadingFinished) - { - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - } - } - - // Wait for play2d to be finished. - _play2dMutex.lock(); - _play2dMutex.unlock(); - - if (_streamingSource) - { - if (_rotateBufferThread != nullptr) - { - while (!_isRotateThreadExited) - { - _sleepCondition.notify_one(); - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - } - - if (_rotateBufferThread->joinable()) { - _rotateBufferThread->join(); - } - - delete _rotateBufferThread; - _rotateBufferThread = nullptr; - ALOGVV("rotateBufferThread exited!"); - } - } - } while(false); - - ALOGVV("Before alSourceStop"); - alSourceStop(_alSource); CHECK_AL_ERROR_DEBUG(); - ALOGVV("Before alSourcei"); - alSourcei(_alSource, AL_BUFFER, NULL); CHECK_AL_ERROR_DEBUG(); - - _removeByAudioEngine = true; - - _ready = false; - ALOGVV("AudioPlayer::destroy end, id=%u", _id); -} - -void AudioPlayer::setCache(AudioCache* cache) -{ - _audioCache = cache; -} - -bool AudioPlayer::play2d() -{ - _play2dMutex.lock(); - ALOGV("AudioPlayer::play2d, _alSource: %u, player id=%u", _alSource, _id); - - /*********************************************************************/ - /* Note that it may be in sub thread or in main thread. **/ - /*********************************************************************/ - bool ret = false; - do - { - if (_audioCache->_state != AudioCache::State::READY) - { - ALOGE("alBuffer isn't ready for play!"); - break; - } - - alSourcei(_alSource, AL_BUFFER, 0);CHECK_AL_ERROR_DEBUG(); - alSourcef(_alSource, AL_PITCH, 1.0f);CHECK_AL_ERROR_DEBUG(); - alSourcef(_alSource, AL_GAIN, _volume);CHECK_AL_ERROR_DEBUG(); - alSourcei(_alSource, AL_LOOPING, AL_FALSE);CHECK_AL_ERROR_DEBUG(); - - if (_audioCache->_queBufferFrames == 0) - { - if (_loop) { - alSourcei(_alSource, AL_LOOPING, AL_TRUE); - CHECK_AL_ERROR_DEBUG(); - } - } - else - { - alGenBuffers(3, _bufferIds); - - auto alError = alGetError(); - if (alError == AL_NO_ERROR) - { - for (int index = 0; index < QUEUEBUFFER_NUM; ++index) - { - alBufferData(_bufferIds[index], _audioCache->_format, _audioCache->_queBuffers[index], _audioCache->_queBufferSize[index], _audioCache->_sampleRate); - } - CHECK_AL_ERROR_DEBUG(); - } - else - { - ALOGE("%s:alGenBuffers error code:%x", __FUNCTION__,alError); - break; - } - _streamingSource = true; - } - - { - std::unique_lock lk(_sleepMutex); - if (_isDestroyed) - break; - - if (_streamingSource) - { - alSourceQueueBuffers(_alSource, QUEUEBUFFER_NUM, _bufferIds); - CHECK_AL_ERROR_DEBUG(); - _rotateBufferThread = new std::thread(&AudioPlayer::rotateBufferThread, this, _audioCache->_queBufferFrames * QUEUEBUFFER_NUM + 1); - } - else - { - alSourcei(_alSource, AL_BUFFER, _audioCache->_alBufferId); - CHECK_AL_ERROR_DEBUG(); - } - - alSourcePlay(_alSource); - } - - auto alError = alGetError(); - if (alError != AL_NO_ERROR) - { - ALOGE("%s:alSourcePlay error code:%x", __FUNCTION__,alError); - break; - } - - ALint state; - alGetSourcei(_alSource, AL_SOURCE_STATE, &state); - if (state != AL_PLAYING) - { - ALOGE("state isn't playing, %d, %s, cache id=%u, player id=%u", state, _audioCache->_fileFullPath.c_str(), _audioCache->_id, _id); - } - assert(state == AL_PLAYING); - _ready = true; - ret = true; - } while (false); - - if (!ret) - { - _removeByAudioEngine = true; - } - - _play2dMutex.unlock(); - return ret; -} - -void AudioPlayer::rotateBufferThread(int offsetFrame) -{ - char* tmpBuffer = nullptr; - AudioDecoder* decoder = AudioDecoderManager::createDecoder(_audioCache->_fileFullPath.c_str()); - do - { - BREAK_IF(decoder == nullptr || !decoder->open(_audioCache->_fileFullPath.c_str())); - - uint32_t framesRead = 0; - const uint32_t framesToRead = _audioCache->_queBufferFrames; - const uint32_t bufferSize = framesToRead * decoder->getBytesPerFrame(); - tmpBuffer = (char*)malloc(bufferSize); - memset(tmpBuffer, 0, bufferSize); - - if (offsetFrame != 0) { - decoder->seek(offsetFrame); - } - - ALint sourceState; - ALint bufferProcessed = 0; - bool needToExitThread = false; - - while (!_isDestroyed) { - alGetSourcei(_alSource, AL_SOURCE_STATE, &sourceState); - if (sourceState == AL_PLAYING) { - alGetSourcei(_alSource, AL_BUFFERS_PROCESSED, &bufferProcessed); - while (bufferProcessed > 0) { - bufferProcessed--; - if (_timeDirty) { - _timeDirty = false; - offsetFrame = (int)(_currTime * decoder->getSampleRate()); - decoder->seek(offsetFrame); - } - else { - _currTime += QUEUEBUFFER_TIME_STEP; - if (_currTime > _audioCache->_duration) { - if (_loop) { - _currTime = 0.0f; - } else { - _currTime = _audioCache->_duration; - } - } - } - - framesRead = decoder->readFixedFrames(framesToRead, tmpBuffer); - - if (framesRead == 0) { - if (_loop) { - decoder->seek(0); - framesRead = decoder->readFixedFrames(framesToRead, tmpBuffer); - } else { - needToExitThread = true; - break; - } - } - - ALuint bid; - alSourceUnqueueBuffers(_alSource, 1, &bid); - alBufferData(bid, _audioCache->_format, tmpBuffer, framesRead * decoder->getBytesPerFrame(), decoder->getSampleRate()); - alSourceQueueBuffers(_alSource, 1, &bid); - } - } - - std::unique_lock lk(_sleepMutex); - if (_isDestroyed || needToExitThread) { - break; - } - - _sleepCondition.wait_for(lk,std::chrono::milliseconds(75)); - } - - } while(false); - - ALOGV("Exit rotate buffer thread ..."); - if (decoder != nullptr) - { - decoder->close(); - } - AudioDecoderManager::destroyDecoder(decoder); - free(tmpBuffer); - _isRotateThreadExited = true; - ALOGV("%s exited.\n", __FUNCTION__); -} - -bool AudioPlayer::setLoop(bool loop) -{ - if (!_isDestroyed ) { - _loop = loop; - return true; - } - - return false; -} - -bool AudioPlayer::setTime(float time) -{ - if (!_isDestroyed && time >= 0.0f && time < _audioCache->_duration) { - - _currTime = time; - _timeDirty = true; - - return true; - } - return false; -} diff --git a/cocos/audio/win32/AudioPlayer.h b/cocos/audio/win32/AudioPlayer.h deleted file mode 100644 index 362ede8..0000000 --- a/cocos/audio/win32/AudioPlayer.h +++ /dev/null @@ -1,90 +0,0 @@ -/**************************************************************************** - Copyright (c) 2014-2016 Chukong Technologies Inc. - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ -#pragma once - -#include -#include -#include -#include -#include -#ifdef OPENAL_PLAIN_INCLUDES -#include -#else -#include -#endif -#include "platform/CCPlatformMacros.h" - -NS_CC_BEGIN - -class AudioCache; -class AudioEngineImpl; - -class CC_DLL AudioPlayer -{ -public: - AudioPlayer(); - ~AudioPlayer(); - - void destroy(); - - //queue buffer related stuff - bool setTime(float time); - float getTime() { return _currTime;} - bool setLoop(bool loop); - -protected: - void setCache(AudioCache* cache); - void rotateBufferThread(int offsetFrame); - bool play2d(); - - AudioCache* _audioCache; - - float _volume; - bool _loop; - std::function _finishCallbak; - - bool _isDestroyed; - bool _removeByAudioEngine; - bool _ready; - ALuint _alSource; - - //play by circular buffer - float _currTime; - bool _streamingSource; - ALuint _bufferIds[3]; - std::thread* _rotateBufferThread; - std::condition_variable _sleepCondition; - std::mutex _sleepMutex; - bool _timeDirty; - bool _isRotateThreadExited; - - std::mutex _play2dMutex; - - unsigned int _id; - - friend class AudioEngineImpl; -}; - -NS_CC_END diff --git a/cocos/audio/win32/MciPlayer.cpp b/cocos/audio/win32/MciPlayer.cpp deleted file mode 100644 index db3dc69..0000000 --- a/cocos/audio/win32/MciPlayer.cpp +++ /dev/null @@ -1,261 +0,0 @@ -/**************************************************************************** - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -#include "audio/win32/MciPlayer.h" -#include -#include "platform/CCFileUtils.h" - -#define WIN_CLASS_NAME "CocosDenshionCallbackWnd" -#define BREAK_IF(cond) if (cond) break; - -namespace CocosDenshion { - -static HINSTANCE s_hInstance; -static MCIERROR s_mciError; - -LRESULT WINAPI _SoundPlayProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); - -MciPlayer::MciPlayer() -: _wnd(NULL) -, _dev(0L) -, _soundID(0) -, _times(0) -, _playing(false) -, strExt("") -{ - if (! s_hInstance) - { - s_hInstance = GetModuleHandle( NULL ); // Grab An Instance For Our Window - - WNDCLASS wc; // Windows Class Structure - - // Redraw On Size, And Own DC For Window. - wc.style = 0; - wc.lpfnWndProc = _SoundPlayProc; // WndProc Handles Messages - wc.cbClsExtra = 0; // No Extra Window Data - wc.cbWndExtra = 0; // No Extra Window Data - wc.hInstance = s_hInstance; // Set The Instance - wc.hIcon = 0; // Load The Default Icon - wc.hCursor = LoadCursor( NULL, IDC_ARROW ); // Load The Arrow Pointer - wc.hbrBackground = NULL; // No Background Required For GL - wc.lpszMenuName = NULL; // We Don't Want A Menu - wc.lpszClassName = _T(WIN_CLASS_NAME); // Set The Class Name - - if (! RegisterClass(&wc) - && ERROR_CLASS_ALREADY_EXISTS != GetLastError()) - { - return; - } - } - - _wnd = CreateWindowEx( - WS_EX_APPWINDOW, // Extended Style For The Window - _T(WIN_CLASS_NAME), // Class Name - NULL, // Window Title - WS_POPUPWINDOW,/*WS_OVERLAPPEDWINDOW*/ // Defined Window Style - 0, 0, // Window Position - 0, // Window Width - 0, // Window Height - NULL, // No Parent Window - NULL, // No Menu - s_hInstance, // Instance - NULL ); - if (_wnd) - { - SetWindowLongPtr(_wnd, GWLP_USERDATA, (LONG_PTR)this); - } -} - -MciPlayer::~MciPlayer() -{ - Close(); - DestroyWindow(_wnd); -} - -void MciPlayer::Open(const char* pFileName, UINT uId) -{ -// WCHAR * pBuf = NULL; - do - { - BREAK_IF(! pFileName || ! _wnd); - int nLen = (int)strlen(pFileName); - BREAK_IF(! nLen); -// pBuf = new WCHAR[nLen + 1]; -// BREAK_IF(! pBuf); -// MultiByteToWideChar(CP_ACP, 0, pFileName, nLen + 1, pBuf, nLen + 1); - - strExt = cocos2d::FileUtils::getInstance()->getFileExtension(pFileName); - - Close(); - - MCI_OPEN_PARMS mciOpen = {0}; - MCIERROR mciError; - mciOpen.lpstrDeviceType = (LPCTSTR)MCI_ALL_DEVICE_ID; - WCHAR* fileNameWideChar = new WCHAR[nLen + 1]; - BREAK_IF(! fileNameWideChar); - MultiByteToWideChar(CP_ACP, 0, pFileName, nLen + 1, fileNameWideChar, nLen + 1); - mciOpen.lpstrElementName = fileNameWideChar; - - mciError = mciSendCommand(0,MCI_OPEN, MCI_OPEN_ELEMENT, reinterpret_cast(&mciOpen)); - CC_SAFE_DELETE_ARRAY(mciOpen.lpstrElementName); - BREAK_IF(mciError); - - _dev = mciOpen.wDeviceID; - _soundID = uId; - _playing = false; - } while (0); -} - -void MciPlayer::Play(UINT uTimes /* = 1 */) -{ - if (! _dev) - { - return; - } - MCI_PLAY_PARMS mciPlay = {0}; - mciPlay.dwCallback = reinterpret_cast(_wnd); - s_mciError = mciSendCommand(_dev,MCI_PLAY, MCI_FROM|MCI_NOTIFY,reinterpret_cast(&mciPlay)); - if (! s_mciError) - { - _playing = true; - _times = uTimes; - } -} - -void MciPlayer::Close() -{ - if (_playing) - { - Stop(); - } - if (_dev) - { - _SendGenericCommand(MCI_CLOSE); - } - _dev = 0; - _playing = false; -} - -void MciPlayer::Pause() -{ - _SendGenericCommand(MCI_PAUSE); - _playing = false; -} - -void MciPlayer::Resume() -{ - if (strExt == ".mid") - { - // midi not support MCI_RESUME, should get the position and use MCI_FROM - MCI_STATUS_PARMS mciStatusParms; - MCI_PLAY_PARMS mciPlayParms; - mciStatusParms.dwItem = MCI_STATUS_POSITION; - _SendGenericCommand(MCI_STATUS, MCI_STATUS_ITEM, reinterpret_cast(&mciStatusParms)); // MCI_STATUS - mciPlayParms.dwFrom = mciStatusParms.dwReturn; // get position - _SendGenericCommand(MCI_PLAY, MCI_FROM, reinterpret_cast(&mciPlayParms)); // MCI_FROM - } - else - { - _SendGenericCommand(MCI_RESUME); - _playing = true; - } -} - -void MciPlayer::Stop() -{ - _SendGenericCommand(MCI_STOP); - _playing = false; - _times = 0; -} - -void MciPlayer::Rewind() -{ - if (! _dev) - { - return; - } - mciSendCommand(_dev, MCI_SEEK, MCI_SEEK_TO_START, 0); - - MCI_PLAY_PARMS mciPlay = {0}; - mciPlay.dwCallback = reinterpret_cast(_wnd); - _playing = mciSendCommand(_dev, MCI_PLAY, MCI_NOTIFY,reinterpret_cast(&mciPlay)) ? false : true; -} - -bool MciPlayer::IsPlaying() -{ - return _playing; -} - -UINT MciPlayer::GetSoundID() -{ - return _soundID; -} - -////////////////////////////////////////////////////////////////////////// -// private member -////////////////////////////////////////////////////////////////////////// -void MciPlayer::_SendGenericCommand( int nCommand, DWORD_PTR param1 /*= 0*/, DWORD_PTR parma2 /*= 0*/ ) -{ - if (! _dev) - { - return; - } - mciSendCommand(_dev, nCommand, param1, parma2); -} - - -////////////////////////////////////////////////////////////////////////// -// static function -////////////////////////////////////////////////////////////////////////// - -LRESULT WINAPI _SoundPlayProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) -{ - MciPlayer * pPlayer = NULL; - if (MM_MCINOTIFY == Msg - && MCI_NOTIFY_SUCCESSFUL == wParam - &&(pPlayer = (MciPlayer *)GetWindowLongPtr(hWnd, GWLP_USERDATA))) - { - if (pPlayer->_times) - { - --pPlayer->_times; - } - - if (pPlayer->_times) - { - mciSendCommand(lParam, MCI_SEEK, MCI_SEEK_TO_START, 0); - - MCI_PLAY_PARMS mciPlay = {0}; - mciPlay.dwCallback = reinterpret_cast(hWnd); - mciSendCommand(lParam, MCI_PLAY, MCI_NOTIFY,reinterpret_cast(&mciPlay)); - } - else - { - pPlayer->_playing = false; - } - return 0; - } - return DefWindowProc(hWnd, Msg, wParam, lParam); -} - -} // end of namespace CocosDenshion diff --git a/cocos/audio/win32/MciPlayer.h b/cocos/audio/win32/MciPlayer.h deleted file mode 100644 index 194bdca..0000000 --- a/cocos/audio/win32/MciPlayer.h +++ /dev/null @@ -1,103 +0,0 @@ -/**************************************************************************** - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -#ifndef _MCI_PLAYER_WIN32_H_ -#define _MCI_PLAYER_WIN32_H_ - -#include "platform/CCStdC.h" -#include -#include -using namespace std; - - -namespace CocosDenshion { - -class MciPlayer -{ -public: - MciPlayer(); - ~MciPlayer(); - - void Close(); - - /** - @brief Open audio file - @param pFileName The file name which includes the file path. - @param uId The audio ID - */ - void Open(const char* pFileName, UINT uId); - - /** - @brief Play audio file - @param nTimes The repeat times, its default value is 1 which means only play once - */ - void Play(UINT uTimes = 1); - - /** - @brief Pause play - */ - void Pause(); - - /** - @brief Resume play - */ - void Resume(); - - /** - @brief Stop play - */ - void Stop(); - - /** - @brief Replay - */ - void Rewind(); - - /** - @brief Is Playing - */ - bool IsPlaying(); - - /** - @brief Get playing sound's ID - @return Sound's ID - */ - UINT GetSoundID(); - -private: - friend LRESULT WINAPI _SoundPlayProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); - - void _SendGenericCommand(int nCommand, DWORD_PTR param1 = 0, DWORD_PTR parma2 = 0); - - HWND _wnd; - MCIDEVICEID _dev; - UINT _soundID; - UINT _times; - bool _playing; - std::string strExt; -}; - -} // end of namespace CocosDenshion - -#endif diff --git a/cocos/editor-support/cocostudio/CCComAudio.cpp b/cocos/editor-support/cocostudio/CCComAudio.cpp index 4a7f10c..cf58210 100644 --- a/cocos/editor-support/cocostudio/CCComAudio.cpp +++ b/cocos/editor-support/cocostudio/CCComAudio.cpp @@ -24,7 +24,6 @@ THE SOFTWARE. ****************************************************************************/ #include "editor-support/cocostudio/CCComAudio.h" -#include "editor-support/cocostudio/SimpleAudioEngine.h" #include "platform/CCFileUtils.h" namespace cocostudio { @@ -165,142 +164,117 @@ ComAudio* ComAudio::create() void ComAudio::end() { - CocosDenshion::SimpleAudioEngine::end(); } void ComAudio::preloadBackgroundMusic(const char* pszFilePath) { - CocosDenshion::SimpleAudioEngine::getInstance()->preloadBackgroundMusic(pszFilePath); - setFile(pszFilePath); - setLoop(false); } void ComAudio::playBackgroundMusic(const char* pszFilePath, bool loop) { - CocosDenshion::SimpleAudioEngine::getInstance()->playBackgroundMusic(pszFilePath, loop); - } void ComAudio::playBackgroundMusic(const char* pszFilePath) { - CocosDenshion::SimpleAudioEngine::getInstance()->playBackgroundMusic(pszFilePath); } void ComAudio::playBackgroundMusic() { - CocosDenshion::SimpleAudioEngine::getInstance()->playBackgroundMusic(_filePath.c_str(), _loop); } void ComAudio::stopBackgroundMusic(bool bReleaseData) { - CocosDenshion::SimpleAudioEngine::getInstance()->stopBackgroundMusic(bReleaseData); } void ComAudio::stopBackgroundMusic() { - CocosDenshion::SimpleAudioEngine::getInstance()->stopBackgroundMusic(); } void ComAudio::pauseBackgroundMusic() { - CocosDenshion::SimpleAudioEngine::getInstance()->pauseBackgroundMusic(); } void ComAudio::resumeBackgroundMusic() { - CocosDenshion::SimpleAudioEngine::getInstance()->resumeBackgroundMusic(); } void ComAudio::rewindBackgroundMusic() { - CocosDenshion::SimpleAudioEngine::getInstance()->rewindBackgroundMusic(); } bool ComAudio::willPlayBackgroundMusic() { - return CocosDenshion::SimpleAudioEngine::getInstance()->willPlayBackgroundMusic(); + return false; } bool ComAudio::isBackgroundMusicPlaying() { - return CocosDenshion::SimpleAudioEngine::getInstance()->isBackgroundMusicPlaying(); + return false; } float ComAudio::getBackgroundMusicVolume() { - return CocosDenshion::SimpleAudioEngine::getInstance()->getBackgroundMusicVolume(); + return 1.0f; } void ComAudio::setBackgroundMusicVolume(float volume) { - CocosDenshion::SimpleAudioEngine::getInstance()->setBackgroundMusicVolume(volume); } float ComAudio::getEffectsVolume() { - return CocosDenshion::SimpleAudioEngine::getInstance()->getEffectsVolume(); + return 1.0f; } void ComAudio::setEffectsVolume(float volume) { - CocosDenshion::SimpleAudioEngine::getInstance()->setEffectsVolume(volume); } unsigned int ComAudio::playEffect(const char* pszFilePath, bool loop) { - return CocosDenshion::SimpleAudioEngine::getInstance()->playEffect(pszFilePath, loop); + return 0; } unsigned int ComAudio::playEffect(const char* pszFilePath) { - return CocosDenshion::SimpleAudioEngine::getInstance()->playEffect(pszFilePath); + return 0; } unsigned int ComAudio::playEffect() { - return CocosDenshion::SimpleAudioEngine::getInstance()->playEffect(_filePath.c_str(), _loop); + return 0; } void ComAudio::pauseEffect(unsigned int nSoundId) { - return CocosDenshion::SimpleAudioEngine::getInstance()->pauseEffect(nSoundId); } void ComAudio::pauseAllEffects() { - CocosDenshion::SimpleAudioEngine::getInstance()->pauseAllEffects(); } void ComAudio::resumeEffect(unsigned int nSoundId) { - CocosDenshion::SimpleAudioEngine::getInstance()->resumeEffect(nSoundId); } void ComAudio::resumeAllEffects() { - CocosDenshion::SimpleAudioEngine::getInstance()->resumeAllEffects(); } void ComAudio::stopEffect(unsigned int nSoundId) { - CocosDenshion::SimpleAudioEngine::getInstance()->stopEffect(nSoundId); } void ComAudio::stopAllEffects() { - CocosDenshion::SimpleAudioEngine::getInstance()->stopAllEffects(); } void ComAudio::preloadEffect(const char* pszFilePath) { - CocosDenshion::SimpleAudioEngine::getInstance()->preloadEffect(pszFilePath); - setFile(pszFilePath); - setLoop(false); } void ComAudio::unloadEffect(const char *pszFilePath) { - CocosDenshion::SimpleAudioEngine::getInstance()->unloadEffect(pszFilePath); } void ComAudio::setFile(const char* pszFilePath) diff --git a/cocos/editor-support/cocostudio/CCSSceneReader.cpp b/cocos/editor-support/cocostudio/CCSSceneReader.cpp index 0f6f3b2..49b6e3e 100644 --- a/cocos/editor-support/cocostudio/CCSSceneReader.cpp +++ b/cocos/editor-support/cocostudio/CCSSceneReader.cpp @@ -25,7 +25,6 @@ THE SOFTWARE. #include "editor-support/cocostudio/CocoStudio.h" #include "ui/CocosGUI.h" -#include "editor-support/cocostudio/SimpleAudioEngine.h" #include "base/ObjectFactory.h" #include "base/ccUtils.h" #include "platform/CCFileUtils.h" @@ -577,7 +576,6 @@ void SceneReader::destroyInstance() { DictionaryHelper::destroyInstance(); TriggerMng::destroyInstance(); - CocosDenshion::SimpleAudioEngine::end(); CC_SAFE_DELETE(s_sharedReader); } diff --git a/cocos/editor-support/cocostudio/CMakeLists.txt b/cocos/editor-support/cocostudio/CMakeLists.txt index d4cb089..740516c 100644 --- a/cocos/editor-support/cocostudio/CMakeLists.txt +++ b/cocos/editor-support/cocostudio/CMakeLists.txt @@ -1,5 +1,4 @@ set(COCOS_CS_HEADER - editor-support/cocostudio/SimpleAudioEngine.h editor-support/cocostudio/CCProcessBase.h editor-support/cocostudio/TriggerMng.h editor-support/cocostudio/CCDataReaderHelper.h @@ -96,7 +95,6 @@ set(COCOS_CS_HEADER ) set(COCOS_CS_SRC - editor-support/cocostudio/SimpleAudioEngine.cpp editor-support/cocostudio/CCActionFrame.cpp editor-support/cocostudio/CCActionFrameEasing.cpp editor-support/cocostudio/CCActionManagerEx.cpp diff --git a/cocos/scripting/lua-bindings/CMakeLists.txt b/cocos/scripting/lua-bindings/CMakeLists.txt index a2a128c..cdae15d 100644 --- a/cocos/scripting/lua-bindings/CMakeLists.txt +++ b/cocos/scripting/lua-bindings/CMakeLists.txt @@ -16,7 +16,6 @@ set(lua_bindings_manual_headers manual/network/Lua_web_socket.h manual/network/lua_extensions.h manual/network/lua_downloader.h - manual/audioengine/lua_cocos2dx_audioengine_manual.h manual/Lua-BindingsExport.h manual/tolua_fix.h manual/navmesh/lua_cocos2dx_navmesh_manual.h @@ -60,14 +59,12 @@ set(lua_bindings_manual_files #manual/spine/lua_cocos2dx_spine_manual.cpp manual/spine/LuaSkeletonAnimation.cpp manual/ui/lua_cocos2dx_ui_manual.cpp - manual/audioengine/lua_cocos2dx_audioengine_manual.cpp manual/physics3d/lua_cocos2dx_physics3d_manual.cpp manual/navmesh/lua_cocos2dx_navmesh_conversions.cpp manual/navmesh/lua_cocos2dx_navmesh_manual.cpp ) set(lua_bindings_auto_headers - auto/lua_cocos2dx_audioengine_auto.hpp auto/lua_cocos2dx_3d_auto.hpp auto/lua_cocos2dx_controller_auto.hpp auto/lua_cocos2dx_spine_auto.hpp @@ -92,7 +89,6 @@ set(lua_bindings_auto_files auto/lua_cocos2dx_studio_auto.cpp auto/lua_cocos2dx_csloader_auto.cpp auto/lua_cocos2dx_ui_auto.cpp - auto/lua_cocos2dx_audioengine_auto.cpp auto/lua_cocos2dx_physics3d_auto.cpp auto/lua_cocos2dx_navmesh_auto.cpp auto/lua_cocos2dx_backend_auto.cpp diff --git a/cocos/scripting/lua-bindings/auto/lua_cocos2dx_audioengine_auto.cpp b/cocos/scripting/lua-bindings/auto/lua_cocos2dx_audioengine_auto.cpp deleted file mode 100644 index 5e68b62..0000000 --- a/cocos/scripting/lua-bindings/auto/lua_cocos2dx_audioengine_auto.cpp +++ /dev/null @@ -1,1161 +0,0 @@ -#include "scripting/lua-bindings/auto/lua_cocos2dx_audioengine_auto.hpp" -#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_MAC || CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 || CC_TARGET_PLATFORM == CC_PLATFORM_LINUX -#include "audio/include/AudioEngine.h" -#include "scripting/lua-bindings/manual/tolua_fix.h" -#include "scripting/lua-bindings/manual/LuaBasicConversions.h" - -int lua_cocos2dx_audioengine_AudioProfile_constructor(lua_State* tolua_S) -{ - int argc = 0; - cocos2d::AudioProfile* cobj = nullptr; - bool ok = true; - -#if COCOS2D_DEBUG >= 1 - tolua_Error tolua_err; -#endif - - - - argc = lua_gettop(tolua_S)-1; - if (argc == 0) - { - if(!ok) - { - tolua_error(tolua_S,"invalid arguments in function 'lua_cocos2dx_audioengine_AudioProfile_constructor'", nullptr); - return 0; - } - cobj = new cocos2d::AudioProfile(); - tolua_pushusertype(tolua_S,(void*)cobj,"cc.AudioProfile"); - tolua_register_gc(tolua_S,lua_gettop(tolua_S)); - return 1; - } - luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d \n", "cc.AudioProfile:AudioProfile",argc, 0); - return 0; - -#if COCOS2D_DEBUG >= 1 - tolua_error(tolua_S,"#ferror in function 'lua_cocos2dx_audioengine_AudioProfile_constructor'.",&tolua_err); -#endif - - return 0; -} - -static int lua_cocos2dx_audioengine_AudioProfile_finalize(lua_State* tolua_S) -{ - printf("luabindings: finalizing LUA object (AudioProfile)"); - return 0; -} - -int lua_register_cocos2dx_audioengine_AudioProfile(lua_State* tolua_S) -{ - tolua_usertype(tolua_S,"cc.AudioProfile"); - tolua_cclass(tolua_S,"AudioProfile","cc.AudioProfile","",nullptr); - - tolua_beginmodule(tolua_S,"AudioProfile"); - tolua_function(tolua_S,"new",lua_cocos2dx_audioengine_AudioProfile_constructor); - tolua_endmodule(tolua_S); - std::string typeName = typeid(cocos2d::AudioProfile).name(); - g_luaType[typeName] = "cc.AudioProfile"; - g_typeCast["AudioProfile"] = "cc.AudioProfile"; - return 1; -} - -int lua_cocos2dx_audioengine_AudioEngine_lazyInit(lua_State* tolua_S) -{ - int argc = 0; - bool ok = true; - -#if COCOS2D_DEBUG >= 1 - tolua_Error tolua_err; -#endif - -#if COCOS2D_DEBUG >= 1 - if (!tolua_isusertable(tolua_S,1,"cc.AudioEngine",0,&tolua_err)) goto tolua_lerror; -#endif - - argc = lua_gettop(tolua_S) - 1; - - if (argc == 0) - { - if(!ok) - { - tolua_error(tolua_S,"invalid arguments in function 'lua_cocos2dx_audioengine_AudioEngine_lazyInit'", nullptr); - return 0; - } - bool ret = cocos2d::AudioEngine::lazyInit(); - tolua_pushboolean(tolua_S,(bool)ret); - return 1; - } - luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d\n ", "cc.AudioEngine:lazyInit",argc, 0); - return 0; -#if COCOS2D_DEBUG >= 1 - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'lua_cocos2dx_audioengine_AudioEngine_lazyInit'.",&tolua_err); -#endif - return 0; -} -int lua_cocos2dx_audioengine_AudioEngine_setCurrentTime(lua_State* tolua_S) -{ - int argc = 0; - bool ok = true; - -#if COCOS2D_DEBUG >= 1 - tolua_Error tolua_err; -#endif - -#if COCOS2D_DEBUG >= 1 - if (!tolua_isusertable(tolua_S,1,"cc.AudioEngine",0,&tolua_err)) goto tolua_lerror; -#endif - - argc = lua_gettop(tolua_S) - 1; - - if (argc == 2) - { - int arg0; - double arg1; - ok &= luaval_to_int32(tolua_S, 2,(int *)&arg0, "cc.AudioEngine:setCurrentTime"); - ok &= luaval_to_number(tolua_S, 3,&arg1, "cc.AudioEngine:setCurrentTime"); - if(!ok) - { - tolua_error(tolua_S,"invalid arguments in function 'lua_cocos2dx_audioengine_AudioEngine_setCurrentTime'", nullptr); - return 0; - } - bool ret = cocos2d::AudioEngine::setCurrentTime(arg0, arg1); - tolua_pushboolean(tolua_S,(bool)ret); - return 1; - } - luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d\n ", "cc.AudioEngine:setCurrentTime",argc, 2); - return 0; -#if COCOS2D_DEBUG >= 1 - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'lua_cocos2dx_audioengine_AudioEngine_setCurrentTime'.",&tolua_err); -#endif - return 0; -} -int lua_cocos2dx_audioengine_AudioEngine_getVolume(lua_State* tolua_S) -{ - int argc = 0; - bool ok = true; - -#if COCOS2D_DEBUG >= 1 - tolua_Error tolua_err; -#endif - -#if COCOS2D_DEBUG >= 1 - if (!tolua_isusertable(tolua_S,1,"cc.AudioEngine",0,&tolua_err)) goto tolua_lerror; -#endif - - argc = lua_gettop(tolua_S) - 1; - - if (argc == 1) - { - int arg0; - ok &= luaval_to_int32(tolua_S, 2,(int *)&arg0, "cc.AudioEngine:getVolume"); - if(!ok) - { - tolua_error(tolua_S,"invalid arguments in function 'lua_cocos2dx_audioengine_AudioEngine_getVolume'", nullptr); - return 0; - } - double ret = cocos2d::AudioEngine::getVolume(arg0); - tolua_pushnumber(tolua_S,(lua_Number)ret); - return 1; - } - luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d\n ", "cc.AudioEngine:getVolume",argc, 1); - return 0; -#if COCOS2D_DEBUG >= 1 - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'lua_cocos2dx_audioengine_AudioEngine_getVolume'.",&tolua_err); -#endif - return 0; -} -int lua_cocos2dx_audioengine_AudioEngine_uncache(lua_State* tolua_S) -{ - int argc = 0; - bool ok = true; - -#if COCOS2D_DEBUG >= 1 - tolua_Error tolua_err; -#endif - -#if COCOS2D_DEBUG >= 1 - if (!tolua_isusertable(tolua_S,1,"cc.AudioEngine",0,&tolua_err)) goto tolua_lerror; -#endif - - argc = lua_gettop(tolua_S) - 1; - - if (argc == 1) - { - std::string arg0; - ok &= luaval_to_std_string(tolua_S, 2,&arg0, "cc.AudioEngine:uncache"); - if(!ok) - { - tolua_error(tolua_S,"invalid arguments in function 'lua_cocos2dx_audioengine_AudioEngine_uncache'", nullptr); - return 0; - } - cocos2d::AudioEngine::uncache(arg0); - lua_settop(tolua_S, 1); - return 1; - } - luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d\n ", "cc.AudioEngine:uncache",argc, 1); - return 0; -#if COCOS2D_DEBUG >= 1 - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'lua_cocos2dx_audioengine_AudioEngine_uncache'.",&tolua_err); -#endif - return 0; -} -int lua_cocos2dx_audioengine_AudioEngine_resumeAll(lua_State* tolua_S) -{ - int argc = 0; - bool ok = true; - -#if COCOS2D_DEBUG >= 1 - tolua_Error tolua_err; -#endif - -#if COCOS2D_DEBUG >= 1 - if (!tolua_isusertable(tolua_S,1,"cc.AudioEngine",0,&tolua_err)) goto tolua_lerror; -#endif - - argc = lua_gettop(tolua_S) - 1; - - if (argc == 0) - { - if(!ok) - { - tolua_error(tolua_S,"invalid arguments in function 'lua_cocos2dx_audioengine_AudioEngine_resumeAll'", nullptr); - return 0; - } - cocos2d::AudioEngine::resumeAll(); - lua_settop(tolua_S, 1); - return 1; - } - luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d\n ", "cc.AudioEngine:resumeAll",argc, 0); - return 0; -#if COCOS2D_DEBUG >= 1 - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'lua_cocos2dx_audioengine_AudioEngine_resumeAll'.",&tolua_err); -#endif - return 0; -} -int lua_cocos2dx_audioengine_AudioEngine_stopAll(lua_State* tolua_S) -{ - int argc = 0; - bool ok = true; - -#if COCOS2D_DEBUG >= 1 - tolua_Error tolua_err; -#endif - -#if COCOS2D_DEBUG >= 1 - if (!tolua_isusertable(tolua_S,1,"cc.AudioEngine",0,&tolua_err)) goto tolua_lerror; -#endif - - argc = lua_gettop(tolua_S) - 1; - - if (argc == 0) - { - if(!ok) - { - tolua_error(tolua_S,"invalid arguments in function 'lua_cocos2dx_audioengine_AudioEngine_stopAll'", nullptr); - return 0; - } - cocos2d::AudioEngine::stopAll(); - lua_settop(tolua_S, 1); - return 1; - } - luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d\n ", "cc.AudioEngine:stopAll",argc, 0); - return 0; -#if COCOS2D_DEBUG >= 1 - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'lua_cocos2dx_audioengine_AudioEngine_stopAll'.",&tolua_err); -#endif - return 0; -} -int lua_cocos2dx_audioengine_AudioEngine_pause(lua_State* tolua_S) -{ - int argc = 0; - bool ok = true; - -#if COCOS2D_DEBUG >= 1 - tolua_Error tolua_err; -#endif - -#if COCOS2D_DEBUG >= 1 - if (!tolua_isusertable(tolua_S,1,"cc.AudioEngine",0,&tolua_err)) goto tolua_lerror; -#endif - - argc = lua_gettop(tolua_S) - 1; - - if (argc == 1) - { - int arg0; - ok &= luaval_to_int32(tolua_S, 2,(int *)&arg0, "cc.AudioEngine:pause"); - if(!ok) - { - tolua_error(tolua_S,"invalid arguments in function 'lua_cocos2dx_audioengine_AudioEngine_pause'", nullptr); - return 0; - } - cocos2d::AudioEngine::pause(arg0); - lua_settop(tolua_S, 1); - return 1; - } - luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d\n ", "cc.AudioEngine:pause",argc, 1); - return 0; -#if COCOS2D_DEBUG >= 1 - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'lua_cocos2dx_audioengine_AudioEngine_pause'.",&tolua_err); -#endif - return 0; -} -int lua_cocos2dx_audioengine_AudioEngine_getMaxAudioInstance(lua_State* tolua_S) -{ - int argc = 0; - bool ok = true; - -#if COCOS2D_DEBUG >= 1 - tolua_Error tolua_err; -#endif - -#if COCOS2D_DEBUG >= 1 - if (!tolua_isusertable(tolua_S,1,"cc.AudioEngine",0,&tolua_err)) goto tolua_lerror; -#endif - - argc = lua_gettop(tolua_S) - 1; - - if (argc == 0) - { - if(!ok) - { - tolua_error(tolua_S,"invalid arguments in function 'lua_cocos2dx_audioengine_AudioEngine_getMaxAudioInstance'", nullptr); - return 0; - } - int ret = cocos2d::AudioEngine::getMaxAudioInstance(); - tolua_pushnumber(tolua_S,(lua_Number)ret); - return 1; - } - luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d\n ", "cc.AudioEngine:getMaxAudioInstance",argc, 0); - return 0; -#if COCOS2D_DEBUG >= 1 - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'lua_cocos2dx_audioengine_AudioEngine_getMaxAudioInstance'.",&tolua_err); -#endif - return 0; -} -int lua_cocos2dx_audioengine_AudioEngine_isEnabled(lua_State* tolua_S) -{ - int argc = 0; - bool ok = true; - -#if COCOS2D_DEBUG >= 1 - tolua_Error tolua_err; -#endif - -#if COCOS2D_DEBUG >= 1 - if (!tolua_isusertable(tolua_S,1,"cc.AudioEngine",0,&tolua_err)) goto tolua_lerror; -#endif - - argc = lua_gettop(tolua_S) - 1; - - if (argc == 0) - { - if(!ok) - { - tolua_error(tolua_S,"invalid arguments in function 'lua_cocos2dx_audioengine_AudioEngine_isEnabled'", nullptr); - return 0; - } - bool ret = cocos2d::AudioEngine::isEnabled(); - tolua_pushboolean(tolua_S,(bool)ret); - return 1; - } - luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d\n ", "cc.AudioEngine:isEnabled",argc, 0); - return 0; -#if COCOS2D_DEBUG >= 1 - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'lua_cocos2dx_audioengine_AudioEngine_isEnabled'.",&tolua_err); -#endif - return 0; -} -int lua_cocos2dx_audioengine_AudioEngine_getCurrentTime(lua_State* tolua_S) -{ - int argc = 0; - bool ok = true; - -#if COCOS2D_DEBUG >= 1 - tolua_Error tolua_err; -#endif - -#if COCOS2D_DEBUG >= 1 - if (!tolua_isusertable(tolua_S,1,"cc.AudioEngine",0,&tolua_err)) goto tolua_lerror; -#endif - - argc = lua_gettop(tolua_S) - 1; - - if (argc == 1) - { - int arg0; - ok &= luaval_to_int32(tolua_S, 2,(int *)&arg0, "cc.AudioEngine:getCurrentTime"); - if(!ok) - { - tolua_error(tolua_S,"invalid arguments in function 'lua_cocos2dx_audioengine_AudioEngine_getCurrentTime'", nullptr); - return 0; - } - double ret = cocos2d::AudioEngine::getCurrentTime(arg0); - tolua_pushnumber(tolua_S,(lua_Number)ret); - return 1; - } - luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d\n ", "cc.AudioEngine:getCurrentTime",argc, 1); - return 0; -#if COCOS2D_DEBUG >= 1 - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'lua_cocos2dx_audioengine_AudioEngine_getCurrentTime'.",&tolua_err); -#endif - return 0; -} -int lua_cocos2dx_audioengine_AudioEngine_setMaxAudioInstance(lua_State* tolua_S) -{ - int argc = 0; - bool ok = true; - -#if COCOS2D_DEBUG >= 1 - tolua_Error tolua_err; -#endif - -#if COCOS2D_DEBUG >= 1 - if (!tolua_isusertable(tolua_S,1,"cc.AudioEngine",0,&tolua_err)) goto tolua_lerror; -#endif - - argc = lua_gettop(tolua_S) - 1; - - if (argc == 1) - { - int arg0; - ok &= luaval_to_int32(tolua_S, 2,(int *)&arg0, "cc.AudioEngine:setMaxAudioInstance"); - if(!ok) - { - tolua_error(tolua_S,"invalid arguments in function 'lua_cocos2dx_audioengine_AudioEngine_setMaxAudioInstance'", nullptr); - return 0; - } - bool ret = cocos2d::AudioEngine::setMaxAudioInstance(arg0); - tolua_pushboolean(tolua_S,(bool)ret); - return 1; - } - luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d\n ", "cc.AudioEngine:setMaxAudioInstance",argc, 1); - return 0; -#if COCOS2D_DEBUG >= 1 - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'lua_cocos2dx_audioengine_AudioEngine_setMaxAudioInstance'.",&tolua_err); -#endif - return 0; -} -int lua_cocos2dx_audioengine_AudioEngine_isLoop(lua_State* tolua_S) -{ - int argc = 0; - bool ok = true; - -#if COCOS2D_DEBUG >= 1 - tolua_Error tolua_err; -#endif - -#if COCOS2D_DEBUG >= 1 - if (!tolua_isusertable(tolua_S,1,"cc.AudioEngine",0,&tolua_err)) goto tolua_lerror; -#endif - - argc = lua_gettop(tolua_S) - 1; - - if (argc == 1) - { - int arg0; - ok &= luaval_to_int32(tolua_S, 2,(int *)&arg0, "cc.AudioEngine:isLoop"); - if(!ok) - { - tolua_error(tolua_S,"invalid arguments in function 'lua_cocos2dx_audioengine_AudioEngine_isLoop'", nullptr); - return 0; - } - bool ret = cocos2d::AudioEngine::isLoop(arg0); - tolua_pushboolean(tolua_S,(bool)ret); - return 1; - } - luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d\n ", "cc.AudioEngine:isLoop",argc, 1); - return 0; -#if COCOS2D_DEBUG >= 1 - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'lua_cocos2dx_audioengine_AudioEngine_isLoop'.",&tolua_err); -#endif - return 0; -} -int lua_cocos2dx_audioengine_AudioEngine_pauseAll(lua_State* tolua_S) -{ - int argc = 0; - bool ok = true; - -#if COCOS2D_DEBUG >= 1 - tolua_Error tolua_err; -#endif - -#if COCOS2D_DEBUG >= 1 - if (!tolua_isusertable(tolua_S,1,"cc.AudioEngine",0,&tolua_err)) goto tolua_lerror; -#endif - - argc = lua_gettop(tolua_S) - 1; - - if (argc == 0) - { - if(!ok) - { - tolua_error(tolua_S,"invalid arguments in function 'lua_cocos2dx_audioengine_AudioEngine_pauseAll'", nullptr); - return 0; - } - cocos2d::AudioEngine::pauseAll(); - lua_settop(tolua_S, 1); - return 1; - } - luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d\n ", "cc.AudioEngine:pauseAll",argc, 0); - return 0; -#if COCOS2D_DEBUG >= 1 - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'lua_cocos2dx_audioengine_AudioEngine_pauseAll'.",&tolua_err); -#endif - return 0; -} -int lua_cocos2dx_audioengine_AudioEngine_uncacheAll(lua_State* tolua_S) -{ - int argc = 0; - bool ok = true; - -#if COCOS2D_DEBUG >= 1 - tolua_Error tolua_err; -#endif - -#if COCOS2D_DEBUG >= 1 - if (!tolua_isusertable(tolua_S,1,"cc.AudioEngine",0,&tolua_err)) goto tolua_lerror; -#endif - - argc = lua_gettop(tolua_S) - 1; - - if (argc == 0) - { - if(!ok) - { - tolua_error(tolua_S,"invalid arguments in function 'lua_cocos2dx_audioengine_AudioEngine_uncacheAll'", nullptr); - return 0; - } - cocos2d::AudioEngine::uncacheAll(); - lua_settop(tolua_S, 1); - return 1; - } - luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d\n ", "cc.AudioEngine:uncacheAll",argc, 0); - return 0; -#if COCOS2D_DEBUG >= 1 - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'lua_cocos2dx_audioengine_AudioEngine_uncacheAll'.",&tolua_err); -#endif - return 0; -} -int lua_cocos2dx_audioengine_AudioEngine_setVolume(lua_State* tolua_S) -{ - int argc = 0; - bool ok = true; - -#if COCOS2D_DEBUG >= 1 - tolua_Error tolua_err; -#endif - -#if COCOS2D_DEBUG >= 1 - if (!tolua_isusertable(tolua_S,1,"cc.AudioEngine",0,&tolua_err)) goto tolua_lerror; -#endif - - argc = lua_gettop(tolua_S) - 1; - - if (argc == 2) - { - int arg0; - double arg1; - ok &= luaval_to_int32(tolua_S, 2,(int *)&arg0, "cc.AudioEngine:setVolume"); - ok &= luaval_to_number(tolua_S, 3,&arg1, "cc.AudioEngine:setVolume"); - if(!ok) - { - tolua_error(tolua_S,"invalid arguments in function 'lua_cocos2dx_audioengine_AudioEngine_setVolume'", nullptr); - return 0; - } - cocos2d::AudioEngine::setVolume(arg0, arg1); - lua_settop(tolua_S, 1); - return 1; - } - luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d\n ", "cc.AudioEngine:setVolume",argc, 2); - return 0; -#if COCOS2D_DEBUG >= 1 - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'lua_cocos2dx_audioengine_AudioEngine_setVolume'.",&tolua_err); -#endif - return 0; -} -int lua_cocos2dx_audioengine_AudioEngine_preload(lua_State* tolua_S) -{ - int argc = 0; - bool ok = true; -#if COCOS2D_DEBUG >= 1 - tolua_Error tolua_err; -#endif - -#if COCOS2D_DEBUG >= 1 - if (!tolua_isusertable(tolua_S,1,"cc.AudioEngine",0,&tolua_err)) goto tolua_lerror; -#endif - - argc = lua_gettop(tolua_S)-1; - - do - { - if (argc == 2) - { - std::string arg0; - ok &= luaval_to_std_string(tolua_S, 2,&arg0, "cc.AudioEngine:preload"); - if (!ok) { break; } - std::function arg1; - do { - // Lambda binding for lua is not supported. - assert(false); - } while(0) - ; - if (!ok) { break; } - cocos2d::AudioEngine::preload(arg0, arg1); - lua_settop(tolua_S, 1); - return 1; - } - } while (0); - ok = true; - do - { - if (argc == 1) - { - std::string arg0; - ok &= luaval_to_std_string(tolua_S, 2,&arg0, "cc.AudioEngine:preload"); - if (!ok) { break; } - cocos2d::AudioEngine::preload(arg0); - lua_settop(tolua_S, 1); - return 1; - } - } while (0); - ok = true; - luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d", "cc.AudioEngine:preload",argc, 1); - return 0; -#if COCOS2D_DEBUG >= 1 - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'lua_cocos2dx_audioengine_AudioEngine_preload'.",&tolua_err); -#endif - return 0; -} -int lua_cocos2dx_audioengine_AudioEngine_setEnabled(lua_State* tolua_S) -{ - int argc = 0; - bool ok = true; - -#if COCOS2D_DEBUG >= 1 - tolua_Error tolua_err; -#endif - -#if COCOS2D_DEBUG >= 1 - if (!tolua_isusertable(tolua_S,1,"cc.AudioEngine",0,&tolua_err)) goto tolua_lerror; -#endif - - argc = lua_gettop(tolua_S) - 1; - - if (argc == 1) - { - bool arg0; - ok &= luaval_to_boolean(tolua_S, 2,&arg0, "cc.AudioEngine:setEnabled"); - if(!ok) - { - tolua_error(tolua_S,"invalid arguments in function 'lua_cocos2dx_audioengine_AudioEngine_setEnabled'", nullptr); - return 0; - } - cocos2d::AudioEngine::setEnabled(arg0); - lua_settop(tolua_S, 1); - return 1; - } - luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d\n ", "cc.AudioEngine:setEnabled",argc, 1); - return 0; -#if COCOS2D_DEBUG >= 1 - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'lua_cocos2dx_audioengine_AudioEngine_setEnabled'.",&tolua_err); -#endif - return 0; -} -int lua_cocos2dx_audioengine_AudioEngine_play2d(lua_State* tolua_S) -{ - int argc = 0; - bool ok = true; - -#if COCOS2D_DEBUG >= 1 - tolua_Error tolua_err; -#endif - -#if COCOS2D_DEBUG >= 1 - if (!tolua_isusertable(tolua_S,1,"cc.AudioEngine",0,&tolua_err)) goto tolua_lerror; -#endif - - argc = lua_gettop(tolua_S) - 1; - - if (argc == 1) - { - std::string arg0; - ok &= luaval_to_std_string(tolua_S, 2,&arg0, "cc.AudioEngine:play2d"); - if(!ok) - { - tolua_error(tolua_S,"invalid arguments in function 'lua_cocos2dx_audioengine_AudioEngine_play2d'", nullptr); - return 0; - } - int ret = cocos2d::AudioEngine::play2d(arg0); - tolua_pushnumber(tolua_S,(lua_Number)ret); - return 1; - } - if (argc == 2) - { - std::string arg0; - bool arg1; - ok &= luaval_to_std_string(tolua_S, 2,&arg0, "cc.AudioEngine:play2d"); - ok &= luaval_to_boolean(tolua_S, 3,&arg1, "cc.AudioEngine:play2d"); - if(!ok) - { - tolua_error(tolua_S,"invalid arguments in function 'lua_cocos2dx_audioengine_AudioEngine_play2d'", nullptr); - return 0; - } - int ret = cocos2d::AudioEngine::play2d(arg0, arg1); - tolua_pushnumber(tolua_S,(lua_Number)ret); - return 1; - } - if (argc == 3) - { - std::string arg0; - bool arg1; - double arg2; - ok &= luaval_to_std_string(tolua_S, 2,&arg0, "cc.AudioEngine:play2d"); - ok &= luaval_to_boolean(tolua_S, 3,&arg1, "cc.AudioEngine:play2d"); - ok &= luaval_to_number(tolua_S, 4,&arg2, "cc.AudioEngine:play2d"); - if(!ok) - { - tolua_error(tolua_S,"invalid arguments in function 'lua_cocos2dx_audioengine_AudioEngine_play2d'", nullptr); - return 0; - } - int ret = cocos2d::AudioEngine::play2d(arg0, arg1, arg2); - tolua_pushnumber(tolua_S,(lua_Number)ret); - return 1; - } - if (argc == 4) - { - std::string arg0; - bool arg1; - double arg2; - const cocos2d::AudioProfile* arg3; - ok &= luaval_to_std_string(tolua_S, 2,&arg0, "cc.AudioEngine:play2d"); - ok &= luaval_to_boolean(tolua_S, 3,&arg1, "cc.AudioEngine:play2d"); - ok &= luaval_to_number(tolua_S, 4,&arg2, "cc.AudioEngine:play2d"); - ok &= luaval_to_object(tolua_S, 5, "cc.AudioProfile",&arg3, "cc.AudioEngine:play2d"); - if(!ok) - { - tolua_error(tolua_S,"invalid arguments in function 'lua_cocos2dx_audioengine_AudioEngine_play2d'", nullptr); - return 0; - } - int ret = cocos2d::AudioEngine::play2d(arg0, arg1, arg2, arg3); - tolua_pushnumber(tolua_S,(lua_Number)ret); - return 1; - } - luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d\n ", "cc.AudioEngine:play2d",argc, 1); - return 0; -#if COCOS2D_DEBUG >= 1 - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'lua_cocos2dx_audioengine_AudioEngine_play2d'.",&tolua_err); -#endif - return 0; -} -int lua_cocos2dx_audioengine_AudioEngine_getState(lua_State* tolua_S) -{ - int argc = 0; - bool ok = true; - -#if COCOS2D_DEBUG >= 1 - tolua_Error tolua_err; -#endif - -#if COCOS2D_DEBUG >= 1 - if (!tolua_isusertable(tolua_S,1,"cc.AudioEngine",0,&tolua_err)) goto tolua_lerror; -#endif - - argc = lua_gettop(tolua_S) - 1; - - if (argc == 1) - { - int arg0; - ok &= luaval_to_int32(tolua_S, 2,(int *)&arg0, "cc.AudioEngine:getState"); - if(!ok) - { - tolua_error(tolua_S,"invalid arguments in function 'lua_cocos2dx_audioengine_AudioEngine_getState'", nullptr); - return 0; - } - int ret = (int)cocos2d::AudioEngine::getState(arg0); - tolua_pushnumber(tolua_S,(lua_Number)ret); - return 1; - } - luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d\n ", "cc.AudioEngine:getState",argc, 1); - return 0; -#if COCOS2D_DEBUG >= 1 - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'lua_cocos2dx_audioengine_AudioEngine_getState'.",&tolua_err); -#endif - return 0; -} -int lua_cocos2dx_audioengine_AudioEngine_resume(lua_State* tolua_S) -{ - int argc = 0; - bool ok = true; - -#if COCOS2D_DEBUG >= 1 - tolua_Error tolua_err; -#endif - -#if COCOS2D_DEBUG >= 1 - if (!tolua_isusertable(tolua_S,1,"cc.AudioEngine",0,&tolua_err)) goto tolua_lerror; -#endif - - argc = lua_gettop(tolua_S) - 1; - - if (argc == 1) - { - int arg0; - ok &= luaval_to_int32(tolua_S, 2,(int *)&arg0, "cc.AudioEngine:resume"); - if(!ok) - { - tolua_error(tolua_S,"invalid arguments in function 'lua_cocos2dx_audioengine_AudioEngine_resume'", nullptr); - return 0; - } - cocos2d::AudioEngine::resume(arg0); - lua_settop(tolua_S, 1); - return 1; - } - luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d\n ", "cc.AudioEngine:resume",argc, 1); - return 0; -#if COCOS2D_DEBUG >= 1 - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'lua_cocos2dx_audioengine_AudioEngine_resume'.",&tolua_err); -#endif - return 0; -} -int lua_cocos2dx_audioengine_AudioEngine_stop(lua_State* tolua_S) -{ - int argc = 0; - bool ok = true; - -#if COCOS2D_DEBUG >= 1 - tolua_Error tolua_err; -#endif - -#if COCOS2D_DEBUG >= 1 - if (!tolua_isusertable(tolua_S,1,"cc.AudioEngine",0,&tolua_err)) goto tolua_lerror; -#endif - - argc = lua_gettop(tolua_S) - 1; - - if (argc == 1) - { - int arg0; - ok &= luaval_to_int32(tolua_S, 2,(int *)&arg0, "cc.AudioEngine:stop"); - if(!ok) - { - tolua_error(tolua_S,"invalid arguments in function 'lua_cocos2dx_audioengine_AudioEngine_stop'", nullptr); - return 0; - } - cocos2d::AudioEngine::stop(arg0); - lua_settop(tolua_S, 1); - return 1; - } - luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d\n ", "cc.AudioEngine:stop",argc, 1); - return 0; -#if COCOS2D_DEBUG >= 1 - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'lua_cocos2dx_audioengine_AudioEngine_stop'.",&tolua_err); -#endif - return 0; -} -int lua_cocos2dx_audioengine_AudioEngine_end(lua_State* tolua_S) -{ - int argc = 0; - bool ok = true; - -#if COCOS2D_DEBUG >= 1 - tolua_Error tolua_err; -#endif - -#if COCOS2D_DEBUG >= 1 - if (!tolua_isusertable(tolua_S,1,"cc.AudioEngine",0,&tolua_err)) goto tolua_lerror; -#endif - - argc = lua_gettop(tolua_S) - 1; - - if (argc == 0) - { - if(!ok) - { - tolua_error(tolua_S,"invalid arguments in function 'lua_cocos2dx_audioengine_AudioEngine_end'", nullptr); - return 0; - } - cocos2d::AudioEngine::end(); - lua_settop(tolua_S, 1); - return 1; - } - luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d\n ", "cc.AudioEngine:end",argc, 0); - return 0; -#if COCOS2D_DEBUG >= 1 - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'lua_cocos2dx_audioengine_AudioEngine_end'.",&tolua_err); -#endif - return 0; -} -int lua_cocos2dx_audioengine_AudioEngine_getDuration(lua_State* tolua_S) -{ - int argc = 0; - bool ok = true; - -#if COCOS2D_DEBUG >= 1 - tolua_Error tolua_err; -#endif - -#if COCOS2D_DEBUG >= 1 - if (!tolua_isusertable(tolua_S,1,"cc.AudioEngine",0,&tolua_err)) goto tolua_lerror; -#endif - - argc = lua_gettop(tolua_S) - 1; - - if (argc == 1) - { - int arg0; - ok &= luaval_to_int32(tolua_S, 2,(int *)&arg0, "cc.AudioEngine:getDuration"); - if(!ok) - { - tolua_error(tolua_S,"invalid arguments in function 'lua_cocos2dx_audioengine_AudioEngine_getDuration'", nullptr); - return 0; - } - double ret = cocos2d::AudioEngine::getDuration(arg0); - tolua_pushnumber(tolua_S,(lua_Number)ret); - return 1; - } - luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d\n ", "cc.AudioEngine:getDuration",argc, 1); - return 0; -#if COCOS2D_DEBUG >= 1 - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'lua_cocos2dx_audioengine_AudioEngine_getDuration'.",&tolua_err); -#endif - return 0; -} -int lua_cocos2dx_audioengine_AudioEngine_setLoop(lua_State* tolua_S) -{ - int argc = 0; - bool ok = true; - -#if COCOS2D_DEBUG >= 1 - tolua_Error tolua_err; -#endif - -#if COCOS2D_DEBUG >= 1 - if (!tolua_isusertable(tolua_S,1,"cc.AudioEngine",0,&tolua_err)) goto tolua_lerror; -#endif - - argc = lua_gettop(tolua_S) - 1; - - if (argc == 2) - { - int arg0; - bool arg1; - ok &= luaval_to_int32(tolua_S, 2,(int *)&arg0, "cc.AudioEngine:setLoop"); - ok &= luaval_to_boolean(tolua_S, 3,&arg1, "cc.AudioEngine:setLoop"); - if(!ok) - { - tolua_error(tolua_S,"invalid arguments in function 'lua_cocos2dx_audioengine_AudioEngine_setLoop'", nullptr); - return 0; - } - cocos2d::AudioEngine::setLoop(arg0, arg1); - lua_settop(tolua_S, 1); - return 1; - } - luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d\n ", "cc.AudioEngine:setLoop",argc, 2); - return 0; -#if COCOS2D_DEBUG >= 1 - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'lua_cocos2dx_audioengine_AudioEngine_setLoop'.",&tolua_err); -#endif - return 0; -} -int lua_cocos2dx_audioengine_AudioEngine_getDefaultProfile(lua_State* tolua_S) -{ - int argc = 0; - bool ok = true; - -#if COCOS2D_DEBUG >= 1 - tolua_Error tolua_err; -#endif - -#if COCOS2D_DEBUG >= 1 - if (!tolua_isusertable(tolua_S,1,"cc.AudioEngine",0,&tolua_err)) goto tolua_lerror; -#endif - - argc = lua_gettop(tolua_S) - 1; - - if (argc == 0) - { - if(!ok) - { - tolua_error(tolua_S,"invalid arguments in function 'lua_cocos2dx_audioengine_AudioEngine_getDefaultProfile'", nullptr); - return 0; - } - cocos2d::AudioProfile* ret = cocos2d::AudioEngine::getDefaultProfile(); - object_to_luaval(tolua_S, "cc.AudioProfile",(cocos2d::AudioProfile*)ret); - return 1; - } - luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d\n ", "cc.AudioEngine:getDefaultProfile",argc, 0); - return 0; -#if COCOS2D_DEBUG >= 1 - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'lua_cocos2dx_audioengine_AudioEngine_getDefaultProfile'.",&tolua_err); -#endif - return 0; -} -int lua_cocos2dx_audioengine_AudioEngine_getProfile(lua_State* tolua_S) -{ - int argc = 0; - bool ok = true; -#if COCOS2D_DEBUG >= 1 - tolua_Error tolua_err; -#endif - -#if COCOS2D_DEBUG >= 1 - if (!tolua_isusertable(tolua_S,1,"cc.AudioEngine",0,&tolua_err)) goto tolua_lerror; -#endif - - argc = lua_gettop(tolua_S)-1; - - do - { - if (argc == 1) - { - std::string arg0; - ok &= luaval_to_std_string(tolua_S, 2,&arg0, "cc.AudioEngine:getProfile"); - if (!ok) { break; } - cocos2d::AudioProfile* ret = cocos2d::AudioEngine::getProfile(arg0); - object_to_luaval(tolua_S, "cc.AudioProfile",(cocos2d::AudioProfile*)ret); - return 1; - } - } while (0); - ok = true; - do - { - if (argc == 1) - { - int arg0; - ok &= luaval_to_int32(tolua_S, 2,(int *)&arg0, "cc.AudioEngine:getProfile"); - if (!ok) { break; } - cocos2d::AudioProfile* ret = cocos2d::AudioEngine::getProfile(arg0); - object_to_luaval(tolua_S, "cc.AudioProfile",(cocos2d::AudioProfile*)ret); - return 1; - } - } while (0); - ok = true; - luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d", "cc.AudioEngine:getProfile",argc, 1); - return 0; -#if COCOS2D_DEBUG >= 1 - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'lua_cocos2dx_audioengine_AudioEngine_getProfile'.",&tolua_err); -#endif - return 0; -} -int lua_cocos2dx_audioengine_AudioEngine_getPlayingAudioCount(lua_State* tolua_S) -{ - int argc = 0; - bool ok = true; - -#if COCOS2D_DEBUG >= 1 - tolua_Error tolua_err; -#endif - -#if COCOS2D_DEBUG >= 1 - if (!tolua_isusertable(tolua_S,1,"cc.AudioEngine",0,&tolua_err)) goto tolua_lerror; -#endif - - argc = lua_gettop(tolua_S) - 1; - - if (argc == 0) - { - if(!ok) - { - tolua_error(tolua_S,"invalid arguments in function 'lua_cocos2dx_audioengine_AudioEngine_getPlayingAudioCount'", nullptr); - return 0; - } - int ret = cocos2d::AudioEngine::getPlayingAudioCount(); - tolua_pushnumber(tolua_S,(lua_Number)ret); - return 1; - } - luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d\n ", "cc.AudioEngine:getPlayingAudioCount",argc, 0); - return 0; -#if COCOS2D_DEBUG >= 1 - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'lua_cocos2dx_audioengine_AudioEngine_getPlayingAudioCount'.",&tolua_err); -#endif - return 0; -} -static int lua_cocos2dx_audioengine_AudioEngine_finalize(lua_State* tolua_S) -{ - printf("luabindings: finalizing LUA object (AudioEngine)"); - return 0; -} - -int lua_register_cocos2dx_audioengine_AudioEngine(lua_State* tolua_S) -{ - tolua_usertype(tolua_S,"cc.AudioEngine"); - tolua_cclass(tolua_S,"AudioEngine","cc.AudioEngine","",nullptr); - - tolua_beginmodule(tolua_S,"AudioEngine"); - tolua_function(tolua_S,"lazyInit", lua_cocos2dx_audioengine_AudioEngine_lazyInit); - tolua_function(tolua_S,"setCurrentTime", lua_cocos2dx_audioengine_AudioEngine_setCurrentTime); - tolua_function(tolua_S,"getVolume", lua_cocos2dx_audioengine_AudioEngine_getVolume); - tolua_function(tolua_S,"uncache", lua_cocos2dx_audioengine_AudioEngine_uncache); - tolua_function(tolua_S,"resumeAll", lua_cocos2dx_audioengine_AudioEngine_resumeAll); - tolua_function(tolua_S,"stopAll", lua_cocos2dx_audioengine_AudioEngine_stopAll); - tolua_function(tolua_S,"pause", lua_cocos2dx_audioengine_AudioEngine_pause); - tolua_function(tolua_S,"getMaxAudioInstance", lua_cocos2dx_audioengine_AudioEngine_getMaxAudioInstance); - tolua_function(tolua_S,"isEnabled", lua_cocos2dx_audioengine_AudioEngine_isEnabled); - tolua_function(tolua_S,"getCurrentTime", lua_cocos2dx_audioengine_AudioEngine_getCurrentTime); - tolua_function(tolua_S,"setMaxAudioInstance", lua_cocos2dx_audioengine_AudioEngine_setMaxAudioInstance); - tolua_function(tolua_S,"isLoop", lua_cocos2dx_audioengine_AudioEngine_isLoop); - tolua_function(tolua_S,"pauseAll", lua_cocos2dx_audioengine_AudioEngine_pauseAll); - tolua_function(tolua_S,"uncacheAll", lua_cocos2dx_audioengine_AudioEngine_uncacheAll); - tolua_function(tolua_S,"setVolume", lua_cocos2dx_audioengine_AudioEngine_setVolume); - tolua_function(tolua_S,"preload", lua_cocos2dx_audioengine_AudioEngine_preload); - tolua_function(tolua_S,"setEnabled", lua_cocos2dx_audioengine_AudioEngine_setEnabled); - tolua_function(tolua_S,"play2d", lua_cocos2dx_audioengine_AudioEngine_play2d); - tolua_function(tolua_S,"getState", lua_cocos2dx_audioengine_AudioEngine_getState); - tolua_function(tolua_S,"resume", lua_cocos2dx_audioengine_AudioEngine_resume); - tolua_function(tolua_S,"stop", lua_cocos2dx_audioengine_AudioEngine_stop); - tolua_function(tolua_S,"endToLua", lua_cocos2dx_audioengine_AudioEngine_end); - tolua_function(tolua_S,"getDuration", lua_cocos2dx_audioengine_AudioEngine_getDuration); - tolua_function(tolua_S,"setLoop", lua_cocos2dx_audioengine_AudioEngine_setLoop); - tolua_function(tolua_S,"getDefaultProfile", lua_cocos2dx_audioengine_AudioEngine_getDefaultProfile); - tolua_function(tolua_S,"getProfile", lua_cocos2dx_audioengine_AudioEngine_getProfile); - tolua_function(tolua_S,"getPlayingAudioCount", lua_cocos2dx_audioengine_AudioEngine_getPlayingAudioCount); - tolua_endmodule(tolua_S); - std::string typeName = typeid(cocos2d::AudioEngine).name(); - g_luaType[typeName] = "cc.AudioEngine"; - g_typeCast["AudioEngine"] = "cc.AudioEngine"; - return 1; -} -TOLUA_API int register_all_cocos2dx_audioengine(lua_State* tolua_S) -{ - tolua_open(tolua_S); - - tolua_module(tolua_S,"cc",0); - tolua_beginmodule(tolua_S,"cc"); - - lua_register_cocos2dx_audioengine_AudioProfile(tolua_S); - lua_register_cocos2dx_audioengine_AudioEngine(tolua_S); - - tolua_endmodule(tolua_S); - return 1; -} - -#endif diff --git a/cocos/scripting/lua-bindings/auto/lua_cocos2dx_audioengine_auto.hpp b/cocos/scripting/lua-bindings/auto/lua_cocos2dx_audioengine_auto.hpp deleted file mode 100644 index 74f434b..0000000 --- a/cocos/scripting/lua-bindings/auto/lua_cocos2dx_audioengine_auto.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "base/ccConfig.h" -#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_MAC || CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 || CC_TARGET_PLATFORM == CC_PLATFORM_LINUX -#ifndef __cocos2dx_audioengine_h__ -#define __cocos2dx_audioengine_h__ - -#ifdef __cplusplus -extern "C" { -#endif -#include "tolua++.h" -#ifdef __cplusplus -} -#endif - -int register_all_cocos2dx_audioengine(lua_State* tolua_S); - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -#endif // __cocos2dx_audioengine_h__ -#endif //#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_MAC || CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 || CC_TARGET_PLATFORM == CC_PLATFORM_LINUX diff --git a/cocos/scripting/lua-bindings/manual/audioengine/lua_cocos2dx_audioengine_manual.cpp b/cocos/scripting/lua-bindings/manual/audioengine/lua_cocos2dx_audioengine_manual.cpp deleted file mode 100644 index fc9a715..0000000 --- a/cocos/scripting/lua-bindings/manual/audioengine/lua_cocos2dx_audioengine_manual.cpp +++ /dev/null @@ -1,317 +0,0 @@ -/**************************************************************************** - Copyright (c) 2014-2016 Chukong Technologies Inc. - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ -#include "scripting/lua-bindings/manual/audioengine/lua_cocos2dx_audioengine_manual.h" -#include "scripting/lua-bindings/auto/lua_cocos2dx_audioengine_auto.hpp" -#include "scripting/lua-bindings/manual/tolua_fix.h" -#include "scripting/lua-bindings/manual/LuaBasicConversions.h" -#include "scripting/lua-bindings/manual/CCLuaEngine.h" -#include "audio/include/AudioEngine.h" - -static int lua_get_AudioProfile_name(lua_State* L) -{ - cocos2d::AudioProfile* self = nullptr; - -#if COCOS2D_DEBUG >= 1 - tolua_Error tolua_err; - if (!tolua_isusertype(L,1,"cc.AudioProfile",0,&tolua_err)) goto tolua_lerror; -#endif - - self = (cocos2d::AudioProfile*) tolua_tousertype(L,1,0); -#if COCOS2D_DEBUG >= 1 - if (nullptr == self) - { - tolua_error(L,"invalid 'self' in function 'lua_get_AudioProfile_name'\n", nullptr); - return 0; - } -#endif - - lua_pushstring(L, self->name.c_str()); - return 1; - -#if COCOS2D_DEBUG >= 1 -tolua_lerror: - tolua_error(L,"#ferror in function 'lua_get_AudioProfile_name'.",&tolua_err); - return 0; -#endif -} - -static int lua_set_AudioProfile_name(lua_State* L) -{ - int argc = 0; - cocos2d::AudioProfile* self = nullptr; - -#if COCOS2D_DEBUG >= 1 - tolua_Error tolua_err; - if (!tolua_isusertype(L,1,"cc.AudioProfile",0,&tolua_err)) goto tolua_lerror; -#endif - - self = (cocos2d::AudioProfile*) tolua_tousertype(L,1,0); -#if COCOS2D_DEBUG >= 1 - if (nullptr == self) - { - tolua_error(L,"invalid 'self' in function 'lua_set_AudioProfile_name'\n", nullptr); - return 0; - } -#endif - - argc = lua_gettop(L) - 1; - - if (1 == argc) - { -#if COCOS2D_DEBUG >= 1 - if (!tolua_isstring(L, 2, 0, &tolua_err)) - goto tolua_lerror; -#endif - self->name = tolua_tostring(L, 2, 0); - return 0; - } - - return 0; - -#if COCOS2D_DEBUG >= 1 -tolua_lerror: - tolua_error(L,"#ferror in function 'lua_set_AudioProfile_name'.",&tolua_err); - return 0; -#endif -} - -static int lua_get_AudioProfile_maxInstances(lua_State* L) -{ - cocos2d::AudioProfile* self = nullptr; - -#if COCOS2D_DEBUG >= 1 - tolua_Error tolua_err; - if (!tolua_isusertype(L,1,"cc.AudioProfile",0,&tolua_err)) goto tolua_lerror; -#endif - - self = (cocos2d::AudioProfile*) tolua_tousertype(L,1,0); -#if COCOS2D_DEBUG >= 1 - if (nullptr == self) - { - tolua_error(L,"invalid 'self' in function 'lua_get_AudioProfile_maxInstances'\n", nullptr); - return 0; - } -#endif - - tolua_pushnumber(L, (lua_Number)self->maxInstances); - return 1; - -#if COCOS2D_DEBUG >= 1 -tolua_lerror: - tolua_error(L,"#ferror in function 'lua_get_AudioProfile_maxInstances'.",&tolua_err); - return 0; -#endif -} - -static int lua_set_AudioProfile_maxInstances(lua_State* L) -{ - int argc = 0; - cocos2d::AudioProfile* self = nullptr; - -#if COCOS2D_DEBUG >= 1 - tolua_Error tolua_err; - if (!tolua_isusertype(L,1,"cc.AudioProfile",0,&tolua_err)) goto tolua_lerror; -#endif - - self = (cocos2d::AudioProfile*) tolua_tousertype(L,1,0); -#if COCOS2D_DEBUG >= 1 - if (nullptr == self) - { - tolua_error(L,"invalid 'self' in function 'lua_set_AudioProfile_maxInstances'\n", nullptr); - return 0; - } -#endif - - argc = lua_gettop(L) - 1; - - if (1 == argc) - { -#if COCOS2D_DEBUG >= 1 - if (!tolua_isnumber(L, 2, 0, &tolua_err)) - goto tolua_lerror; -#endif - self->maxInstances = (unsigned)tolua_tonumber(L, 2, 0); - return 0; - } - - return 0; - -#if COCOS2D_DEBUG >= 1 -tolua_lerror: - tolua_error(L,"#ferror in function 'lua_set_AudioProfile_maxInstances'.",&tolua_err); - return 0; -#endif -} - -static int lua_get_AudioProfile_minDelay(lua_State* L) -{ - cocos2d::AudioProfile* self = nullptr; - -#if COCOS2D_DEBUG >= 1 - tolua_Error tolua_err; - if (!tolua_isusertype(L,1,"cc.AudioProfile",0,&tolua_err)) goto tolua_lerror; -#endif - - self = (cocos2d::AudioProfile*) tolua_tousertype(L,1,0); -#if COCOS2D_DEBUG >= 1 - if (nullptr == self) - { - tolua_error(L,"invalid 'self' in function 'lua_get_AudioProfile_minDelay'\n", nullptr); - return 0; - } -#endif - - tolua_pushnumber(L, (lua_Number)self->minDelay); - return 1; - -#if COCOS2D_DEBUG >= 1 -tolua_lerror: - tolua_error(L,"#ferror in function 'lua_get_AudioProfile_minDelay'.",&tolua_err); - return 0; -#endif -} - -static int lua_set_AudioProfile_minDelay(lua_State* L) -{ - int argc = 0; - cocos2d::AudioProfile* self = nullptr; - -#if COCOS2D_DEBUG >= 1 - tolua_Error tolua_err; - if (!tolua_isusertype(L,1,"cc.AudioProfile",0,&tolua_err)) goto tolua_lerror; -#endif - - self = (cocos2d::AudioProfile*) tolua_tousertype(L,1,0); -#if COCOS2D_DEBUG >= 1 - if (nullptr == self) - { - tolua_error(L,"invalid 'self' in function 'lua_set_AudioProfile_minDelay'\n", nullptr); - return 0; - } -#endif - - argc = lua_gettop(L) - 1; - - if (1 == argc) - { -#if COCOS2D_DEBUG >= 1 - if (!tolua_isnumber(L, 2, 0, &tolua_err)) - goto tolua_lerror; -#endif - self->minDelay = tolua_tonumber(L, 2, 0); - return 0; - } - - return 0; - -#if COCOS2D_DEBUG >= 1 -tolua_lerror: - tolua_error(L,"#ferror in function 'lua_set_AudioProfile_minDelay'.",&tolua_err); - return 0; -#endif -} - -int lua_cocos2dx_audioengine_AudioEngine_setFinishCallback(lua_State* tolua_S) -{ - int argc = 0; - bool ok = true; - -#if COCOS2D_DEBUG >= 1 - tolua_Error tolua_err; -#endif - -#if COCOS2D_DEBUG >= 1 - if (!tolua_isusertable(tolua_S,1,"cc.AudioEngine",0,&tolua_err)) goto tolua_lerror; -#endif - - argc = lua_gettop(tolua_S) - 1; - - if (argc == 2) - { - int arg0; - ok &= luaval_to_int32(tolua_S, 2,(int *)&arg0, "cc.AudioEngine:setFinishCallback"); - -#if COCOS2D_DEBUG >= 1 - if (!toluafix_isfunction(tolua_S,3,"LUA_FUNCTION",0,&tolua_err)) - { - goto tolua_lerror; - } -#endif - - LUA_FUNCTION handler = ( toluafix_ref_function(tolua_S,3,0)); - - cocos2d::AudioEngine::setFinishCallback(arg0, [handler](int audioID, std::string filePath){ - LuaStack* stack = LuaEngine::getInstance()->getLuaStack(); - - stack->pushInt(audioID); - stack->pushString(filePath.c_str()); - - stack->executeFunctionByHandler(handler, 2); - - LuaEngine::getInstance()->removeScriptHandler(handler); - }); - - return 0; - } - luaL_error(tolua_S, "%s has wrong number of arguments: %d, was expecting %d\n ", "cc.AudioEngine:setFinishCallback",argc, 2); - return 0; -#if COCOS2D_DEBUG >= 1 -tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'lua_cocos2dx_audioengine_AudioEngine_setFinishCallback'.",&tolua_err); -#endif - return 0; -} - -int register_audioengine_module(lua_State* L) -{ - lua_getglobal(L, "_G"); - if (lua_istable(L,-1))//stack:...,_G, - { - register_all_cocos2dx_audioengine(L); - if (L) - { - lua_pushstring(L, "cc.AudioProfile"); - lua_rawget(L, LUA_REGISTRYINDEX); - if (lua_istable(L,-1)) - { - tolua_variable(L, "name", lua_get_AudioProfile_name, lua_set_AudioProfile_name); - tolua_variable(L, "maxInstances", lua_get_AudioProfile_maxInstances, lua_set_AudioProfile_maxInstances); - tolua_variable(L, "minDelay", lua_get_AudioProfile_minDelay, lua_set_AudioProfile_minDelay); - } - lua_pop(L, 1); - - lua_pushstring(L, "cc.AudioEngine"); - lua_rawget(L, LUA_REGISTRYINDEX); - if (lua_istable(L,-1)) - { - tolua_function(L, "setFinishCallback", lua_cocos2dx_audioengine_AudioEngine_setFinishCallback); - } - lua_pop(L, 1); - } - } - lua_pop(L, 1); - - return 1; -} diff --git a/cocos/scripting/lua-bindings/manual/audioengine/lua_cocos2dx_audioengine_manual.h b/cocos/scripting/lua-bindings/manual/audioengine/lua_cocos2dx_audioengine_manual.h deleted file mode 100644 index 07c9dbe..0000000 --- a/cocos/scripting/lua-bindings/manual/audioengine/lua_cocos2dx_audioengine_manual.h +++ /dev/null @@ -1,51 +0,0 @@ -/**************************************************************************** - Copyright (c) 2014-2016 Chukong Technologies Inc. - Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif -#include "tolua++.h" -#ifdef __cplusplus -} -#endif - -/** - * @addtogroup lua - * @{ - */ - -/** - * Call this function can import the lua bindings for the audioengine module. - * After registering, we could call the related audioengine code conveniently in the lua.eg,.cc.AudioEngine:stop(audioID). - * If you don't want to use the audioengine module in the lua, you only don't call this registering function. - * If you don't register the audioengine module, the package size would become smaller . - * The current mechanism,this function is called in the lua_module_register.h - */ - -TOLUA_API int register_audioengine_module(lua_State* L); - -// end group -/// @} diff --git a/cocos/scripting/lua-bindings/manual/lua_module_register.cpp b/cocos/scripting/lua-bindings/manual/lua_module_register.cpp index e5743d8..77a7429 100644 --- a/cocos/scripting/lua-bindings/manual/lua_module_register.cpp +++ b/cocos/scripting/lua-bindings/manual/lua_module_register.cpp @@ -30,7 +30,6 @@ #include "scripting/lua-bindings/manual/ui/lua_cocos2dx_ui_manual.hpp" #include "scripting/lua-bindings/manual/spine/lua_cocos2dx_spine_manual.hpp" #include "scripting/lua-bindings/manual/3d/lua_cocos2dx_3d_manual.h" -#include "scripting/lua-bindings/manual/audioengine/lua_cocos2dx_audioengine_manual.h" #include "scripting/lua-bindings/manual/physics3d/lua_cocos2dx_physics3d_manual.h" #include "scripting/lua-bindings/manual/navmesh/lua_cocos2dx_navmesh_manual.h" @@ -45,7 +44,6 @@ int lua_module_register(lua_State* L) //TODO arnold // register_spine_module(L); register_cocos3d_module(L); - register_audioengine_module(L); #if CC_USE_3D_PHYSICS && CC_ENABLE_BULLET_INTEGRATION register_physics3d_module(L); #endif diff --git a/cocos/scripting/lua-bindings/script/init.lua b/cocos/scripting/lua-bindings/script/init.lua index 670ae48..0483739 100644 --- a/cocos/scripting/lua-bindings/script/init.lua +++ b/cocos/scripting/lua-bindings/script/init.lua @@ -41,8 +41,6 @@ if nil ~= ccui then require "cocos.ui.GuiConstants" end --- extensions -require "cocos.extension.ExtensionConstants" -- network require "cocos.network.NetworkConstants" -- Spine diff --git a/tools/CreateProject.py b/tools/CreateProject.py index 3e19173..6a1d3e7 100755 --- a/tools/CreateProject.py +++ b/tools/CreateProject.py @@ -145,6 +145,7 @@ def createProject(packageName, outputDir, isLandscape, needCopyCocos2d): for fileName in ["CHANGELOG", "CMakeLists.txt", "install-deps-linux.sh", "README.md"]: copyFile(joinDir(engineRoot, fileName), joinDir(outputDir, "frameworks", "cocos2d-x", fileName)) copyFile(joinDir(engineRoot, "cocos", "scripting", "lua-bindings", "manual", "lua_module_register.h"), joinDir(outputDir, "frameworks", "runtime-src", "Classes", "lua_module_register.h")) + shutil.rmtree(joinDir(outputDir, "frameworks", "cocos2d-x", "cocos", "scripting", "lua-bindings", "script")) # remove double files print "====> Done." if __name__ == "__main__":