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