mirror of
https://github.com/celisej567/mcpe.git
synced 2026-09-11 20:11:18 +03:00
* Android Native: Add SoundSystemSL!
This gives the native Android build sound support!
This commit is contained in:
@@ -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 <fstream>
|
||||
#include <sstream>
|
||||
|
||||
#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!");
|
||||
}
|
||||
|
||||
241
platforms/android/SoundSystemSL.cpp
Normal file
241
platforms/android/SoundSystemSL.cpp
Normal file
@@ -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<SLObjectItf> 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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
65
platforms/android/SoundSystemSL.hpp
Normal file
65
platforms/android/SoundSystemSL.hpp
Normal file
@@ -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 <vector>
|
||||
#include <list>
|
||||
|
||||
#define USE_PTHREAD_MUTEX
|
||||
|
||||
#ifdef USE_PTHREAD_MUTEX
|
||||
#include <pthread.h>
|
||||
#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 <SLES/OpenSLES.h>
|
||||
#ifdef ANDROID
|
||||
#include <SLES/OpenSLES_Android.h>
|
||||
#endif
|
||||
|
||||
#include "client/sound/SoundSystem.hpp"
|
||||
#include "client/sound/SoundData.hpp"
|
||||
|
||||
typedef std::list<SLObjectItf> 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<SLObjectItf> m_tempToRemove;
|
||||
|
||||
static std::vector<SLObjectItf> toRemove;
|
||||
static SLObjectItf objEngine;
|
||||
static pthread_mutex_t toRemoveMutex;
|
||||
};
|
||||
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user