diff --git a/cocos/audio/CMakeLists.txt b/cocos/audio/CMakeLists.txt index 18e5b3f989..0c8016a796 100644 --- a/cocos/audio/CMakeLists.txt +++ b/cocos/audio/CMakeLists.txt @@ -25,7 +25,7 @@ set(COCOS_AUDIO_SRC # stupid, clang always compie .mm as objc/cpp mix obj if(ANDROID) set(COCOS_AUDIO_SRC ${COCOS_AUDIO_SRC} - audio/src/alink.cpp + audio/src/android-link.cpp ) else() set(COCOS_AUDIO_SRC ${COCOS_AUDIO_SRC} diff --git a/cocos/audio/include/AudioDecoderMp3.h b/cocos/audio/include/AudioDecoderMp3.h index db38a20355..b25dc68dd7 100644 --- a/cocos/audio/include/AudioDecoderMp3.h +++ b/cocos/audio/include/AudioDecoderMp3.h @@ -28,7 +28,15 @@ #include "audio/include/AudioDecoder.h" #include "platform/PXFileStream.h" -struct mpg123_handle_struct; +#if !defined(CC_USE_MPG123) +#define CC_USE_MPG123 0 +#endif + +#if !CC_USE_MPG123 +typedef struct mp3dec_impl* mp3dec_handle_t; +#else +typedef struct mpg123_handle_struct* mp3dec_handle_t; +#endif namespace cocos2d { @@ -74,7 +82,7 @@ protected: static void destroy(); PXFileStream _fileStream; - struct mpg123_handle_struct* _mpg123handle; + mp3dec_handle_t _handle; friend class AudioDecoderManager; }; diff --git a/cocos/audio/src/AudioDecoderManager.cpp b/cocos/audio/src/AudioDecoderManager.cpp index 37f64ed90e..9ed0477b18 100644 --- a/cocos/audio/src/AudioDecoderManager.cpp +++ b/cocos/audio/src/AudioDecoderManager.cpp @@ -21,7 +21,7 @@ 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. +THE SOFTWARE. ****************************************************************************/ #define LOG_TAG "AudioDecoderManager" @@ -67,7 +67,7 @@ AudioDecoder* AudioDecoderManager::createDecoder(const std::string& path) } #if CC_TARGET_PLATFORM != CC_PLATFORM_IOS else if (cxx20::ic::ends_with(svPath, ".mp3")) - { + { return new (std::nothrow) AudioDecoderMp3(); } else if (cxx20::ic::ends_with(svPath, ".wav")) { diff --git a/cocos/audio/src/AudioDecoderMp3.cpp b/cocos/audio/src/AudioDecoderMp3.cpp index 071df67961..d60a78992a 100644 --- a/cocos/audio/src/AudioDecoderMp3.cpp +++ b/cocos/audio/src/AudioDecoderMp3.cpp @@ -1,6 +1,7 @@ /**************************************************************************** Copyright (c) 2016 Chukong Technologies Inc. Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. + Copyright (c) 2020 c4games.com http://www.cocos2d-x.org @@ -29,17 +30,40 @@ #include "platform/CCFileUtils.h" #include "base/CCConsole.h" + +#if !CC_USE_MPG123 +#define MINIMP3_IMPLEMENTATION +#include "minimp3/minimp3_ex.h" +#else // because the cocos2d-x engine has ssize_t typedef, so disable mpg123 ssize_t #define MPG123_DEF_SSIZE_T #include "mpg123.h" +#endif #if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID #include #include #endif -namespace cocos2d { +#if !CC_USE_MPG123 +struct mp3dec_impl { + mp3dec_ex_t _dec; + mp3dec_io_t _decIO; +}; +#endif +namespace cocos2d { +#if !CC_USE_MPG123 + static size_t minimp3_read_r(void* buf, size_t size, void* user_data) + { + return ((PXFileStream*)user_data)->read(buf, size); + } + + static int minimp3_seek_r(uint64_t position, void* user_data) + { + return ((PXFileStream*)user_data)->seek(position, SEEK_SET) >= 0 ? 0 : -1; + } +#else static bool __mp3Inited = false; static ssize_t mpg123_read_r(void * handle, void * buffer, size_t count) @@ -55,10 +79,11 @@ namespace cocos2d { void mpg123_close_r(void* handle) { ((PXFileStream*)handle)->close(); } - +#endif bool AudioDecoderMp3::lazyInit() { bool ret = true; +#if CC_USE_MPG123 if (!__mp3Inited) { int error = mpg123_init(); @@ -72,20 +97,23 @@ namespace cocos2d { ret = false; } } +#endif return ret; } void AudioDecoderMp3::destroy() { +#if CC_USE_MPG123 if (__mp3Inited) { mpg123_exit(); __mp3Inited = false; } +#endif } AudioDecoderMp3::AudioDecoderMp3() - : _mpg123handle(nullptr) + : _handle(nullptr) { lazyInit(); } @@ -97,14 +125,57 @@ namespace cocos2d { bool AudioDecoderMp3::open(const std::string& fullPath) { +#if !CC_USE_MPG123 + do + { + if (!_fileStream.open(fullPath)) + { + ALOGE("Trouble with minimp3(1): %s\n", strerror(errno)); + break; + } + + auto handle = new mp3dec_impl(); + + handle->_decIO.read = minimp3_read_r; + handle->_decIO.seek = minimp3_seek_r; + handle->_decIO.read_data = handle->_decIO.seek_data = &_fileStream; + + if (mp3dec_ex_open_cb(&handle->_dec, &handle->_decIO, MP3D_SEEK_TO_SAMPLE) != 0) + { + delete handle; + break; + } + + auto& info = handle->_dec.info; + _channelCount = info.channels; // the _channelCount is samplesPerFrame + _sampleRate = info.hz; +#ifndef MINIMP3_FLOAT_OUTPUT + _sourceFormat = AUDIO_SOURCE_FORMAT::PCM_16; + _bytesPerBlock = sizeof(uint16_t) * _channelCount; +#else + _sourceFormat = AUDIO_SOURCE_FORMAT::PCM_FLT32; + _bytesPerBlock = sizeof(float) * _channelCount; +#endif + // samples + _totalFrames = handle->_dec.samples / _channelCount; + + // store the handle + _handle = handle; + + _isOpened = true; + return true; + } while (false); + + return false; +#else long rate = 0; int error = MPG123_OK; int mp3Encoding = 0; int channel = 0; do { - _mpg123handle = mpg123_new(nullptr, &error); - if (nullptr == _mpg123handle) + _handle = mpg123_new(nullptr, &error); + if (nullptr == _handle) { ALOGE("Basic setup goes wrong: %s", mpg123_plain_strerror(error)); break; @@ -116,12 +187,12 @@ namespace cocos2d { break; } - mpg123_replace_reader_handle(_mpg123handle, mpg123_read_r, mpg123_lseek_r, mpg123_close_r); + mpg123_replace_reader_handle(_handle, mpg123_read_r, mpg123_lseek_r, mpg123_close_r); - if (mpg123_open_handle(_mpg123handle, &_fileStream) != MPG123_OK - || mpg123_getformat(_mpg123handle, &rate, &channel, &mp3Encoding) != MPG123_OK) + if (mpg123_open_handle(_handle, &_fileStream) != MPG123_OK + || mpg123_getformat(_handle, &rate, &channel, &mp3Encoding) != MPG123_OK) { - ALOGE("Trouble with mpg123(2): %s\n", mpg123_strerror(_mpg123handle)); + ALOGE("Trouble with mpg123(2): %s\n", mpg123_strerror(_handle)); break; } @@ -145,62 +216,80 @@ namespace cocos2d { } /* Ensure that this output format will not change (it could, when we allow it). */ - mpg123_format_none(_mpg123handle); - mpg123_format(_mpg123handle, rate, channel, mp3Encoding); + mpg123_format_none(_handle); + mpg123_format(_handle, rate, channel, mp3Encoding); /* Ensure that we can get accurate length by call mpg123_length */ - mpg123_scan(_mpg123handle); + mpg123_scan(_handle); - _totalFrames = mpg123_length(_mpg123handle); + _totalFrames = mpg123_length(_handle); _isOpened = true; return true; } while (false); - if (_mpg123handle != nullptr) + if (_handle != nullptr) { - mpg123_close(_mpg123handle); - mpg123_delete(_mpg123handle); - _mpg123handle = nullptr; + mpg123_close(_handle); + mpg123_delete(_handle); + _handle = nullptr; } return false; +#endif } void AudioDecoderMp3::close() { if (isOpened()) { - if (_mpg123handle != nullptr) - { - mpg123_close(_mpg123handle); - mpg123_delete(_mpg123handle); - _mpg123handle = nullptr; +#if !CC_USE_MPG123 + if (_handle) { + mp3dec_ex_close(&_handle->_dec); + + delete _handle; + _handle = nullptr; + + _fileStream.close(); } +#else + if (_handle != nullptr) + { + mpg123_close(_handle); + mpg123_delete(_handle); + _handle = nullptr; + } +#endif _isOpened = false; } } uint32_t AudioDecoderMp3::read(uint32_t framesToRead, char* pcmBuf) { +#if !CC_USE_MPG123 + auto sampelsToRead = framesToRead * _channelCount; + auto samplesRead = mp3dec_ex_read(&_handle->_dec, (mp3d_sample_t*)pcmBuf, sampelsToRead); + return static_cast(samplesRead / _channelCount); +#else int bytesToRead = framesToBytes(framesToRead); size_t bytesRead = 0; - int err = mpg123_read(_mpg123handle, (unsigned char*)pcmBuf, bytesToRead, &bytesRead); + int err = mpg123_read(_handle, (unsigned char*)pcmBuf, bytesToRead, &bytesRead); if (err == MPG123_ERR) { - ALOGE("Trouble with mpg123: %s\n", mpg123_strerror(_mpg123handle) ); + ALOGE("Trouble with mpg123: %s\n", mpg123_strerror(_handle) ); return 0; } return bytesToFrames(bytesRead); +#endif } bool AudioDecoderMp3::seek(uint32_t frameOffset) { - off_t offset = mpg123_seek(_mpg123handle, frameOffset, SEEK_SET); +#if !CC_USE_MPG123 + return 0 == mp3dec_ex_seek(&_handle->_dec, frameOffset); +#else + off_t offset = mpg123_seek(_handle, frameOffset, SEEK_SET); //ALOGD("mpg123_seek return: %d", (int)offset); - if (offset >= 0 && offset == frameOffset) - { - return true; - } - return false; + return (offset >= 0 && offset == frameOffset); +#endif } } // namespace cocos2d { diff --git a/cocos/audio/src/alink.cpp b/cocos/audio/src/android-link.cpp similarity index 100% rename from cocos/audio/src/alink.cpp rename to cocos/audio/src/android-link.cpp