From dafc28e01d54e04ce0ac8e33e093b9a99876a2ec Mon Sep 17 00:00:00 2001 From: iProgramInCpp Date: Sat, 23 Dec 2023 00:51:42 +0200 Subject: [PATCH] * Android Native: Add SoundSystemSL! This gives the native Android build sound support! --- platforms/android/AppPlatform_android.cpp | 6 +- platforms/android/SoundSystemSL.cpp | 241 ++++++++++++++++++ platforms/android/SoundSystemSL.hpp | 65 +++++ .../project/app/src/main/cpp/CMakeLists.txt | 3 +- 4 files changed, 310 insertions(+), 5 deletions(-) create mode 100644 platforms/android/SoundSystemSL.cpp create mode 100644 platforms/android/SoundSystemSL.hpp diff --git a/platforms/android/AppPlatform_android.cpp b/platforms/android/AppPlatform_android.cpp index 51b0529..dae72fa 100644 --- a/platforms/android/AppPlatform_android.cpp +++ b/platforms/android/AppPlatform_android.cpp @@ -5,12 +5,11 @@ The following code is licensed under the BSD 1 clause license. SPDX-License-Identifier: BSD-1-Clause ********************************************************************/ - -#define WIN32_LEAN_AND_MEAN #include #include #include "AppPlatform_android.hpp" +#include "SoundSystemSL.hpp" #include "client/player/input/Mouse.hpp" #include "stb_image.h" @@ -171,9 +170,8 @@ SoundSystem* const AppPlatform_android::getSoundSystem() const void AppPlatform_android::initSoundSystem() { - // TODO: SoundSystemSL! if (!m_pSoundSystem) - m_pSoundSystem = new SoundSystem(); + m_pSoundSystem = new SoundSystemSL(); else LOG_E("Trying to initialize SoundSystem more than once!"); } diff --git a/platforms/android/SoundSystemSL.cpp b/platforms/android/SoundSystemSL.cpp new file mode 100644 index 0000000..65649cd --- /dev/null +++ b/platforms/android/SoundSystemSL.cpp @@ -0,0 +1,241 @@ +/******************************************************************** + Minecraft: Pocket Edition - Decompilation Project + Copyright (C) 2023 iProgramInCpp + + The following code is licensed under the BSD 1 clause license. + SPDX-License-Identifier: BSD-1-Clause + ********************************************************************/ +#include "SoundSystemSL.hpp" +#include "common/Utils.hpp" + +#define C_MAX_SOUNDS 4 + +// TODO: Use other types of mutexes later. +SLObjectItf SoundSystemSL::objEngine; +std::vector SoundSystemSL::toRemove; +pthread_mutex_t SoundSystemSL::toRemoveMutex; + +SoundSystemSL::SoundSystemSL() +{ + m_listenerX = 0.0f; + m_listenerY = 0.0f; + m_listenerZ = 0.0f; + m_soundCount = 0; + m_3dLocationItf = nullptr; + m_bAvailable = true; + init(); +} + +SoundSystemSL::~SoundSystemSL() +{ + pthread_mutex_unlock(&toRemoveMutex); + + for (SLSoundList::iterator it = m_playingSounds.begin(); + it != m_playingSounds.end(); + ++it) + { + (**it)->Destroy(*it); + } + + (*m_slOutputMix)->Destroy(m_slOutputMix); + + if (objEngine) + { + (*objEngine)->Destroy(objEngine); + objEngine = nullptr; + } +} + +void SoundSystemSL::init() +{ + toRemove.clear(); + // some weird stuff + + if (objEngine) + (*objEngine)->Destroy(objEngine); + + SLEngineOption option; + option.feature = SL_ENGINEOPTION_THREADSAFE; + option.data = true; + checkErr(slCreateEngine(&objEngine, 1, &option, 0, nullptr, nullptr)); + + if (checkErr((*objEngine)->Realize(objEngine, false))) + { + m_bAvailable = false; + return; + } + + checkErr((*objEngine)->GetInterface(objEngine, SL_IID_ENGINE, &m_slEngine)); + checkErr((*m_slEngine)->CreateOutputMix(m_slEngine, &m_slOutputMix, 0, nullptr, nullptr)); + checkErr((*m_slOutputMix)->Realize(m_slOutputMix, false)); +} + +bool SoundSystemSL::checkErr(SLresult res) +{ + if (res == SL_RESULT_SUCCESS) + return false; + + LOG_E("OpenSL error: %d\n", res); + return true; +} + +void SoundSystemSL::removePlayer(SLAndroidSimpleBufferQueueItf caller, void* context) +{ + pthread_mutex_lock(&toRemoveMutex); + toRemove.push_back((SLObjectItf) context); + pthread_mutex_unlock(&toRemoveMutex); +} + +void SoundSystemSL::removeStoppedSounds() +{ + pthread_mutex_lock(&toRemoveMutex); + m_tempToRemove = toRemove; + toRemove.clear(); + pthread_mutex_unlock(&toRemoveMutex); + + for (int i = 0; i < m_tempToRemove.size(); i++) + { + + for (SLSoundList::iterator it = m_playingSounds.begin(); + it != m_playingSounds.end(); + ++it) + { + if (*it == m_tempToRemove[i]) + { + m_playingSounds.erase(it); + break; + } + } + + (*m_tempToRemove[i])->Destroy(m_tempToRemove[i]); + m_soundCount--; + } +} + + +void SoundSystemSL::setListenerPos(float x, float y, float z) +{ + if (!m_3dLocationItf) + { + m_listenerX = x; + m_listenerY = y; + m_listenerZ = z; + return; + } + + SLVec3D vec; + vec.x = int(1000.0f * x); + vec.y = int(1000.0f * y); + vec.z = int(1000.0f * z); + checkErr((*m_3dLocationItf)->SetLocationCartesian( + m_3dLocationItf, + &vec + )); +} + +void SoundSystemSL::setListenerAngle(float yaw, float pitch) +{ + if (!m_3dLocationItf) + return; + + checkErr((*m_3dLocationItf)->SetOrientationAngles( + m_3dLocationItf, + int(180000.0f * yaw), + 0, + 0 + )); +} + +void SoundSystemSL::playAt(const SoundDesc &sound, float x, float y, float z, float volume, float pitch) +{ + removeStoppedSounds(); + + if (m_soundCount >= C_MAX_SOUNDS) + return; + + SLDataSource dataSource; + SLDataSink dataSink; + SLDataLocator_AndroidSimpleBufferQueue dataSourceLocator; + SLDataFormat_PCM dataSourceFormat; + SLDataLocator_OutputMix dataSinkLocator; + SLObjectItf pAudioPlayer; + SLPlayItf pPlayItf; + SLVolumeItf pVolumeItf; + SLmillibel maxVolume; + SLAndroidSimpleBufferQueueItf pBufferQueueItf; + static SLInterfaceID static_iid_array[2]; + static SLboolean static_bool_array[2]; + + dataSource.pLocator = &dataSourceLocator; + dataSource.pFormat = &dataSourceFormat; + dataSink.pLocator = &dataSinkLocator; + dataSink.pFormat = nullptr; + + // TODO: Nicer initialization based on initializer lists :) + dataSourceLocator.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; + dataSourceLocator.numBuffers = 2; + dataSinkLocator.locatorType = SL_DATALOCATOR_OUTPUTMIX; + dataSinkLocator.outputMix = m_slOutputMix; + dataSourceFormat.numChannels = sound.m_header.m_channels; + dataSourceFormat.channelMask = sound.m_header.m_channels == 1 ? 4 : 3; + dataSourceFormat.samplesPerSec = 1000 * sound.m_header.m_sample_rate; + dataSourceFormat.formatType = SL_DATAFORMAT_PCM; + dataSourceFormat.endianness = SL_BYTEORDER_LITTLEENDIAN; + dataSourceFormat.bitsPerSample = 8 * sound.m_header.m_bytes_per_sample; + dataSourceFormat.containerSize = 8 * sound.m_header.m_bytes_per_sample; + static_iid_array[0] = SL_IID_BUFFERQUEUE; + static_iid_array[1] = SL_IID_VOLUME; + static_bool_array[0] = true; + static_bool_array[1] = true; + + checkErr((*m_slEngine)->CreateAudioPlayer( + m_slEngine, + &pAudioPlayer, + &dataSource, + &dataSink, + 2, + static_iid_array, + static_bool_array + )); + checkErr((*pAudioPlayer)->Realize(pAudioPlayer, false)); + checkErr((*pAudioPlayer)->GetInterface(pAudioPlayer, SL_IID_PLAY, &pPlayItf)); + checkErr((*pAudioPlayer)->GetInterface(pAudioPlayer, SL_IID_VOLUME, &pVolumeItf)); + checkErr((*pVolumeItf)->GetMaxVolumeLevel(pVolumeItf, &maxVolume)); + SLmillibel remappedVolume = int(float(maxVolume) + (1.0f - volume) * -2000.0f); + LOG_I("min: %d, max: %d, current: %d (%f)\n", SL_MILLIBEL_MIN, maxVolume, remappedVolume, volume); + checkErr((*pVolumeItf)->SetVolumeLevel(pVolumeItf, remappedVolume)); + checkErr((*pAudioPlayer)->GetInterface(pAudioPlayer, SL_IID_BUFFERQUEUE, &pBufferQueueItf)); + checkErr((*pBufferQueueItf)->RegisterCallback(pBufferQueueItf, removePlayer, (void*) pAudioPlayer)); + checkErr((*pBufferQueueItf)->Enqueue(pBufferQueueItf, sound.m_pData, sound.field_4)); + checkErr((*pPlayItf)->SetPlayState(pPlayItf, SL_PLAYSTATE_PLAYING)); + + m_playingSounds.push_back(pAudioPlayer); + m_soundCount++; +} + +// Confirmed Stubs +void SoundSystemSL::destroy() +{ + +} + +void SoundSystemSL::load(const std::string &sound) +{ + +} + +void SoundSystemSL::play(const std::string &sound) +{ + +} + +void SoundSystemSL::pause(const std::string &sound) +{ + +} + +void SoundSystemSL::stop(const std::string &sound) +{ + +} + diff --git a/platforms/android/SoundSystemSL.hpp b/platforms/android/SoundSystemSL.hpp new file mode 100644 index 0000000..121625b --- /dev/null +++ b/platforms/android/SoundSystemSL.hpp @@ -0,0 +1,65 @@ +/******************************************************************** + Minecraft: Pocket Edition - Decompilation Project + Copyright (C) 2023 iProgramInCpp + + The following code is licensed under the BSD 1 clause license. + SPDX-License-Identifier: BSD-1-Clause + ********************************************************************/ +#pragma once + +#include +#include + +#define USE_PTHREAD_MUTEX + +#ifdef USE_PTHREAD_MUTEX +#include +#else +#error TODO: Implement support for other types of mutexes, such +#error as C++11 mutexes. Although I'm pretty sure this will only +#error be included for Android. -iProgram +#endif + +#include +#ifdef ANDROID +#include +#endif + +#include "client/sound/SoundSystem.hpp" +#include "client/sound/SoundData.hpp" + +typedef std::list SLSoundList; + +class SoundSystemSL : public SoundSystem +{ +public: + SoundSystemSL(); + ~SoundSystemSL(); + void init(); + void destroy(); + bool checkErr(SLresult res); + void removeStoppedSounds(); + void setListenerPos(float x, float y, float z) override; + void setListenerAngle(float yaw, float pitch) override; + void load(const std::string& sound) override; + void play(const std::string& sound) override; + void pause(const std::string& sound) override; + void stop(const std::string& sound) override; + void playAt(const SoundDesc& sound, float x, float y, float z, float volume, float pitch) override; + static void removePlayer(SLAndroidSimpleBufferQueueItf caller, void* context); +private: + SLSoundList m_playingSounds; + SLEngineItf m_slEngine; + SL3DLocationItf m_3dLocationItf; + SLObjectItf m_slOutputMix; + float m_listenerX; + float m_listenerY; + float m_listenerZ; + int m_soundCount; + bool m_bAvailable; + std::vector m_tempToRemove; + + static std::vector toRemove; + static SLObjectItf objEngine; + static pthread_mutex_t toRemoveMutex; +}; \ No newline at end of file diff --git a/platforms/android/project/app/src/main/cpp/CMakeLists.txt b/platforms/android/project/app/src/main/cpp/CMakeLists.txt index f6e1c5b..6a03a61 100644 --- a/platforms/android/project/app/src/main/cpp/CMakeLists.txt +++ b/platforms/android/project/app/src/main/cpp/CMakeLists.txt @@ -12,6 +12,7 @@ set(USE_NATIVE_ANDROID TRUE) add_library(reminecraftpe SHARED "${MC_ROOT}/platforms/android/android_native_app_glue.c" "${MC_ROOT}/platforms/android/AppPlatform_android.cpp" + "${MC_ROOT}/platforms/android/SoundSystemSL.cpp" "${MC_ROOT}/platforms/android/main.cpp" ) @@ -24,7 +25,7 @@ add_subdirectory("${MC_ROOT}/thirdparty/stb_image" stb_image) target_link_libraries(reminecraftpe stb_image) # Extra Dependencies -target_link_libraries(reminecraftpe android) +target_link_libraries(reminecraftpe android OpenSLES) # Check for the presence of some optional asset based features. if(EXISTS "${MC_ROOT}/game/assets/gui/background/panorama_0.png")