I’m James Chen, one of the core developers of Cocos2d-x in Chukong Technologies.
Recently, we have released Cocos2d-x v3.13, v3.14. We refactored AudioEngine implementation since v3.13 to resolve high latency while playing audio on some specific Android devices. Thanks to our developers, we received some feedbacks of audio issues. Let me explain more about those issues.
Since Android is Open Source, it has many fragments as it contains different Android versions, thousand of devices by different vendors. Nearly every vendor will modify android source more or less, probably add OMXCodec plugins or modify its implementation.
These fragments make Android audio decoding API (OpenSLES (c) / SoundPool (java)) not stable enough. Although we have tested a lot on different Android devices with different Android versions before releasing a new Cocos2d-X version, we still encounter with many problems of New AudioEngine. What’s more, audio decoding uses Android System API has very pool performance.
Community have reported some new AudioEngine issues like the following topics:
I checked all of them, analyzed the crash stack or performance issue. In the end, it’s almost the issues of System Audio Decoding API (OpenSLES API or SoundPool).
These issues are extremely hard to be resolved in engine side.
About a month ago, I have an idea that what about we do the decoding work rather than using System Decoding API directly?
In this way, I will be easier to maintain the decoding logic and every devices with different android versions will have the same decoding behavior.
Decoding 101 ogg/mp3 files by 3rd-party decoder on Meizu MX3 (32bit Android 5.0.1, came into market about 3 years ago) is 5x faster than System OpenSLES Decoder, 10x faster than System SoundPool.
Decoding 101 ogg/mp3 files by 3rd-party decoder on Nexus 5X (64bit Android 7.1.1, came into market about 1.5 years ago) is 15x faster than System OpenSLES Decoder, 38x faster than System SoundPool.
WHY DO WE GET BETTER PERFORMANCE BY USING 3RD-PARTY DECODING LIBRARIES?
Because OpenSLES or SoundPool Decoding API wastes much time in communicating to system audio service with different process, and this route isn’t well optimized for game. Even worse, lots of vendors will modify source code that make us even more difficult to analyze audio issues.
BUT THERE IS STILL A DRAWBACK (PROBABLY NOT AN ISSUE FOR MOST DEVELOPERS)
In all seriousness, 108K increased file size is nothing at all when you consider the overall size of the APK.
I would be more than happy to test out the changes, but what is the best way to get the updated files and such? Is there a git command I can use to download all of them? (I rarely use git, which is why I’m asking).
Thanks for your hard work, its about time as i have a game in which i am preloading about 80 sound files as soon as game resources start to load in my loading scene, total size is not more than 2.8MB in total and file format is .mp3.
Its taking about 8-10 seconds to preload these sounds and on Android i am getting following call-stack on Logcat from system :-
more then 5000 lines of it. As my game have many scene created with cocos studio(20+) i am stuck with cocos2d-x 3.10 as of now. I firmly believe it the same issue pointed by @dumganhar.
My development environment and test environment is a follow:-
OS X El Capitan 10.11.6 (15G31)
NDK r10-c
android:minSdkVersion="9"
and Test device is
Redmi Note 3(MIUI Global 8.1.1.0)
Android version : 6.0.1
Is there is a way to test new audio engine with cocos2d-x 3.10(Engine version)? NO git
Please refer to 3rd floor, I have uploaded the zip ball file there.
But it’s based on v3.13 or v3.14.
I guess it’s also easy for integrating it to v3.10. Just have a try.
I did all the above steps and while compiling for android i got these errors for cocos2d-x 3.10
[armeabi] Compile++ thumb: cocos_flatbuffers_static <= idl_gen_fbs.cpp
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp: In destructor 'virtual CocosDenshion::android::AndroidJavaEngine::~AndroidJavaEngine()':
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp:73:5: error: 'callStaticVoidMethod' is not a member of 'cocos2d::JniHelper'
JniHelper::callStaticVoidMethod(helperClassName, "end");
^
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp: In member function 'virtual void CocosDenshion::android::AndroidJavaEngine::preloadBackgroundMusic(const char*)':
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp:78:5: error: 'callStaticVoidMethod' is not a member of 'cocos2d::JniHelper'
JniHelper::callStaticVoidMethod(helperClassName, "preloadBackgroundMusic", fullPath);
^
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp: In member function 'virtual void CocosDenshion::android::AndroidJavaEngine::playBackgroundMusic(const char*, bool)':
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp:83:5: error: 'callStaticVoidMethod' is not a member of 'cocos2d::JniHelper'
JniHelper::callStaticVoidMethod(helperClassName, "playBackgroundMusic", fullPath, loop);
^
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp: In member function 'virtual void CocosDenshion::android::AndroidJavaEngine::stopBackgroundMusic(bool)':
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp:87:5: error: 'callStaticVoidMethod' is not a member of 'cocos2d::JniHelper'
JniHelper::callStaticVoidMethod(helperClassName, "stopBackgroundMusic");
^
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp: In member function 'virtual void CocosDenshion::android::AndroidJavaEngine::pauseBackgroundMusic()':
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp:91:5: error: 'callStaticVoidMethod' is not a member of 'cocos2d::JniHelper'
JniHelper::callStaticVoidMethod(helperClassName, "pauseBackgroundMusic");
^
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp: In member function 'virtual void CocosDenshion::android::AndroidJavaEngine::resumeBackgroundMusic()':
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp:96:5: error: 'callStaticVoidMethod' is not a member of 'cocos2d::JniHelper'
JniHelper::callStaticVoidMethod(helperClassName, "resumeBackgroundMusic");
^
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp: In member function 'virtual void CocosDenshion::android::AndroidJavaEngine::rewindBackgroundMusic()':
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp:100:5: error: 'callStaticVoidMethod' is not a member of 'cocos2d::JniHelper'
JniHelper::callStaticVoidMethod(helperClassName, "rewindBackgroundMusic");
^
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp: In member function 'virtual bool CocosDenshion::android::AndroidJavaEngine::willPlayBackgroundMusic()':
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp:104:12: error: 'callStaticBooleanMethod' is not a member of 'cocos2d::JniHelper'
return JniHelper::callStaticBooleanMethod(helperClassName, "willPlayBackgroundMusic");
^
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp: In member function 'virtual bool CocosDenshion::android::AndroidJavaEngine::isBackgroundMusicPlaying()':
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp:108:12: error: 'callStaticBooleanMethod' is not a member of 'cocos2d::JniHelper'
return JniHelper::callStaticBooleanMethod(helperClassName, "isBackgroundMusicPlaying");
^
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp: In member function 'virtual float CocosDenshion::android::AndroidJavaEngine::getBackgroundMusicVolume()':
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp:112:12: error: 'callStaticFloatMethod' is not a member of 'cocos2d::JniHelper'
return JniHelper::callStaticFloatMethod(helperClassName, "getBackgroundMusicVolume");
^
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp: In member function 'virtual void CocosDenshion::android::AndroidJavaEngine::setBackgroundMusicVolume(float)':
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp:116:5: error: 'callStaticVoidMethod' is not a member of 'cocos2d::JniHelper'
JniHelper::callStaticVoidMethod(helperClassName, "setBackgroundMusicVolume", volume);
^
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp: In member function 'virtual float CocosDenshion::android::AndroidJavaEngine::getEffectsVolume()':
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp:127:16: error: 'callStaticFloatMethod' is not a member of 'cocos2d::JniHelper'
return JniHelper::callStaticFloatMethod(helperClassName, "getEffectsVolume");
^
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp: In member function 'virtual void CocosDenshion::android::AndroidJavaEngine::setEffectsVolume(float)':
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp:155:9: error: 'callStaticVoidMethod' is not a member of 'cocos2d::JniHelper'
JniHelper::callStaticVoidMethod(helperClassName, "setEffectsVolume", volume);
^
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp: In member function 'virtual unsigned int CocosDenshion::android::AndroidJavaEngine::playEffect(const char*, bool, float, float, float)':
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp:179:19: error: 'callStaticIntMethod' is not a member of 'cocos2d::JniHelper'
int ret = JniHelper::callStaticIntMethod(helperClassName, "playEffect", fullPath, loop, pitch, pan, gain);
^
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp: In member function 'virtual void CocosDenshion::android::AndroidJavaEngine::pauseEffect(unsigned int)':
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp:192:9: error: 'callStaticVoidMethod' is not a member of 'cocos2d::JniHelper'
JniHelper::callStaticVoidMethod(helperClassName, "pauseEffect", (int)soundID);
^
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp: In member function 'virtual void CocosDenshion::android::AndroidJavaEngine::resumeEffect(unsigned int)':
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp:204:9: error: 'callStaticVoidMethod' is not a member of 'cocos2d::JniHelper'
JniHelper::callStaticVoidMethod(helperClassName, "resumeEffect", (int)soundID);
^
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp: In member function 'virtual void CocosDenshion::android::AndroidJavaEngine::stopEffect(unsigned int)':
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp:217:9: error: 'callStaticVoidMethod' is not a member of 'cocos2d::JniHelper'
JniHelper::callStaticVoidMethod(helperClassName, "stopEffect", (int)soundID);
^
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp: In member function 'virtual void CocosDenshion::android::AndroidJavaEngine::pauseAllEffects()':
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp:232:9: error: 'callStaticVoidMethod' is not a member of 'cocos2d::JniHelper'
JniHelper::callStaticVoidMethod(helperClassName, "pauseAllEffects");
^
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp: In member function 'virtual void CocosDenshion::android::AndroidJavaEngine::resumeAllEffects()':
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp:247:9: error: 'callStaticVoidMethod' is not a member of 'cocos2d::JniHelper'
JniHelper::callStaticVoidMethod(helperClassName, "resumeAllEffects");
^
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp: In member function 'virtual void CocosDenshion::android::AndroidJavaEngine::stopAllEffects()':
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp:263:9: error: 'callStaticVoidMethod' is not a member of 'cocos2d::JniHelper'
JniHelper::callStaticVoidMethod(helperClassName, "stopAllEffects");
^
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp: In member function 'virtual void CocosDenshion::android::AndroidJavaEngine::preloadEffect(const char*)':
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp:272:9: error: 'callStaticVoidMethod' is not a member of 'cocos2d::JniHelper'
JniHelper::callStaticVoidMethod(helperClassName, "preloadEffect", fullPath);
^
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp: In member function 'virtual void CocosDenshion::android::AndroidJavaEngine::unloadEffect(const char*)':
/Users/ajaychauhan/Documents/CocosProjects/BingoJazz/proj.android/../cocos2d/cocos/audio/android/jni/cddandroidAndroidJavaEngine.cpp:281:9: error: 'callStaticVoidMethod' is not a member of 'cocos2d::JniHelper'
JniHelper::callStaticVoidMethod(helperClassName, "unloadEffect", fullPath);
can i have some pointers to resolve it ASAP, Thanks for your support and hard work.
No more preload and decoding issues with OGG files.
No more sound sync issues when using OGG audio format. Sounds were always visibly out of sync with animations in my game, but that issue is gone.
Game starts up much quicker than before (roughly 30 audio files, mixed OGG/MP3 are preloaded).
If any specific issue arises, then I’ll post back, but for now this is an amazing change to the Android build. Thank you very much James and anyone else who may have contributed to bringing this to fruition.
If all goes well, how soon will it be before an official release of cocos2d-x is made with this new code?
Hello @dumganhar,
Thanks for the pointer, I did modified the JNI as per the requirements, but still got errors from CCFileUtils-android by tracing back to logs i came to the conclusion that cocos2d-x is now trying to read data from OBB files due to introduction of OBB-File extension support from 3.12(AFAIR). I am a little lost as i have no idea what files were modified to implement OBB support. A pointer here would be much of an help.
It seems that the audio documentation is outdated for a long time. I didn’t find New AudioEngine docs too.
You could just visit the interfaces in AudioEngine.h and find the sample code in cpp-tests/NewAudioEngineTest .
Is it blocking main thread while loading files? In my game taking some real example I have a scene with several oggs. I don’t have any loading screen, just going there. Usually it was half a second lag before scene loaded, but now it’s much longer. I found out that just preloading isn’t harmful, but if you’d play sound before it’s loaded it’ll freeze game for 1-2 seconds.
In simple audio engine there were a code when after loading sample it checked if it should be played and then it was played.
Can we do something about it?