mirror of
https://gitea.sffempire.ru/Kolyah35/minecraft-pe-0.6.1.git
synced 2026-03-19 22:43:32 +00:00
244 lines
7.2 KiB
C++
Executable File
244 lines
7.2 KiB
C++
Executable File
#include "SoundSystemSL.h"
|
|
#include <SLES/OpenSLES_Platform.h>
|
|
#include <SLES/OpenSLES_AndroidConfiguration.h>
|
|
#include "../../util/Mth.h"
|
|
#include "../../world/level/tile/Tile.h"
|
|
#include "../../world/phys/Vec3.h"
|
|
#include "../../client/sound/Sound.h"
|
|
|
|
#include "../log.h"
|
|
|
|
// Only one engine can be created at once. You CAN (if you really want)
|
|
// start two games at once, then it will crash without objEngine being static.
|
|
/*static*/ SLObjectItf SoundSystemSL::objEngine = 0;
|
|
|
|
typedef struct t_context {
|
|
SLObjectItf obj;
|
|
Mutex* mutex;
|
|
} t_context;
|
|
|
|
Mutex SoundSystemSL::toRemoveMutex;
|
|
std::vector<SLObjectItf> SoundSystemSL::toRemove;
|
|
|
|
SoundSystemSL::SoundSystemSL()
|
|
: available(true),
|
|
listener(NULL),
|
|
numBuffersPlaying(0)
|
|
{
|
|
init();
|
|
}
|
|
|
|
SoundSystemSL::~SoundSystemSL()
|
|
{
|
|
toRemoveMutex.unlock();
|
|
for (SoundList::iterator it = playingBuffers.begin(); it != playingBuffers.end(); ++it)
|
|
(**it)->Destroy(*it);
|
|
(*objOutput)->Destroy(objOutput);
|
|
|
|
if (SoundSystemSL::objEngine != 0) {
|
|
(*SoundSystemSL::objEngine)->Destroy(SoundSystemSL::objEngine);
|
|
SoundSystemSL::objEngine = 0;
|
|
}
|
|
}
|
|
|
|
void SoundSystemSL::init()
|
|
{
|
|
SoundSystemSL::toRemove.clear();
|
|
SoundSystemSL::toRemove.reserve(MAX_BUFFERS_PLAYING);
|
|
toRemoveCopy.resize(MAX_BUFFERS_PLAYING);
|
|
|
|
SLresult res;
|
|
const int MAX_NUMBER_INTERFACES = 2;
|
|
SLboolean required[MAX_NUMBER_INTERFACES];
|
|
SLInterfaceID iidArray[MAX_NUMBER_INTERFACES];
|
|
|
|
SLEngineOption EngineOption[] = {(SLuint32)
|
|
SL_ENGINEOPTION_THREADSAFE, (SLuint32) SL_BOOLEAN_TRUE};
|
|
|
|
/* Create OpenSL ES (destroy first if needed)*/
|
|
if (SoundSystemSL::objEngine != 0)
|
|
(*SoundSystemSL::objEngine)->Destroy(SoundSystemSL::objEngine);
|
|
|
|
res = slCreateEngine( &SoundSystemSL::objEngine, 1, EngineOption, 0, NULL, NULL);
|
|
checkErr(res);
|
|
|
|
/* Realizing the SL Engine in synchronous mode. */
|
|
res = (*SoundSystemSL::objEngine)->Realize(SoundSystemSL::objEngine, SL_BOOLEAN_FALSE);
|
|
if (checkErr(res)) {
|
|
available = false;
|
|
return;
|
|
}
|
|
|
|
(*SoundSystemSL::objEngine)->GetInterface(SoundSystemSL::objEngine, SL_IID_ENGINE, (void*)&engEngine);
|
|
checkErr(res);
|
|
|
|
/* Create Output Mix object to be used by player - no interfaces
|
|
required */
|
|
res = (*engEngine)->CreateOutputMix(engEngine, &objOutput, 0, iidArray, required);
|
|
checkErr(res);
|
|
|
|
/* Realizing the Output Mix object in synchronous mode. */
|
|
res = (*objOutput)->Realize(objOutput, SL_BOOLEAN_FALSE);
|
|
checkErr(res);
|
|
}
|
|
|
|
void SoundSystemSL::destroy() {}
|
|
|
|
void SoundSystemSL::setListenerPos( float x, float y, float z )
|
|
{
|
|
if (!listener) {
|
|
listenerPos = Vec3(x, y, z);
|
|
return;
|
|
}
|
|
|
|
SLVec3D pos = {(SLint32)(1000.0f * x), (SLint32)(1000.0f * y), (SLint32)(1000.0f * z)};
|
|
SLresult res = (*listener)->SetLocationCartesian(listener, &pos);
|
|
checkErr(res);
|
|
}
|
|
|
|
void SoundSystemSL::setListenerAngle( float deg )
|
|
{
|
|
if (!listener) return;
|
|
|
|
SLresult res = (*listener)->SetOrientationAngles(listener, deg*1000.0f, 0, 0);
|
|
checkErr(res);
|
|
}
|
|
|
|
void SoundSystemSL::playAt( const SoundDesc& sound, float x, float y, float z, float volume, float pitch )
|
|
{
|
|
removeStoppedSounds();
|
|
|
|
if (numBuffersPlaying >= MAX_BUFFERS_PLAYING)
|
|
return;
|
|
|
|
/* Setup the data source structure for the player */
|
|
SLDataLocator_AndroidSimpleBufferQueue uri = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};
|
|
SLDataFormat_PCM mime = {
|
|
SL_DATAFORMAT_PCM,
|
|
(SLuint32)sound.channels,
|
|
(SLuint32)(sound.frameRate * 1000),
|
|
(SLuint32)(sound.byteWidth << 3),
|
|
(SLuint32)(sound.byteWidth << 3),
|
|
sound.channels==1? SL_SPEAKER_FRONT_CENTER :
|
|
SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,
|
|
SL_BYTEORDER_LITTLEENDIAN
|
|
};
|
|
SLDataSource audioSource = {&uri, &mime};
|
|
SLDataLocator_OutputMix locator_outputmix;
|
|
SLDataSink audioSink;
|
|
SLObjectItf player;
|
|
SLPlayItf playItf;
|
|
//SL3DLocationItf locationItf;
|
|
SLVolumeItf volumeItf;
|
|
|
|
/* Setup the data sink structure */
|
|
locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
|
|
locator_outputmix.outputMix = objOutput;
|
|
audioSink.pLocator = (void *)&locator_outputmix;
|
|
audioSink.pFormat = NULL;
|
|
|
|
/* Buffer queue-able */
|
|
static SLboolean required[2];
|
|
static SLInterfaceID iidArray[2];
|
|
required[0] = SL_BOOLEAN_TRUE;
|
|
iidArray[0] = SL_IID_BUFFERQUEUE;
|
|
required[1] = SL_BOOLEAN_TRUE;
|
|
iidArray[1] = SL_IID_VOLUME;
|
|
|
|
/* Create the 3D player */
|
|
SLresult res = (*engEngine)->CreateAudioPlayer(engEngine, &player,
|
|
&audioSource, &audioSink, 2, iidArray, required);
|
|
//printf("SL: Created audio player\n");
|
|
checkErr(res);
|
|
|
|
/* Realizing the player in synchronous mode. */
|
|
res = (*player)->Realize(player, SL_BOOLEAN_FALSE);
|
|
//LOGI("SL: Realize audio player\n");
|
|
checkErr(res);
|
|
|
|
/* Get the play and volume interfaces */
|
|
res = (*player)->GetInterface(player, SL_IID_PLAY, (void*)&playItf);
|
|
//LOGI("SL: Get Player interface\n");
|
|
checkErr(res);
|
|
|
|
res = (*player)->GetInterface(player, SL_IID_VOLUME, (void*)&volumeItf);
|
|
//LOGI("SL: Get Player interface\n");
|
|
checkErr(res);
|
|
|
|
SLmillibel maxVolume;
|
|
res = (*volumeItf)->GetMaxVolumeLevel(volumeItf, &maxVolume);
|
|
SLmillibel mbelVolume = maxVolume - 2000 * (1-volume);//Mth::lerp(SL_MILLIBEL_MIN, maxVolume, 0.95f + 0.05f*volume);
|
|
LOGI("min: %d, max: %d, current: %d (%f)\n", SL_MILLIBEL_MIN, maxVolume, mbelVolume, volume);
|
|
res = (*volumeItf)->SetVolumeLevel(volumeItf, mbelVolume);
|
|
checkErr(res);
|
|
|
|
SLAndroidSimpleBufferQueueItf buffer1;
|
|
res = (*player)->GetInterface(player, SL_IID_BUFFERQUEUE, &buffer1);
|
|
checkErr(res);
|
|
|
|
//t_context* context = new t_context(); //{ player, &toRemoveMutex };
|
|
//context->obj = player;
|
|
//context->mutex = &toRemoveMutex;
|
|
res = (*buffer1)->RegisterCallback(buffer1, SoundSystemSL::removePlayer, (void*)player);
|
|
checkErr(res);
|
|
|
|
res = (*buffer1)->Enqueue(buffer1, sound.frames, sound.size);
|
|
checkErr(res);
|
|
|
|
/* Start playing the 3D source */
|
|
res = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PLAYING );
|
|
//LOGI("SL: Set play state\n");
|
|
checkErr(res);
|
|
|
|
playingBuffers.push_back(player);
|
|
++numBuffersPlaying;
|
|
}
|
|
|
|
bool SoundSystemSL::checkErr( SLresult res )
|
|
{
|
|
if ( res != SL_RESULT_SUCCESS ) {
|
|
LOGI("OpenSL error: %d\n", res);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/*static*/
|
|
void SoundSystemSL::removeStoppedSounds()
|
|
{
|
|
toRemoveMutex.lock();
|
|
const int numBuffersToRemove = toRemove.size();
|
|
for (int i = 0; i < numBuffersToRemove; ++i)
|
|
toRemoveCopy[i] = toRemove[i];
|
|
SoundSystemSL::toRemove.clear();
|
|
toRemoveMutex.unlock();
|
|
|
|
for (int i = 0; i < numBuffersToRemove; ++i) {
|
|
SLObjectItf obj = toRemoveCopy[i];
|
|
|
|
SoundList::iterator it = playingBuffers.begin();
|
|
while (it != playingBuffers.end()) {
|
|
if (*it == obj) {
|
|
playingBuffers.erase(it);
|
|
break;
|
|
}
|
|
++it;
|
|
}
|
|
(*obj)->Destroy(obj);
|
|
--numBuffersPlaying;
|
|
}
|
|
}
|
|
|
|
void SoundSystemSL::removePlayer( SLAndroidSimpleBufferQueueItf bq, void *context_ )
|
|
{
|
|
//t_context* context = (t_context*) context_;
|
|
//context->mutex->lock();
|
|
//SoundSystemSL::toRemove.push_back( context->obj );
|
|
//context->mutex->unlock();
|
|
//delete context;
|
|
|
|
SoundSystemSL::toRemoveMutex.lock();
|
|
SoundSystemSL::toRemove.push_back( (SLObjectItf) context_ );
|
|
SoundSystemSL::toRemoveMutex.unlock();
|
|
}
|