Alibek Omarov
6 years ago
1 changed files with 309 additions and 0 deletions
@ -0,0 +1,309 @@
@@ -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