/* =========================================================================== Copyright (C) 2005 - 2015, ioquake3 contributors Copyright (C) 2013 - 2015, OpenJK contributors This file is part of the OpenJK source code. OpenJK is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. 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, see . =========================================================================== */ #include #include #include #include #include #include //#include #include #ifdef __linux__ // rb0101023 - guard this #include #endif #ifdef __FreeBSD__ // rb0101023 - added #include #endif #include #include "qcommon/q_shared.h" #include "client/snd_local.h" //Updated by Emile Belanger for OpenSL // for native audio #include #include #include pthread_mutex_t dma_mutex; // engine interfaces static SLObjectItf engineObject = NULL; static SLEngineItf engineEngine; // output mix interfaces static SLObjectItf outputMixObject = NULL; // buffer queue player interfaces static SLObjectItf bqPlayerObject = NULL; static SLPlayItf bqPlayerPlay; static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue; static SLEffectSendItf bqPlayerEffectSend; static SLMuteSoloItf bqPlayerMuteSolo; static SLVolumeItf bqPlayerVolume; void myassert(int v,const char * message) { if (!v) Com_Printf("myassert: %s",message); } int audio_fd; int snd_inited = 0; cvar_t *sndbits; cvar_t *sndspeed; cvar_t *sndchannels; cvar_t *snddevice; /* Some devices may work only with 48000 */ static int tryrates[] = { 22050, 11025, 44100, 48000, 8000 }; static int dmapos = 0; static int dmasize = 0; #define OPENSL_BUFF_LEN 1024 static unsigned char play_buffer[OPENSL_BUFF_LEN]; void bqPause(int p) { int result; if (p) { result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PAUSED); myassert(SL_RESULT_SUCCESS == result,"SetPlayState"); } else { result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING); myassert(SL_RESULT_SUCCESS == result,"SetPlayState"); result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, "\0", 1); myassert(SL_RESULT_SUCCESS == result,"Enqueue first buffer"); } } //NOTE!! There are definetly threading issues with this, but it appears to work for now... // TEST is me testing black screen issue! void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) { //LOGI("bqPlayerCallback"); // TEST pthread_mutex_lock(&dma_mutex); int pos = (dmapos * (dma.samplebits/8)); if (pos >= dmasize) dmapos = pos = 0; int len = OPENSL_BUFF_LEN; int factor = 2*2; int FrameCount = (unsigned int)OPENSL_BUFF_LEN / factor; if (!snd_inited) /* shouldn't happen, but just in case... */ { memset(play_buffer, '\0', len); return; } else { int tobufend = dmasize - pos; /* bytes to buffer's end. */ int len1 = len; int len2 = 0; if (len1 > tobufend) { len1 = tobufend; len2 = len - len1; } memcpy(play_buffer, dma.buffer + pos, len1); if (len2 <= 0) dmapos += (len1 / (dma.samplebits/8)); else /* wraparound? */ { memcpy(play_buffer+len1, dma.buffer, len2); dmapos = (len2 / (dma.samplebits/8)); } } if (dmapos >= dmasize) dmapos = 0; SLresult result; //LOGI("Frame count = %d",FrameCount); if (FrameCount == 0) FrameCount = 1; result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, play_buffer,FrameCount * factor); myassert(SL_RESULT_SUCCESS == result,"Enqueue failed"); // TEST pthread_mutex_unlock(&dma_mutex); } int SNDDMA_Init( int sampleFrequencyInKHz ) { int rc; int fmt; int tmp; int i; // char *s; // bk001204 - unused struct audio_buf_info info; int caps; extern uid_t saved_euid; if ( snd_inited ) { return 1; } dmapos = 0; dma.samplebits = 16; dma.channels = 2; dma.samples = 1024*16; dma.submission_chunk = 1024*2; //dma.submission_chunk = 1; dma.speed = 44100; dma.speed = 22050; dmasize = (dma.samples * (dma.samplebits/8)); dma.buffer = (byte*)calloc(1, dmasize); SLresult result; // create engine result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL); myassert(SL_RESULT_SUCCESS == result,"slCreateEngine"); // realize the engine result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE); myassert(SL_RESULT_SUCCESS == result,"Realize"); // get the engine interface, which is needed in order to create other objects result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine); myassert(SL_RESULT_SUCCESS == result,"GetInterface"); // create output mix result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, NULL, NULL); myassert(SL_RESULT_SUCCESS == result,"CreateOutputMix"); // realize the output mix result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE); myassert(SL_RESULT_SUCCESS == result,"Realize output mix"); //CREATE THE PLAYER // configure audio source SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 1}; SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, 2, SL_SAMPLINGRATE_22_05, SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16, SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT, SL_BYTEORDER_LITTLEENDIAN}; SLDataSource audioSrc = {&loc_bufq, &format_pcm}; // configure audio sink SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject}; SLDataSink audioSnk = {&loc_outmix, NULL}; // create audio player Com_Printf("create audio player"); const SLInterfaceID ids[1] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE}; const SLboolean req[1] = {SL_BOOLEAN_TRUE}; result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk, 1, ids, req); myassert(SL_RESULT_SUCCESS == result,"CreateAudioPlayer"); // realize the player result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE); myassert(SL_RESULT_SUCCESS == result,"Realize AudioPlayer"); // get the play interface result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay); myassert(SL_RESULT_SUCCESS == result,"GetInterface AudioPlayer"); // get the buffer queue interface result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE, &bqPlayerBufferQueue); myassert(SL_RESULT_SUCCESS == result,"GetInterface buffer queue"); // register callback on the buffer queue result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, NULL); myassert(SL_RESULT_SUCCESS == result,"RegisterCallback"); snd_inited = 1; // set the player's state to playing result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING); myassert(SL_RESULT_SUCCESS == result,"SetPlayState"); result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, "\0", 1); myassert(SL_RESULT_SUCCESS == result,"Enqueue first buffer"); return 1; } int SNDDMA_GetDMAPos( void ) { struct count_info count; if ( !snd_inited ) { return 0; } // TEST pthread_mutex_lock(&dma_mutex); //LOGI("SNDDMA_GetDMAPos"); return dmapos; } void SNDDMA_Shutdown( void ) { //LOGI("shutdown Sound"); bqPause(1); (*bqPlayerObject)->Destroy(bqPlayerObject); (*outputMixObject)->Destroy(outputMixObject); (*engineObject)->Destroy(engineObject); bqPlayerObject = NULL; outputMixObject = NULL; engineObject = NULL; } /* ============== SNDDMA_Submit Send sound to device if buffer isn't really the dma buffer =============== */ void SNDDMA_Submit( void ) { //LOGI("SNDDMA_Submit"); // TEST pthread_mutex_unlock(&dma_mutex); } void SNDDMA_BeginPainting( void ) { //LOGI("SNDDMA_BeginPainting"); //pthread_mutex_lock(&dma_mutex); }