diff options
author | Juan Linietsky <reduzio@gmail.com> | 2014-02-09 22:10:30 -0300 |
---|---|---|
committer | Juan Linietsky <reduzio@gmail.com> | 2014-02-09 22:10:30 -0300 |
commit | 0b806ee0fc9097fa7bda7ac0109191c9c5e0a1ac (patch) | |
tree | 276c4d099e178eb67fbd14f61d77b05e3808e9e3 /platform/android/audio_driver_android.cpp | |
parent | 0e49da1687bc8192ed210947da52c9e5c5f301bb (diff) |
GODOT IS OPEN SOURCE
Diffstat (limited to 'platform/android/audio_driver_android.cpp')
-rw-r--r-- | platform/android/audio_driver_android.cpp | 393 |
1 files changed, 393 insertions, 0 deletions
diff --git a/platform/android/audio_driver_android.cpp b/platform/android/audio_driver_android.cpp new file mode 100644 index 0000000000..4f7b4ee348 --- /dev/null +++ b/platform/android/audio_driver_android.cpp @@ -0,0 +1,393 @@ +/*************************************************************************/ +/* audio_driver_android.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "audio_driver_android.h" +#include <string.h> +#ifdef ANDROID_NATIVE_ACTIVITY + + + + + +#define MAX_NUMBER_INTERFACES 3 +#define MAX_NUMBER_OUTPUT_DEVICES 6 + +/* Structure for passing information to callback function */ + + +void AudioDriverAndroid::_buffer_callback( + SLAndroidSimpleBufferQueueItf queueItf + /* SLuint32 eventFlags, + const void * pBuffer, + SLuint32 bufferSize, + SLuint32 dataUsed*/) { + + + + if (mutex) + mutex->lock(); + + audio_server_process(buffer_size,mixdown_buffer); + + if (mutex) + mutex->unlock(); + + + const int32_t* src_buff=mixdown_buffer; + + int16_t *ptr = (int16_t*)buffers[last_free]; + last_free=(last_free+1)%BUFFER_COUNT; + + for(int i=0;i<buffer_size*2;i++) { + + ptr[i]=src_buff[i]>>16; + } + + (*queueItf)->Enqueue(queueItf, ptr, 4 * buffer_size); + + +#if 0 + SLresult res; + CallbackCntxt *pCntxt = (CallbackCntxt*)pContext; + if(pCntxt->pData < (pCntxt->pDataBase + pCntxt->size)) + { + res = (*queueItf)->Enqueue(queueItf, (void*) pCntxt->pData, + 2 * AUDIO_DATA_BUFFER_SIZE, SL_BOOLEAN_FALSE); /* Size given + in bytes. */ + CheckErr(res); + /* Increase data pointer by buffer size */ + pCntxt->pData += AUDIO_DATA_BUFFER_SIZE; + } + } +#endif +} + +void AudioDriverAndroid::_buffer_callbacks( + SLAndroidSimpleBufferQueueItf queueItf, + /*SLuint32 eventFlags, + const void * pBuffer, + SLuint32 bufferSize, + SLuint32 dataUsed,*/ + void *pContext) { + + + AudioDriverAndroid *ad = (AudioDriverAndroid*)pContext; + +// ad->_buffer_callback(queueItf,eventFlags,pBuffer,bufferSize,dataUsed); + ad->_buffer_callback(queueItf); + +} + + +AudioDriverAndroid* AudioDriverAndroid::s_ad=NULL; + +const char* AudioDriverAndroid::get_name() const { + + return "Android"; +} + +#if 0 +int AudioDriverAndroid::thread_func(SceSize args, void *argp) { + + AudioDriverAndroid* ad = s_ad; + sceAudioOutput2Reserve(AUDIO_OUTPUT_SAMPLE); + + int half=0; + while(!ad->exit_thread) { + + int16_t *ptr = &ad->outbuff[AUDIO_OUTPUT_SAMPLE*2*half]; + + + + if (!ad->active) { + + for(int i=0;i<AUDIO_OUTPUT_SAMPLE*2;i++) { + ptr[i]=0; + } + + } else { + + //printf("samples: %i\n",AUDIO_OUTPUT_SAMPLE); + ad->lock(); + + ad->audio_server_process(AUDIO_OUTPUT_SAMPLE,ad->outbuff_32); + + ad->unlock(); + + const int32_t* src_buff=ad->outbuff_32; + + for(int i=0;i<AUDIO_OUTPUT_SAMPLE*2;i++) { + + ptr[i]=src_buff[i]>>16; + } + } + + + /* Output 16-bit PCM STEREO data that is in pcmBuf without changing the volume */ + sceAudioOutput2OutputBlocking( + SCE_AUDIO_VOLUME_0dB*3, //0db at 0x8000, that's obvious + ptr + ); + + if (half) + half=0; + else + half=1; + + } + + sceAudioOutput2Release(); + + sceKernelExitThread(SCE_KERNEL_EXIT_SUCCESS); + ad->thread_exited=true; + return SCE_KERNEL_EXIT_SUCCESS; + +} + +#endif +Error AudioDriverAndroid::init(){ + + SLresult + res; + SLEngineOption EngineOption[] = { + (SLuint32) SL_ENGINEOPTION_THREADSAFE, + (SLuint32) SL_BOOLEAN_TRUE + + }; + res = slCreateEngine( &sl, 1, EngineOption, 0, NULL, NULL); + if (res!=SL_RESULT_SUCCESS) { + + ERR_EXPLAIN("Could not Initialize OpenSL"); + ERR_FAIL_V(ERR_INVALID_PARAMETER); + } + res = (*sl)->Realize(sl, SL_BOOLEAN_FALSE); + if (res!=SL_RESULT_SUCCESS) { + + ERR_EXPLAIN("Could not Realize OpenSL"); + ERR_FAIL_V(ERR_INVALID_PARAMETER); + } + + print_line("OpenSL Init OK!"); + + return OK; + +} +void AudioDriverAndroid::start(){ + + + mutex = Mutex::create(); + active=false; + + + SLint32 numOutputs = 0; + SLuint32 deviceID = 0; + SLresult res; + + + buffer_size = 1024; + + for(int i=0;i<BUFFER_COUNT;i++) { + + buffers[i]=memnew_arr( int16_t,buffer_size*2 ); + memset(buffers[i],0,buffer_size*4); + } + + mixdown_buffer = memnew_arr( int32_t,buffer_size* 2); + + /* Callback context for the buffer queue callback function */ + + /* Get the SL Engine Interface which is implicit */ + res = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void*)&EngineItf); + + ERR_FAIL_COND( res !=SL_RESULT_SUCCESS ); + /* Initialize arrays required[] and iidArray[] */ + int i; + SLboolean required[MAX_NUMBER_INTERFACES]; + SLInterfaceID iidArray[MAX_NUMBER_INTERFACES]; + +#if 0 + + for (i=0; i<MAX_NUMBER_INTERFACES; i++) + { + required[i] = SL_BOOLEAN_FALSE; + iidArray[i] = SL_IID_NULL; + } + // Set arrays required[] and iidArray[] for VOLUME interface + required[0] = SL_BOOLEAN_TRUE; + iidArray[0] = SL_IID_VOLUME; + + // Create Output Mix object to be used by player + res = (*EngineItf)->CreateOutputMix(EngineItf, &OutputMix, 1, + iidArray, required); +#else + + { + const SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB}; + const SLboolean req[1] = {SL_BOOLEAN_FALSE}; + res = (*EngineItf)->CreateOutputMix(EngineItf, &OutputMix, 0, + ids, req); + } + + +#endif + ERR_FAIL_COND( res !=SL_RESULT_SUCCESS ); + // Realizing the Output Mix object in synchronous mode. + res = (*OutputMix)->Realize(OutputMix, SL_BOOLEAN_FALSE); + ERR_FAIL_COND( res !=SL_RESULT_SUCCESS ); + + SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, BUFFER_COUNT}; +// bufferQueue.locatorType = SL_DATALOCATOR_BUFFERQUEUE; +// bufferQueue.numBuffers = BUFFER_COUNT; /* Four buffers in our buffer queue */ + /* Setup the format of the content in the buffer queue */ + pcm.formatType = SL_DATAFORMAT_PCM; + pcm.numChannels = 2; + pcm.samplesPerSec = SL_SAMPLINGRATE_44_1; + pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16; + pcm.containerSize = SL_PCMSAMPLEFORMAT_FIXED_16; + pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; +#ifdef BIG_ENDIAN_ENABLED + pcm.endianness = SL_BYTEORDER_BIGENDIAN; +#else + pcm.endianness = SL_BYTEORDER_LITTLEENDIAN; +#endif + audioSource.pFormat = (void *)&pcm; + audioSource.pLocator = (void *)&loc_bufq; + + + /* Setup the data sink structure */ + locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX; + locator_outputmix.outputMix= OutputMix; + audioSink.pLocator = (void *)&locator_outputmix; + audioSink.pFormat = NULL; + /* Initialize the context for Buffer queue callbacks */ +// cntxt.pDataBase = (void*)&pcmData; + //cntxt.pData = cntxt.pDataBase; + //cntxt.size = sizeof(pcmData); + /* Set arrays required[] and iidArray[] for SEEK interface + (PlayItf is implicit) */ + required[0] = SL_BOOLEAN_TRUE; + iidArray[0] = SL_IID_BUFFERQUEUE; + /* Create the music player */ + + { + const SLInterfaceID ids[2] = {SL_IID_BUFFERQUEUE, SL_IID_EFFECTSEND}; + const SLboolean req[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; + + res = (*EngineItf)->CreateAudioPlayer(EngineItf, &player, + &audioSource, &audioSink, 1, ids, req); + ERR_FAIL_COND( res !=SL_RESULT_SUCCESS ); + } + /* Realizing the player in synchronous mode. */ + res = (*player)->Realize(player, SL_BOOLEAN_FALSE); + ERR_FAIL_COND( res !=SL_RESULT_SUCCESS ); + /* Get seek and play interfaces */ + res = (*player)->GetInterface(player, SL_IID_PLAY, (void*)&playItf); + ERR_FAIL_COND( res !=SL_RESULT_SUCCESS ); + res = (*player)->GetInterface(player, SL_IID_BUFFERQUEUE, + (void*)&bufferQueueItf); + ERR_FAIL_COND( res !=SL_RESULT_SUCCESS ); + /* Setup to receive buffer queue event callbacks */ + res = (*bufferQueueItf)->RegisterCallback(bufferQueueItf, + _buffer_callbacks, this); + ERR_FAIL_COND( res !=SL_RESULT_SUCCESS ); + /* Before we start set volume to -3dB (-300mB) */ +#if 0 + res = (*OutputMix)->GetInterface(OutputMix, SL_IID_VOLUME, + (void*)&volumeItf); + ERR_FAIL_COND( res !=SL_RESULT_SUCCESS ); + /* Setup the data source structure for the buffer queue */ + + res = (*volumeItf)->SetVolumeLevel(volumeItf, -300); + ERR_FAIL_COND( res !=SL_RESULT_SUCCESS ); +#endif + last_free=0; +#if 1 + //fill up buffers + for(int i=0;i<BUFFER_COUNT;i++) { + /* Enqueue a few buffers to get the ball rolling */ + res = (*bufferQueueItf)->Enqueue(bufferQueueItf, buffers[i], + 4 * buffer_size); /* Size given in */ + + } +#endif + + res = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PLAYING); + ERR_FAIL_COND( res !=SL_RESULT_SUCCESS ); + +#if 0 + res = (*bufferQueueItf)->GetState(bufferQueueItf, &state); + ERR_FAIL_COND( res !=SL_RESULT_SUCCESS ); + while(state.count) + { + (*bufferQueueItf)->GetState(bufferQueueItf, &state); + } + /* Make sure player is stopped */ + res = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED); + CheckErr(res); + /* Destroy the player */ + (*player)->Destroy(player); + /* Destroy Output Mix object */ + (*OutputMix)->Destroy(OutputMix); +#endif + + active=true; +} +int AudioDriverAndroid::get_mix_rate() const { + + return 44100; +} +AudioDriverSW::OutputFormat AudioDriverAndroid::get_output_format() const{ + + return OUTPUT_STEREO; +} +void AudioDriverAndroid::lock(){ + + //if (active && mutex) + // mutex->lock(); + +} +void AudioDriverAndroid::unlock() { + + //if (active && mutex) + // mutex->unlock(); + +} +void AudioDriverAndroid::finish(){ + + (*sl)->Destroy(sl); + +} + + +AudioDriverAndroid::AudioDriverAndroid() +{ + s_ad=this; + mutex=NULL; +} + +#endif |