sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_openslES.c (24490B)


      1 /*
      2   Simple DirectMedia Layer
      3   Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
      4 
      5   This software is provided 'as-is', without any express or implied
      6   warranty.  In no event will the authors be held liable for any damages
      7   arising from the use of this software.
      8 
      9   Permission is granted to anyone to use this software for any purpose,
     10   including commercial applications, and to alter it and redistribute it
     11   freely, subject to the following restrictions:
     12 
     13   1. The origin of this software must not be misrepresented; you must not
     14      claim that you wrote the original software. If you use this software
     15      in a product, an acknowledgment in the product documentation would be
     16      appreciated but is not required.
     17   2. Altered source versions must be plainly marked as such, and must not be
     18      misrepresented as being the original software.
     19   3. This notice may not be removed or altered from any source distribution.
     20 */
     21 #include "../../SDL_internal.h"
     22 
     23 #if SDL_AUDIO_DRIVER_OPENSLES
     24 
     25 /* For more discussion of low latency audio on Android, see this:
     26    https://googlesamples.github.io/android-audio-high-performance/guides/opensl_es.html
     27 */
     28 
     29 #include "SDL_audio.h"
     30 #include "../SDL_audio_c.h"
     31 #include "../../core/android/SDL_android.h"
     32 #include "SDL_openslES.h"
     33 
     34 /* for native audio */
     35 #include <SLES/OpenSLES.h>
     36 #include <SLES/OpenSLES_Android.h>
     37 
     38 #include <android/log.h>
     39 
     40 #if 0
     41 #define LOG_TAG "SDL_openslES"
     42 #define LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
     43 #define LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
     44 //#define LOGV(...)  __android_log_print(ANDROID_LOG_VERBOSE,LOG_TAG,__VA_ARGS__)
     45 #define LOGV(...)
     46 #else
     47 #define LOGE(...)
     48 #define LOGI(...)
     49 #define LOGV(...)
     50 #endif
     51 
     52 /*
     53 #define SL_SPEAKER_FRONT_LEFT            ((SLuint32) 0x00000001)
     54 #define SL_SPEAKER_FRONT_RIGHT           ((SLuint32) 0x00000002)
     55 #define SL_SPEAKER_FRONT_CENTER          ((SLuint32) 0x00000004)
     56 #define SL_SPEAKER_LOW_FREQUENCY         ((SLuint32) 0x00000008)
     57 #define SL_SPEAKER_BACK_LEFT             ((SLuint32) 0x00000010)
     58 #define SL_SPEAKER_BACK_RIGHT            ((SLuint32) 0x00000020)
     59 #define SL_SPEAKER_FRONT_LEFT_OF_CENTER  ((SLuint32) 0x00000040)
     60 #define SL_SPEAKER_FRONT_RIGHT_OF_CENTER ((SLuint32) 0x00000080)
     61 #define SL_SPEAKER_BACK_CENTER           ((SLuint32) 0x00000100)
     62 #define SL_SPEAKER_SIDE_LEFT             ((SLuint32) 0x00000200)
     63 #define SL_SPEAKER_SIDE_RIGHT            ((SLuint32) 0x00000400)
     64 #define SL_SPEAKER_TOP_CENTER            ((SLuint32) 0x00000800)
     65 #define SL_SPEAKER_TOP_FRONT_LEFT        ((SLuint32) 0x00001000)
     66 #define SL_SPEAKER_TOP_FRONT_CENTER      ((SLuint32) 0x00002000)
     67 #define SL_SPEAKER_TOP_FRONT_RIGHT       ((SLuint32) 0x00004000)
     68 #define SL_SPEAKER_TOP_BACK_LEFT         ((SLuint32) 0x00008000)
     69 #define SL_SPEAKER_TOP_BACK_CENTER       ((SLuint32) 0x00010000)
     70 #define SL_SPEAKER_TOP_BACK_RIGHT        ((SLuint32) 0x00020000)
     71 */
     72 #define SL_ANDROID_SPEAKER_STEREO (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT)
     73 #define SL_ANDROID_SPEAKER_QUAD (SL_ANDROID_SPEAKER_STEREO | SL_SPEAKER_BACK_LEFT | SL_SPEAKER_BACK_RIGHT)
     74 #define SL_ANDROID_SPEAKER_5DOT1 (SL_ANDROID_SPEAKER_QUAD | SL_SPEAKER_FRONT_CENTER  | SL_SPEAKER_LOW_FREQUENCY)
     75 #define SL_ANDROID_SPEAKER_7DOT1 (SL_ANDROID_SPEAKER_5DOT1 | SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT)
     76 
     77 /* engine interfaces */
     78 static SLObjectItf engineObject;
     79 static SLEngineItf engineEngine;
     80 
     81 /* output mix interfaces */
     82 static SLObjectItf outputMixObject;
     83 
     84 /* buffer queue player interfaces */
     85 static SLObjectItf bqPlayerObject;
     86 static SLPlayItf bqPlayerPlay;
     87 static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue;
     88 #if 0
     89 static SLVolumeItf bqPlayerVolume;
     90 #endif
     91 
     92 /* recorder interfaces */
     93 static SLObjectItf recorderObject;
     94 static SLRecordItf recorderRecord;
     95 static SLAndroidSimpleBufferQueueItf recorderBufferQueue;
     96 
     97 #if 0
     98 static const char *sldevaudiorecorderstr = "SLES Audio Recorder";
     99 static const char *sldevaudioplayerstr   = "SLES Audio Player";
    100 
    101 #define  SLES_DEV_AUDIO_RECORDER  sldevaudiorecorderstr
    102 #define  SLES_DEV_AUDIO_PLAYER  sldevaudioplayerstr
    103 static void openslES_DetectDevices( int iscapture )
    104 {
    105     LOGI( "openSLES_DetectDevices()" );
    106     if ( iscapture )
    107             addfn( SLES_DEV_AUDIO_RECORDER );
    108     else
    109             addfn( SLES_DEV_AUDIO_PLAYER );
    110 }
    111 #endif
    112 
    113 static void openslES_DestroyEngine(void)
    114 {
    115     LOGI("openslES_DestroyEngine()");
    116 
    117     /* destroy output mix object, and invalidate all associated interfaces */
    118     if (outputMixObject != NULL) {
    119         (*outputMixObject)->Destroy(outputMixObject);
    120         outputMixObject = NULL;
    121     }
    122 
    123     /* destroy engine object, and invalidate all associated interfaces */
    124     if (engineObject != NULL) {
    125         (*engineObject)->Destroy(engineObject);
    126         engineObject = NULL;
    127         engineEngine = NULL;
    128     }
    129 }
    130 
    131 static int
    132 openslES_CreateEngine(void)
    133 {
    134     SLresult result;
    135 
    136     LOGI("openSLES_CreateEngine()");
    137 
    138     /* create engine */
    139     result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
    140     if (SL_RESULT_SUCCESS != result) {
    141         LOGE("slCreateEngine failed: %d", result);
    142         goto error;
    143     }
    144     LOGI("slCreateEngine OK");
    145 
    146     /* realize the engine */
    147     result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
    148     if (SL_RESULT_SUCCESS != result) {
    149         LOGE("RealizeEngine failed: %d", result);
    150         goto error;
    151     }
    152     LOGI("RealizeEngine OK");
    153 
    154     /* get the engine interface, which is needed in order to create other objects */
    155     result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
    156     if (SL_RESULT_SUCCESS != result) {
    157         LOGE("EngineGetInterface failed: %d", result);
    158         goto error;
    159     }
    160     LOGI("EngineGetInterface OK");
    161 
    162     /* create output mix */
    163     const SLInterfaceID ids[1] = { SL_IID_VOLUME };
    164     const SLboolean req[1] = { SL_BOOLEAN_FALSE };
    165     result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, ids, req);
    166     if (SL_RESULT_SUCCESS != result) {
    167         LOGE("CreateOutputMix failed: %d", result);
    168         goto error;
    169     }
    170     LOGI("CreateOutputMix OK");
    171 
    172     /* realize the output mix */
    173     result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
    174     if (SL_RESULT_SUCCESS != result) {
    175         LOGE("RealizeOutputMix failed: %d", result);
    176         goto error;
    177     }
    178     return 1;
    179 
    180 error:
    181     openslES_DestroyEngine();
    182     return 0;
    183 }
    184 
    185 /* this callback handler is called every time a buffer finishes recording */
    186 static void
    187 bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
    188 {
    189     struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) context;
    190 
    191     LOGV("SLES: Recording Callback");
    192     SDL_SemPost(audiodata->playsem);
    193 }
    194 
    195 static void
    196 openslES_DestroyPCMRecorder(_THIS)
    197 {
    198     struct SDL_PrivateAudioData *audiodata = this->hidden;
    199     SLresult result;
    200 
    201     /* stop recording */
    202     if (recorderRecord != NULL) {
    203         result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_STOPPED);
    204         if (SL_RESULT_SUCCESS != result) {
    205             LOGE("SetRecordState stopped: %d", result);
    206         }
    207     }
    208 
    209     /* destroy audio recorder object, and invalidate all associated interfaces */
    210     if (recorderObject != NULL) {
    211         (*recorderObject)->Destroy(recorderObject);
    212         recorderObject = NULL;
    213         recorderRecord = NULL;
    214         recorderBufferQueue = NULL;
    215     }
    216 
    217     if (audiodata->playsem) {
    218         SDL_DestroySemaphore(audiodata->playsem);
    219         audiodata->playsem = NULL;
    220     }
    221 
    222     if (audiodata->mixbuff) {
    223         SDL_free(audiodata->mixbuff);
    224     }
    225 }
    226 
    227 static int
    228 openslES_CreatePCMRecorder(_THIS)
    229 {
    230     struct SDL_PrivateAudioData *audiodata = this->hidden;
    231     SLDataFormat_PCM format_pcm;
    232     SLresult result;
    233     int i;
    234 
    235     if (!Android_JNI_RequestPermission("android.permission.RECORD_AUDIO")) {
    236         LOGE("This app doesn't have RECORD_AUDIO permission");
    237         return SDL_SetError("This app doesn't have RECORD_AUDIO permission");
    238     }
    239 
    240     /* Just go with signed 16-bit audio as it's the most compatible */
    241     this->spec.format = AUDIO_S16SYS;
    242     this->spec.channels = 1;
    243     /*this->spec.freq = SL_SAMPLINGRATE_16 / 1000;*/
    244 
    245     /* Update the fragment size as size in bytes */
    246     SDL_CalculateAudioSpec(&this->spec);
    247 
    248     LOGI("Try to open %u hz %u bit chan %u %s samples %u",
    249           this->spec.freq, SDL_AUDIO_BITSIZE(this->spec.format),
    250           this->spec.channels, (this->spec.format & 0x1000) ? "BE" : "LE", this->spec.samples);
    251 
    252     /* configure audio source */
    253     SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, SL_DEFAULTDEVICEID_AUDIOINPUT, NULL};
    254     SLDataSource audioSrc = {&loc_dev, NULL};
    255 
    256     /* configure audio sink */
    257     SLDataLocator_AndroidSimpleBufferQueue loc_bufq = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, NUM_BUFFERS };
    258 
    259     format_pcm.formatType    = SL_DATAFORMAT_PCM;
    260     format_pcm.numChannels   = this->spec.channels;
    261     format_pcm.samplesPerSec = this->spec.freq * 1000;  /* / kilo Hz to milli Hz */
    262     format_pcm.bitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
    263     format_pcm.containerSize = SDL_AUDIO_BITSIZE(this->spec.format);
    264     format_pcm.endianness    = SL_BYTEORDER_LITTLEENDIAN;
    265     format_pcm.channelMask   = SL_SPEAKER_FRONT_CENTER;
    266 
    267     SLDataSink audioSnk = { &loc_bufq, &format_pcm };
    268 
    269     /* create audio recorder */
    270     /* (requires the RECORD_AUDIO permission) */
    271     const SLInterfaceID ids[1] = {
    272         SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
    273     };
    274     const SLboolean req[1] = {
    275         SL_BOOLEAN_TRUE,
    276     };
    277 
    278     result = (*engineEngine)->CreateAudioRecorder(engineEngine, &recorderObject, &audioSrc, &audioSnk, 1, ids, req);
    279     if (SL_RESULT_SUCCESS != result) {
    280         LOGE("CreateAudioRecorder failed: %d", result);
    281         goto failed;
    282     }
    283 
    284     /* realize the recorder */
    285     result = (*recorderObject)->Realize(recorderObject, SL_BOOLEAN_FALSE);
    286     if (SL_RESULT_SUCCESS != result) {
    287         LOGE("RealizeAudioPlayer failed: %d", result);
    288         goto failed;
    289     }
    290 
    291     /* get the record interface */
    292     result = (*recorderObject)->GetInterface(recorderObject, SL_IID_RECORD, &recorderRecord);
    293     if (SL_RESULT_SUCCESS != result) {
    294         LOGE("SL_IID_RECORD interface get failed: %d", result);
    295         goto failed;
    296     }
    297 
    298     /* get the buffer queue interface */
    299     result = (*recorderObject)->GetInterface(recorderObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &recorderBufferQueue);
    300     if (SL_RESULT_SUCCESS != result) {
    301         LOGE("SL_IID_BUFFERQUEUE interface get failed: %d", result);
    302         goto failed;
    303     }
    304 
    305     /* register callback on the buffer queue */
    306     /* context is '(SDL_PrivateAudioData *)this->hidden' */
    307     result = (*recorderBufferQueue)->RegisterCallback(recorderBufferQueue, bqRecorderCallback, this->hidden);
    308     if (SL_RESULT_SUCCESS != result) {
    309         LOGE("RegisterCallback failed: %d", result);
    310         goto failed;
    311     }
    312 
    313     /* Create the audio buffer semaphore */
    314     audiodata->playsem = SDL_CreateSemaphore(0);
    315     if (!audiodata->playsem) {
    316         LOGE("cannot create Semaphore!");
    317         goto failed;
    318     }
    319 
    320     /* Create the sound buffers */
    321     audiodata->mixbuff = (Uint8 *) SDL_malloc(NUM_BUFFERS * this->spec.size);
    322     if (audiodata->mixbuff == NULL) {
    323         LOGE("mixbuffer allocate - out of memory");
    324         goto failed;
    325     }
    326 
    327     for (i = 0; i < NUM_BUFFERS; i++) {
    328         audiodata->pmixbuff[i] = audiodata->mixbuff + i * this->spec.size;
    329     }
    330 
    331     /* in case already recording, stop recording and clear buffer queue */
    332     result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_STOPPED);
    333     if (SL_RESULT_SUCCESS != result) {
    334         LOGE("Record set state failed: %d", result);
    335         goto failed;
    336     }
    337 
    338     /* enqueue empty buffers to be filled by the recorder */
    339     for (i = 0; i < NUM_BUFFERS; i++) {
    340         result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, audiodata->pmixbuff[i], this->spec.size);
    341         if (SL_RESULT_SUCCESS != result) {
    342             LOGE("Record enqueue buffers failed: %d", result);
    343             goto failed;
    344         }
    345     }
    346 
    347     /* start recording */
    348     result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_RECORDING);
    349     if (SL_RESULT_SUCCESS != result) {
    350         LOGE("Record set state failed: %d", result);
    351         goto failed;
    352     }
    353 
    354     return 0;
    355 
    356 failed:
    357 
    358     openslES_DestroyPCMRecorder(this);
    359 
    360     return SDL_SetError("Open device failed!");
    361 }
    362 
    363 /* this callback handler is called every time a buffer finishes playing */
    364 static void
    365 bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
    366 {
    367     struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) context;
    368 
    369     LOGV("SLES: Playback Callback");
    370     SDL_SemPost(audiodata->playsem);
    371 }
    372 
    373 static void
    374 openslES_DestroyPCMPlayer(_THIS)
    375 {
    376     struct SDL_PrivateAudioData *audiodata = this->hidden;
    377     SLresult result;
    378 
    379     /* set the player's state to 'stopped' */
    380     if (bqPlayerPlay != NULL) {
    381         result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_STOPPED);
    382         if (SL_RESULT_SUCCESS != result) {
    383             LOGE("SetPlayState stopped failed: %d", result);
    384         }
    385     }
    386 
    387     /* destroy buffer queue audio player object, and invalidate all associated interfaces */
    388     if (bqPlayerObject != NULL) {
    389 
    390         (*bqPlayerObject)->Destroy(bqPlayerObject);
    391 
    392         bqPlayerObject = NULL;
    393         bqPlayerPlay = NULL;
    394         bqPlayerBufferQueue = NULL;
    395     }
    396 
    397     if (audiodata->playsem) {
    398         SDL_DestroySemaphore(audiodata->playsem);
    399         audiodata->playsem = NULL;
    400     }
    401 
    402     if (audiodata->mixbuff) {
    403         SDL_free(audiodata->mixbuff);
    404     }
    405 }
    406 
    407 static int
    408 openslES_CreatePCMPlayer(_THIS)
    409 {
    410     struct SDL_PrivateAudioData *audiodata = this->hidden;
    411     SLDataFormat_PCM format_pcm;
    412     SLresult result;
    413     int i;
    414 
    415     /* If we want to add floating point audio support (requires API level 21)
    416        it can be done as described here:
    417         https://developer.android.com/ndk/guides/audio/opensl/android-extensions.html#floating-point
    418     */
    419 #if 1
    420     /* Just go with signed 16-bit audio as it's the most compatible */
    421     this->spec.format = AUDIO_S16SYS;
    422 #else
    423     SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
    424     while (test_format != 0) {
    425         if (SDL_AUDIO_ISSIGNED(test_format) && SDL_AUDIO_ISINT(test_format)) {
    426             break;
    427         }
    428         test_format = SDL_NextAudioFormat();
    429     }
    430 
    431     if (test_format == 0) {
    432         /* Didn't find a compatible format : */
    433         LOGI( "No compatible audio format, using signed 16-bit audio" );
    434         test_format = AUDIO_S16SYS;
    435     }
    436     this->spec.format = test_format;
    437 #endif
    438 
    439     /* Update the fragment size as size in bytes */
    440     SDL_CalculateAudioSpec(&this->spec);
    441 
    442     LOGI("Try to open %u hz %u bit chan %u %s samples %u",
    443           this->spec.freq, SDL_AUDIO_BITSIZE(this->spec.format),
    444           this->spec.channels, (this->spec.format & 0x1000) ? "BE" : "LE", this->spec.samples);
    445 
    446     /* configure audio source */
    447     SLDataLocator_AndroidSimpleBufferQueue loc_bufq = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, NUM_BUFFERS };
    448 
    449     format_pcm.formatType    = SL_DATAFORMAT_PCM;
    450     format_pcm.numChannels   = this->spec.channels;
    451     format_pcm.samplesPerSec = this->spec.freq * 1000;  /* / kilo Hz to milli Hz */
    452     format_pcm.bitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
    453     format_pcm.containerSize = SDL_AUDIO_BITSIZE(this->spec.format);
    454 
    455     if (SDL_AUDIO_ISBIGENDIAN(this->spec.format)) {
    456         format_pcm.endianness = SL_BYTEORDER_BIGENDIAN;
    457     } else {
    458         format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
    459     }
    460 
    461     switch (this->spec.channels)
    462     {
    463     case 1:
    464         format_pcm.channelMask = SL_SPEAKER_FRONT_LEFT;
    465         break;
    466     case 2:
    467         format_pcm.channelMask = SL_ANDROID_SPEAKER_STEREO;
    468         break;
    469     case 3:
    470         format_pcm.channelMask = SL_ANDROID_SPEAKER_STEREO | SL_SPEAKER_FRONT_CENTER;
    471         break;
    472     case 4:
    473         format_pcm.channelMask = SL_ANDROID_SPEAKER_QUAD;
    474         break;
    475     case 5:
    476         format_pcm.channelMask = SL_ANDROID_SPEAKER_QUAD | SL_SPEAKER_FRONT_CENTER;
    477         break;
    478     case 6:
    479         format_pcm.channelMask = SL_ANDROID_SPEAKER_5DOT1;
    480         break;
    481     case 7:
    482         format_pcm.channelMask = SL_ANDROID_SPEAKER_5DOT1 | SL_SPEAKER_BACK_CENTER;
    483         break;
    484     case 8:
    485         format_pcm.channelMask = SL_ANDROID_SPEAKER_7DOT1;
    486         break;
    487     default:
    488         /* Unknown number of channels, fall back to stereo */
    489         this->spec.channels = 2;
    490         format_pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
    491         break;
    492     }
    493 
    494     SLDataSource audioSrc = { &loc_bufq, &format_pcm };
    495 
    496     /* configure audio sink */
    497     SLDataLocator_OutputMix loc_outmix = { SL_DATALOCATOR_OUTPUTMIX, outputMixObject };
    498     SLDataSink audioSnk = { &loc_outmix, NULL };
    499 
    500     /* create audio player */
    501     const SLInterfaceID ids[2] = {
    502         SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
    503         SL_IID_VOLUME
    504     };
    505 
    506     const SLboolean req[2] = {
    507         SL_BOOLEAN_TRUE,
    508         SL_BOOLEAN_FALSE,
    509     };
    510 
    511     result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk, 2, ids, req);
    512     if (SL_RESULT_SUCCESS != result) {
    513         LOGE("CreateAudioPlayer failed: %d", result);
    514         goto failed;
    515     }
    516 
    517     /* realize the player */
    518     result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
    519     if (SL_RESULT_SUCCESS != result) {
    520         LOGE("RealizeAudioPlayer failed: %d", result);
    521         goto failed;
    522     }
    523 
    524     /* get the play interface */
    525     result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);
    526     if (SL_RESULT_SUCCESS != result) {
    527         LOGE("SL_IID_PLAY interface get failed: %d", result);
    528         goto failed;
    529     }
    530 
    531     /* get the buffer queue interface */
    532     result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bqPlayerBufferQueue);
    533     if (SL_RESULT_SUCCESS != result) {
    534         LOGE("SL_IID_BUFFERQUEUE interface get failed: %d", result);
    535         goto failed;
    536     }
    537 
    538     /* register callback on the buffer queue */
    539     /* context is '(SDL_PrivateAudioData *)this->hidden' */
    540     result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, this->hidden);
    541     if (SL_RESULT_SUCCESS != result) {
    542         LOGE("RegisterCallback failed: %d", result);
    543         goto failed;
    544     }
    545 
    546 #if 0
    547     /* get the volume interface */
    548     result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume);
    549     if (SL_RESULT_SUCCESS != result) {
    550         LOGE("SL_IID_VOLUME interface get failed: %d", result);
    551         /* goto failed; */
    552     }
    553 #endif
    554 
    555     /* Create the audio buffer semaphore */
    556     audiodata->playsem = SDL_CreateSemaphore(NUM_BUFFERS - 1);
    557     if (!audiodata->playsem) {
    558         LOGE("cannot create Semaphore!");
    559         goto failed;
    560     }
    561 
    562     /* Create the sound buffers */
    563     audiodata->mixbuff = (Uint8 *) SDL_malloc(NUM_BUFFERS * this->spec.size);
    564     if (audiodata->mixbuff == NULL) {
    565         LOGE("mixbuffer allocate - out of memory");
    566         goto failed;
    567     }
    568 
    569     for (i = 0; i < NUM_BUFFERS; i++) {
    570         audiodata->pmixbuff[i] = audiodata->mixbuff + i * this->spec.size;
    571     }
    572 
    573     /* set the player's state to playing */
    574     result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
    575     if (SL_RESULT_SUCCESS != result) {
    576         LOGE("Play set state failed: %d", result);
    577         goto failed;
    578     }
    579 
    580     return 0;
    581 
    582 failed:
    583 
    584     openslES_DestroyPCMPlayer(this);
    585 
    586     return SDL_SetError("Open device failed!");
    587 }
    588 
    589 static int
    590 openslES_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
    591 {
    592     this->hidden = (struct SDL_PrivateAudioData *) SDL_calloc(1, (sizeof *this->hidden));
    593     if (this->hidden == NULL) {
    594         return SDL_OutOfMemory();
    595     }
    596 
    597     if (iscapture) {
    598         LOGI("openslES_OpenDevice() %s for capture", devname);
    599         return openslES_CreatePCMRecorder(this);
    600     } else {
    601         LOGI("openslES_OpenDevice() %s for playing", devname);
    602         return openslES_CreatePCMPlayer(this);
    603     }
    604 }
    605 
    606 static void
    607 openslES_WaitDevice(_THIS)
    608 {
    609     struct SDL_PrivateAudioData *audiodata = this->hidden;
    610 
    611     LOGV("openslES_WaitDevice()");
    612 
    613     /* Wait for an audio chunk to finish */
    614     SDL_SemWait(audiodata->playsem);
    615 }
    616 
    617 static void
    618 openslES_PlayDevice(_THIS)
    619 {
    620     struct SDL_PrivateAudioData *audiodata = this->hidden;
    621     SLresult result;
    622 
    623     LOGV("======openslES_PlayDevice()======");
    624 
    625     /* Queue it up */
    626     result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, audiodata->pmixbuff[audiodata->next_buffer], this->spec.size);
    627 
    628     audiodata->next_buffer++;
    629     if (audiodata->next_buffer >= NUM_BUFFERS) {
    630         audiodata->next_buffer = 0;
    631     }
    632 
    633     /* If Enqueue fails, callback won't be called.
    634      * Post the semphore, not to run out of buffer */
    635     if (SL_RESULT_SUCCESS != result) {
    636         SDL_SemPost(audiodata->playsem);
    637     }
    638 }
    639 
    640 /*/           n   playn sem */
    641 /* getbuf     0   -     1 */
    642 /* fill buff  0   -     1 */
    643 /* play       0 - 0     1 */
    644 /* wait       1   0     0 */
    645 /* getbuf     1   0     0 */
    646 /* fill buff  1   0     0 */
    647 /* play       0   0     0 */
    648 /* wait */
    649 /* */
    650 /* okay.. */
    651 
    652 static Uint8 *
    653 openslES_GetDeviceBuf(_THIS)
    654 {
    655     struct SDL_PrivateAudioData *audiodata = this->hidden;
    656 
    657     LOGV("openslES_GetDeviceBuf()");
    658     return audiodata->pmixbuff[audiodata->next_buffer];
    659 }
    660 
    661 static int
    662 openslES_CaptureFromDevice(_THIS, void *buffer, int buflen)
    663 {
    664     struct SDL_PrivateAudioData *audiodata = this->hidden;
    665     SLresult result;
    666 
    667     /* Wait for new recorded data */
    668     SDL_SemWait(audiodata->playsem);
    669 
    670     /* Copy it to the output buffer */
    671     SDL_assert(buflen == this->spec.size);
    672     SDL_memcpy(buffer, audiodata->pmixbuff[audiodata->next_buffer], this->spec.size);
    673 
    674     /* Re-enqueue the buffer */
    675     result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, audiodata->pmixbuff[audiodata->next_buffer], this->spec.size);
    676     if (SL_RESULT_SUCCESS != result) {
    677         LOGE("Record enqueue buffers failed: %d", result);
    678         return -1;
    679     }
    680 
    681     audiodata->next_buffer++;
    682     if (audiodata->next_buffer >= NUM_BUFFERS) {
    683         audiodata->next_buffer = 0;
    684     }
    685 
    686     return this->spec.size;
    687 }
    688 
    689 static void
    690 openslES_CloseDevice(_THIS)
    691 {
    692     /* struct SDL_PrivateAudioData *audiodata = this->hidden; */
    693 
    694     if (this->iscapture) {
    695         LOGI("openslES_CloseDevice() for capture");
    696         openslES_DestroyPCMRecorder(this);
    697     } else {
    698         LOGI("openslES_CloseDevice() for playing");
    699         openslES_DestroyPCMPlayer(this);
    700     }
    701 
    702     SDL_free(this->hidden);
    703 }
    704 
    705 static int
    706 openslES_Init(SDL_AudioDriverImpl * impl)
    707 {
    708     LOGI("openslES_Init() called");
    709 
    710     if (!openslES_CreateEngine()) {
    711         return 0;
    712     }
    713 
    714     LOGI("openslES_Init() - set pointers");
    715 
    716     /* Set the function pointers */
    717     /* impl->DetectDevices = openslES_DetectDevices; */
    718     impl->OpenDevice    = openslES_OpenDevice;
    719     impl->WaitDevice    = openslES_WaitDevice;
    720     impl->PlayDevice    = openslES_PlayDevice;
    721     impl->GetDeviceBuf  = openslES_GetDeviceBuf;
    722     impl->CaptureFromDevice = openslES_CaptureFromDevice;
    723     impl->CloseDevice   = openslES_CloseDevice;
    724     impl->Deinitialize  = openslES_DestroyEngine;
    725 
    726     /* and the capabilities */
    727     impl->HasCaptureSupport = 1;
    728     impl->OnlyHasDefaultOutputDevice = 1;
    729     impl->OnlyHasDefaultCaptureDevice = 1;
    730 
    731     LOGI("openslES_Init() - success");
    732 
    733     /* this audio target is available. */
    734     return 1;
    735 }
    736 
    737 AudioBootStrap openslES_bootstrap = {
    738     "openslES", "opensl ES audio driver", openslES_Init, 0
    739 };
    740 
    741 void openslES_ResumeDevices(void)
    742 {
    743     if (bqPlayerPlay != NULL) {
    744         /* set the player's state to 'playing' */
    745         SLresult result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
    746         if (SL_RESULT_SUCCESS != result) {
    747             LOGE("openslES_ResumeDevices failed: %d", result);
    748         }
    749     }
    750 }
    751 
    752 void openslES_PauseDevices(void)
    753 {
    754     if (bqPlayerPlay != NULL) {
    755         /* set the player's state to 'paused' */
    756         SLresult result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PAUSED);
    757         if (SL_RESULT_SUCCESS != result) {
    758             LOGE("openslES_PauseDevices failed: %d", result);
    759         }
    760     }
    761 }
    762 
    763 #endif /* SDL_AUDIO_DRIVER_OPENSLES */
    764 
    765 /* vi: set ts=4 sw=4 expandtab: */