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:
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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user