mirror of
https://github.com/FWGS/xash3d-fwgs
synced 2024-12-25 18:25:45 +01:00
engine: android: restore OpenSL ES audio
This commit is contained in:
parent
e7ddc6d6c5
commit
621cdba53c
309
engine/platform/android/snd_opensles.c
Normal file
309
engine/platform/android/snd_opensles.c
Normal file
@ -0,0 +1,309 @@
|
||||
/*
|
||||
Copyright (C) 2015 SiPlus, Chasseur de bots
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#if XASH_SOUND == SOUND_OPENSLES
|
||||
#include <SLES/OpenSLES.h>
|
||||
#include "pthread.h"
|
||||
#include "sound.h"
|
||||
|
||||
extern convar_t *s_primary;
|
||||
extern dma_t dma;
|
||||
|
||||
static SLObjectItf snddma_android_engine = NULL;
|
||||
static SLObjectItf snddma_android_outputMix = NULL;
|
||||
static SLObjectItf snddma_android_player = NULL;
|
||||
static SLBufferQueueItf snddma_android_bufferQueue;
|
||||
static SLPlayItf snddma_android_play;
|
||||
|
||||
static pthread_mutex_t snddma_android_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static int snddma_android_pos;
|
||||
static int snddma_android_size;
|
||||
|
||||
static const SLInterfaceID *pSL_IID_ENGINE;
|
||||
static const SLInterfaceID *pSL_IID_BUFFERQUEUE;
|
||||
static const SLInterfaceID *pSL_IID_PLAY;
|
||||
static SLresult SLAPIENTRY (*pslCreateEngine)(
|
||||
SLObjectItf *pEngine,
|
||||
SLuint32 numOptions,
|
||||
const SLEngineOption *pEngineOptions,
|
||||
SLuint32 numInterfaces,
|
||||
const SLInterfaceID *pInterfaceIds,
|
||||
const SLboolean * pInterfaceRequired
|
||||
);
|
||||
|
||||
void S_Activate( qboolean active )
|
||||
{
|
||||
if( !dma.initialized )
|
||||
return;
|
||||
|
||||
if( active )
|
||||
{
|
||||
memset( dma.buffer, 0, snddma_android_size * 2 );
|
||||
(*snddma_android_bufferQueue)->Enqueue( snddma_android_bufferQueue, dma.buffer, snddma_android_size );
|
||||
(*snddma_android_play)->SetPlayState( snddma_android_play, SL_PLAYSTATE_PLAYING );
|
||||
}
|
||||
else
|
||||
{
|
||||
//if( s_globalfocus->integer )
|
||||
//return;
|
||||
(*snddma_android_play)->SetPlayState( snddma_android_play, SL_PLAYSTATE_STOPPED );
|
||||
(*snddma_android_bufferQueue)->Clear( snddma_android_bufferQueue );
|
||||
}
|
||||
}
|
||||
|
||||
static void SNDDMA_Android_Callback( SLBufferQueueItf bq, void *context )
|
||||
{
|
||||
uint8_t *buffer2;
|
||||
|
||||
pthread_mutex_lock( &snddma_android_mutex );
|
||||
|
||||
buffer2 = ( uint8_t * )dma.buffer + snddma_android_size;
|
||||
(*bq)->Enqueue( bq, buffer2, snddma_android_size );
|
||||
memcpy( buffer2, dma.buffer, snddma_android_size );
|
||||
memset( dma.buffer, 0, snddma_android_size );
|
||||
snddma_android_pos += dma.samples;
|
||||
|
||||
pthread_mutex_unlock( &snddma_android_mutex );
|
||||
}
|
||||
|
||||
static const char *SNDDMA_Android_Init( void )
|
||||
{
|
||||
SLresult result;
|
||||
|
||||
SLEngineItf engine;
|
||||
|
||||
int freq;
|
||||
|
||||
SLDataLocator_BufferQueue sourceLocator;
|
||||
SLDataFormat_PCM sourceFormat;
|
||||
SLDataSource source;
|
||||
|
||||
SLDataLocator_OutputMix sinkLocator;
|
||||
SLDataSink sink;
|
||||
|
||||
SLInterfaceID interfaceID;
|
||||
SLboolean interfaceRequired;
|
||||
|
||||
int samples;
|
||||
void *handle = dlopen( "libOpenSLES.so", RTLD_LAZY );
|
||||
|
||||
if( !handle )
|
||||
return "dlopen for libOpenSLES.so";
|
||||
|
||||
pslCreateEngine = dlsym( handle, "slCreateEngine" );
|
||||
|
||||
if( !pslCreateEngine )
|
||||
return "resolve slCreateEngine";
|
||||
|
||||
pSL_IID_ENGINE = dlsym( handle, "SL_IID_ENGINE" );
|
||||
|
||||
if( !pSL_IID_ENGINE )
|
||||
return "resolve SL_IID_ENGINE";
|
||||
|
||||
pSL_IID_PLAY = dlsym( handle, "SL_IID_PLAY" );
|
||||
|
||||
if( !pSL_IID_PLAY )
|
||||
return "resolve SL_IID_PLAY";
|
||||
|
||||
pSL_IID_BUFFERQUEUE = dlsym( handle, "SL_IID_BUFFERQUEUE" );
|
||||
|
||||
if( !pSL_IID_BUFFERQUEUE )
|
||||
return "resolve SL_IID_BUFFERQUEUE";
|
||||
|
||||
|
||||
result = pslCreateEngine( &snddma_android_engine, 0, NULL, 0, NULL, NULL );
|
||||
if( result != SL_RESULT_SUCCESS ) return "slCreateEngine";
|
||||
result = (*snddma_android_engine)->Realize( snddma_android_engine, SL_BOOLEAN_FALSE );
|
||||
if( result != SL_RESULT_SUCCESS ) return "engine->Realize";
|
||||
result = (*snddma_android_engine)->GetInterface( snddma_android_engine, *pSL_IID_ENGINE, &engine );
|
||||
if( result != SL_RESULT_SUCCESS ) return "engine->GetInterface(ENGINE)";
|
||||
|
||||
result = (*engine)->CreateOutputMix( engine, &snddma_android_outputMix, 0, NULL, NULL );
|
||||
if( result != SL_RESULT_SUCCESS ) return "engine->CreateOutputMix";
|
||||
result = (*snddma_android_outputMix)->Realize( snddma_android_outputMix, SL_BOOLEAN_FALSE );
|
||||
if( result != SL_RESULT_SUCCESS ) return "outputMix->Realize";
|
||||
|
||||
freq = SOUND_DMA_SPEED;
|
||||
sourceLocator.locatorType = SL_DATALOCATOR_BUFFERQUEUE;
|
||||
sourceLocator.numBuffers = 2;
|
||||
sourceFormat.formatType = SL_DATAFORMAT_PCM;
|
||||
sourceFormat.numChannels = 2; // always stereo, because engine supports only stereo
|
||||
sourceFormat.samplesPerSec = freq * 1000;
|
||||
sourceFormat.bitsPerSample = 16; // always 16 bit audio
|
||||
sourceFormat.containerSize = sourceFormat.bitsPerSample;
|
||||
sourceFormat.channelMask = SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT;
|
||||
sourceFormat.endianness = SL_BYTEORDER_LITTLEENDIAN;
|
||||
source.pLocator = &sourceLocator;
|
||||
source.pFormat = &sourceFormat;
|
||||
|
||||
sinkLocator.locatorType = SL_DATALOCATOR_OUTPUTMIX;
|
||||
sinkLocator.outputMix = snddma_android_outputMix;
|
||||
sink.pLocator = &sinkLocator;
|
||||
sink.pFormat = NULL;
|
||||
|
||||
interfaceID = *pSL_IID_BUFFERQUEUE;
|
||||
interfaceRequired = SL_BOOLEAN_TRUE;
|
||||
|
||||
result = (*engine)->CreateAudioPlayer( engine, &snddma_android_player, &source, &sink, 1, &interfaceID, &interfaceRequired );
|
||||
if( result != SL_RESULT_SUCCESS ) return "engine->CreateAudioPlayer";
|
||||
result = (*snddma_android_player)->Realize( snddma_android_player, SL_BOOLEAN_FALSE );
|
||||
if( result != SL_RESULT_SUCCESS ) return "player->Realize";
|
||||
result = (*snddma_android_player)->GetInterface( snddma_android_player, *pSL_IID_BUFFERQUEUE, &snddma_android_bufferQueue );
|
||||
if( result != SL_RESULT_SUCCESS ) return "player->GetInterface(BUFFERQUEUE)";
|
||||
result = (*snddma_android_player)->GetInterface( snddma_android_player, *pSL_IID_PLAY, &snddma_android_play );
|
||||
if( result != SL_RESULT_SUCCESS ) return "player->GetInterface(PLAY)";
|
||||
result = (*snddma_android_bufferQueue)->RegisterCallback( snddma_android_bufferQueue, SNDDMA_Android_Callback, NULL );
|
||||
if( result != SL_RESULT_SUCCESS ) return "bufferQueue->RegisterCallback";
|
||||
|
||||
samples = s_samplecount->value;
|
||||
if( !samples )
|
||||
samples = 4096;
|
||||
|
||||
dma.format.channels = sourceFormat.numChannels;
|
||||
dma.samples = samples * sourceFormat.numChannels;
|
||||
dma.format.speed = freq;
|
||||
snddma_android_size = dma.samples * ( sourceFormat.bitsPerSample >> 3 );
|
||||
dma.buffer = Z_Malloc( snddma_android_size * 2 );
|
||||
dma.samplepos = 0;
|
||||
// dma.sampleframes = dma.samples / dma.format.channels;
|
||||
dma.format.width = 2;
|
||||
if( !dma.buffer ) return "malloc";
|
||||
|
||||
//snddma_android_mutex = trap_Mutex_Create();
|
||||
|
||||
snddma_android_pos = 0;
|
||||
dma.initialized = true;
|
||||
|
||||
S_Activate( true );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
qboolean SNDDMA_Init( void *hwnd)
|
||||
{
|
||||
const char *initError;
|
||||
|
||||
Msg( "OpenSL ES audio device initializing...\n" );
|
||||
|
||||
initError = SNDDMA_Android_Init();
|
||||
if( initError )
|
||||
{
|
||||
Msg( S_ERROR "SNDDMA_Init: %s failed.\n", initError );
|
||||
SNDDMA_Shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
Msg( "OpenSL ES audio initialized.\n" );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int SNDDMA_GetDMAPos( void )
|
||||
{
|
||||
return snddma_android_pos;
|
||||
}
|
||||
|
||||
void SNDDMA_Shutdown( void )
|
||||
{
|
||||
Msg( "Closing OpenSL ES audio device...\n" );
|
||||
|
||||
if( snddma_android_player )
|
||||
{
|
||||
(*snddma_android_player)->Destroy( snddma_android_player );
|
||||
snddma_android_player = NULL;
|
||||
}
|
||||
if( snddma_android_outputMix )
|
||||
{
|
||||
(*snddma_android_outputMix)->Destroy( snddma_android_outputMix );
|
||||
snddma_android_outputMix = NULL;
|
||||
}
|
||||
if( snddma_android_engine )
|
||||
{
|
||||
(*snddma_android_engine)->Destroy( snddma_android_engine );
|
||||
snddma_android_engine = NULL;
|
||||
}
|
||||
|
||||
if( dma.buffer )
|
||||
{
|
||||
Z_Free( dma.buffer );
|
||||
dma.buffer = NULL;
|
||||
}
|
||||
|
||||
//if( snddma_android_mutex )
|
||||
//trap_Mutex_Destroy( &snddma_android_mutex );
|
||||
|
||||
Msg( "OpenSL ES audio device shut down.\n" );
|
||||
}
|
||||
|
||||
void SNDDMA_Submit( void )
|
||||
{
|
||||
pthread_mutex_unlock( &snddma_android_mutex );
|
||||
}
|
||||
|
||||
void SNDDMA_BeginPainting( void )
|
||||
{
|
||||
pthread_mutex_lock( &snddma_android_mutex );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
SNDDMA_GetSoundtime
|
||||
|
||||
update global soundtime
|
||||
===============
|
||||
*/
|
||||
int SNDDMA_GetSoundtime( void )
|
||||
{
|
||||
static int buffers, oldsamplepos;
|
||||
int samplepos, fullsamples;
|
||||
|
||||
fullsamples = dma.samples / 2;
|
||||
|
||||
// it is possible to miscount buffers
|
||||
// if it has wrapped twice between
|
||||
// calls to S_Update. Oh well.
|
||||
samplepos = SNDDMA_GetDMAPos();
|
||||
|
||||
if( samplepos < oldsamplepos )
|
||||
{
|
||||
buffers++; // buffer wrapped
|
||||
|
||||
if( paintedtime > 0x40000000 )
|
||||
{
|
||||
// time to chop things off to avoid 32 bit limits
|
||||
buffers = 0;
|
||||
paintedtime = fullsamples;
|
||||
S_StopAllSounds( true );
|
||||
}
|
||||
}
|
||||
|
||||
oldsamplepos = samplepos;
|
||||
|
||||
return (buffers * fullsamples + samplepos / 2);
|
||||
}
|
||||
|
||||
void S_PrintDeviceName( void )
|
||||
{
|
||||
Msg( "Audio: OpenSL\n" );
|
||||
}
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user