src/audio/openslES/SDL_openslES.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 08 Jun 2019 10:21:38 -0700
changeset 12767 8b07df58da32
parent 12766 a85ea89b0561
child 13041 6ea2f4ed7014
permissions -rw-r--r--
OpenSL ES audio cleanup and added a note with low latency audio discussion
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2019 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 "SDL_openslES.h"
    32 
    33 /* for native audio */
    34 #include <SLES/OpenSLES.h>
    35 #include <SLES/OpenSLES_Android.h>
    36 
    37 #include <android/log.h>
    38 
    39 #define LOG_TAG "SDL_openslES"
    40 
    41 #if 0
    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 /* engine interfaces */
    53 static SLObjectItf engineObject = NULL;
    54 static SLEngineItf engineEngine = NULL;
    55 
    56 /* output mix interfaces */
    57 static SLObjectItf outputMixObject = NULL;
    58 // static SLEnvironmentalReverbItf outputMixEnvironmentalReverb = NULL;
    59 
    60 /* aux effect on the output mix, used by the buffer queue player */
    61 /* static const SLEnvironmentalReverbSettings reverbSettings = SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR; */
    62 
    63 /* buffer queue player interfaces */
    64 static SLObjectItf                   bqPlayerObject      = NULL;
    65 static SLPlayItf                     bqPlayerPlay        = NULL;
    66 static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue = NULL;
    67 #if 0
    68 static SLEffectSendItf               bqPlayerEffectSend  = NULL;
    69 static SLMuteSoloItf                 bqPlayerMuteSolo    = NULL;
    70 static SLVolumeItf                   bqPlayerVolume      = NULL;
    71 #endif
    72 
    73 #if 0
    74 /* recorder interfaces TODO */
    75 static SLObjectItf                   recorderObject = NULL;
    76 static SLRecordItf                   recorderRecord;
    77 static SLAndroidSimpleBufferQueueItf recorderBufferQueue;
    78 #endif
    79 
    80 /* pointer and size of the next player buffer to enqueue, and number of remaining buffers */
    81 #if 0
    82 static short      *nextBuffer;
    83 static unsigned    nextSize;
    84 static int         nextCount;
    85 #endif
    86 
    87 // static SDL_AudioDevice* audioDevice = NULL;
    88 
    89 #if 0
    90 static const char *sldevaudiorecorderstr = "SLES Audio Recorder";
    91 static const char *sldevaudioplayerstr   = "SLES Audio Player";
    92 
    93 #define  SLES_DEV_AUDIO_RECORDER  sldevaudiorecorderstr
    94 #define  SLES_DEV_AUDIO_PLAYER  sldevaudioplayerstr
    95 static void openslES_DetectDevices( int iscapture )
    96 {
    97   LOGI( "openSLES_DetectDevices()" );
    98     if ( iscapture )
    99             addfn( SLES_DEV_AUDIO_RECORDER );
   100   else
   101             addfn( SLES_DEV_AUDIO_PLAYER );
   102   return;
   103 }
   104 #endif
   105 
   106 static void openslES_DestroyEngine();
   107 
   108 static int
   109 openslES_CreateEngine()
   110 {
   111     SLresult result;
   112 
   113     LOGI("openSLES_CreateEngine()");
   114 
   115     /* create engine */
   116     result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
   117     if (SL_RESULT_SUCCESS != result) {
   118         LOGE("slCreateEngine failed");
   119         goto error;
   120     }
   121 
   122     LOGI("slCreateEngine OK");
   123 
   124     /* realize the engine */
   125     result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
   126     if (SL_RESULT_SUCCESS != result) {
   127         LOGE("RealizeEngine failed");
   128         goto error;
   129     }
   130 
   131     LOGI("RealizeEngine OK");
   132 
   133     /* get the engine interface, which is needed in order to create other objects */
   134     result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
   135     if (SL_RESULT_SUCCESS != result) {
   136         LOGE("EngineGetInterface failed");
   137         goto error;
   138     }
   139 
   140     LOGI("EngineGetInterface OK");
   141 
   142     /* create output mix, with environmental reverb specified as a non-required interface */
   143     /* const SLInterfaceID ids[1] = { SL_IID_ENVIRONMENTALREVERB }; */
   144     /* const SLboolean req[1] = { SL_BOOLEAN_FALSE }; */
   145 
   146     const SLInterfaceID ids[1] = { SL_IID_VOLUME };
   147     const SLboolean req[1] = { SL_BOOLEAN_FALSE };
   148     result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, ids, req);
   149 
   150     if (SL_RESULT_SUCCESS != result) {
   151         LOGE("CreateOutputMix failed");
   152         goto error;
   153     }
   154     LOGI("CreateOutputMix OK");
   155 
   156     /* realize the output mix */
   157     result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
   158     if (SL_RESULT_SUCCESS != result) {
   159         LOGE("RealizeOutputMix failed");
   160         goto error;
   161     }
   162     return 1;
   163 
   164 error:
   165     openslES_DestroyEngine();
   166     return 0;
   167 }
   168 
   169 static void openslES_DestroyPCMPlayer(_THIS);
   170 static void openslES_DestroyPCMRecorder(_THIS);
   171 
   172 static void openslES_DestroyEngine()
   173 {
   174     LOGI("openslES_DestroyEngine()");
   175 
   176 //        openslES_DestroyPCMPlayer(this);
   177 //    openslES_DestroyPCMRecorder(this);
   178 
   179     /* destroy output mix object, and invalidate all associated interfaces */
   180     if (outputMixObject != NULL) {
   181         (*outputMixObject)->Destroy(outputMixObject);
   182         outputMixObject = NULL;
   183         /* outputMixEnvironmentalReverb = NULL; */
   184     }
   185 
   186     /* destroy engine object, and invalidate all associated interfaces */
   187     if (engineObject != NULL) {
   188         (*engineObject)->Destroy(engineObject);
   189         engineObject = NULL;
   190         engineEngine = NULL;
   191     }
   192 
   193     return;
   194 }
   195 
   196 /* this callback handler is called every time a buffer finishes playing */
   197 static void
   198 bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
   199 {
   200     struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) context;
   201     LOGV("SLES: Playback Callmeback");
   202     SDL_SemPost(audiodata->playsem);
   203     return;
   204 }
   205 
   206 static int
   207 openslES_CreatePCMRecorder(_THIS)
   208 {
   209 /*    struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) this->hidden; */
   210 
   211     LOGE("openslES_CreatePCMRecorder not implimented yet!");
   212     return SDL_SetError("openslES_CreatePCMRecorder not implimented yet!");
   213 }
   214 
   215 static void
   216 openslES_DestroyPCMRecorder(_THIS)
   217 {
   218 /*    struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) this->hidden; */
   219 
   220     return;
   221 }
   222 
   223 static int
   224 openslES_CreatePCMPlayer(_THIS)
   225 {
   226     struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) this->hidden;
   227     SLDataFormat_PCM format_pcm;
   228     SLresult result;
   229     int i;
   230 
   231     /* If we want to add floating point audio support (requires API level 21)
   232        it can be done as described here:
   233         https://developer.android.com/ndk/guides/audio/opensl/android-extensions.html#floating-point
   234     */
   235 #if 1
   236     /* Just go with signed 16-bit audio as it's the most compatible */
   237     this->spec.format = AUDIO_S16SYS;
   238 #else
   239     SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
   240     while (test_format != 0) {
   241         if (SDL_AUDIO_ISSIGNED(test_format) && SDL_AUDIO_ISINT(test_format)) {
   242             break;
   243         }
   244         test_format = SDL_NextAudioFormat();
   245     }
   246 
   247     if (test_format == 0) {
   248         /* Didn't find a compatible format : */
   249         LOGI( "No compatible audio format, using signed 16-bit audio" );
   250         test_format = AUDIO_S16SYS;
   251     }
   252     this->spec.format = test_format;
   253 #endif
   254 
   255     /* Update the fragment size as size in bytes */
   256     SDL_CalculateAudioSpec(&this->spec);
   257 
   258     LOGI("Try to open %u hz %u bit chan %u %s samples %u",
   259           this->spec.freq, SDL_AUDIO_BITSIZE(this->spec.format),
   260           this->spec.channels, (this->spec.format & 0x1000) ? "BE" : "LE", this->spec.samples);
   261 
   262     /* configure audio source */
   263     SLDataLocator_AndroidSimpleBufferQueue loc_bufq = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, NUM_BUFFERS };
   264 
   265     format_pcm.formatType    = SL_DATAFORMAT_PCM;
   266     format_pcm.numChannels   = this->spec.channels;
   267     format_pcm.samplesPerSec = this->spec.freq * 1000;  /* / kilo Hz to milli Hz */
   268     format_pcm.bitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
   269     format_pcm.containerSize = SDL_AUDIO_BITSIZE(this->spec.format);
   270 
   271     if (SDL_AUDIO_ISBIGENDIAN(this->spec.format)) {
   272         format_pcm.endianness = SL_BYTEORDER_BIGENDIAN;
   273     } else {
   274         format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
   275     }
   276 
   277 /*
   278 #define SL_SPEAKER_FRONT_LEFT            ((SLuint32) 0x00000001)
   279 #define SL_SPEAKER_FRONT_RIGHT           ((SLuint32) 0x00000002)
   280 #define SL_SPEAKER_FRONT_CENTER          ((SLuint32) 0x00000004)
   281 #define SL_SPEAKER_LOW_FREQUENCY         ((SLuint32) 0x00000008)
   282 #define SL_SPEAKER_BACK_LEFT             ((SLuint32) 0x00000010)
   283 #define SL_SPEAKER_BACK_RIGHT            ((SLuint32) 0x00000020)
   284 #define SL_SPEAKER_FRONT_LEFT_OF_CENTER  ((SLuint32) 0x00000040)
   285 #define SL_SPEAKER_FRONT_RIGHT_OF_CENTER ((SLuint32) 0x00000080)
   286 #define SL_SPEAKER_BACK_CENTER           ((SLuint32) 0x00000100)
   287 #define SL_SPEAKER_SIDE_LEFT             ((SLuint32) 0x00000200)
   288 #define SL_SPEAKER_SIDE_RIGHT            ((SLuint32) 0x00000400)
   289 #define SL_SPEAKER_TOP_CENTER            ((SLuint32) 0x00000800)
   290 #define SL_SPEAKER_TOP_FRONT_LEFT        ((SLuint32) 0x00001000)
   291 #define SL_SPEAKER_TOP_FRONT_CENTER      ((SLuint32) 0x00002000)
   292 #define SL_SPEAKER_TOP_FRONT_RIGHT       ((SLuint32) 0x00004000)
   293 #define SL_SPEAKER_TOP_BACK_LEFT         ((SLuint32) 0x00008000)
   294 #define SL_SPEAKER_TOP_BACK_CENTER       ((SLuint32) 0x00010000)
   295 #define SL_SPEAKER_TOP_BACK_RIGHT        ((SLuint32) 0x00020000)
   296 */
   297 #define SL_ANDROID_SPEAKER_STEREO (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT)
   298 #define SL_ANDROID_SPEAKER_QUAD (SL_ANDROID_SPEAKER_STEREO | SL_SPEAKER_BACK_LEFT | SL_SPEAKER_BACK_RIGHT)
   299 #define SL_ANDROID_SPEAKER_5DOT1 (SL_ANDROID_SPEAKER_QUAD | SL_SPEAKER_FRONT_CENTER  | SL_SPEAKER_LOW_FREQUENCY)
   300 #define SL_ANDROID_SPEAKER_7DOT1 (SL_ANDROID_SPEAKER_5DOT1 | SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT)
   301 
   302     switch (this->spec.channels)
   303     {
   304     case 1:
   305         format_pcm.channelMask = SL_SPEAKER_FRONT_LEFT;
   306         break;
   307     case 2:
   308         format_pcm.channelMask = SL_ANDROID_SPEAKER_STEREO;
   309         break;
   310     case 3:
   311         format_pcm.channelMask = SL_ANDROID_SPEAKER_STEREO | SL_SPEAKER_FRONT_CENTER;
   312         break;
   313     case 4:
   314         format_pcm.channelMask = SL_ANDROID_SPEAKER_QUAD;
   315         break;
   316     case 5:
   317         format_pcm.channelMask = SL_ANDROID_SPEAKER_QUAD | SL_SPEAKER_FRONT_CENTER;
   318         break;
   319     case 6:
   320         format_pcm.channelMask = SL_ANDROID_SPEAKER_5DOT1;
   321         break;
   322     case 7:
   323         format_pcm.channelMask = SL_ANDROID_SPEAKER_5DOT1 | SL_SPEAKER_BACK_CENTER;
   324         break;
   325     case 8:
   326         format_pcm.channelMask = SL_ANDROID_SPEAKER_7DOT1;
   327         break;
   328     default:
   329         /* Unknown number of channels, fall back to stereo */
   330         this->spec.channels = 2;
   331         format_pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
   332         break;
   333     }
   334 
   335     SLDataSource audioSrc = { &loc_bufq, &format_pcm };
   336 
   337     /* configure audio sink */
   338     SLDataLocator_OutputMix loc_outmix = { SL_DATALOCATOR_OUTPUTMIX, outputMixObject };
   339     SLDataSink audioSnk = { &loc_outmix, NULL };
   340 
   341     /* create audio player */
   342     const SLInterfaceID ids[2] = {
   343         SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
   344         SL_IID_VOLUME
   345     };
   346 
   347     const SLboolean req[2] = {
   348         SL_BOOLEAN_TRUE,
   349         SL_BOOLEAN_FALSE,
   350     };
   351 
   352     result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk, 2, ids, req);
   353     if (SL_RESULT_SUCCESS != result) {
   354         LOGE("CreateAudioPlayer failed");
   355         goto failed;
   356     }
   357 
   358     /* realize the player */
   359     result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
   360     if (SL_RESULT_SUCCESS != result) {
   361         LOGE("RealizeAudioPlayer failed");
   362         goto failed;
   363     }
   364 
   365     /* get the play interface */
   366     result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);
   367     if (SL_RESULT_SUCCESS != result) {
   368         LOGE("SL_IID_PLAY interface get failed");
   369         goto failed;
   370     }
   371 
   372     /* get the buffer queue interface */
   373     result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bqPlayerBufferQueue);
   374     if (SL_RESULT_SUCCESS != result) {
   375         LOGE("SL_IID_BUFFERQUEUE interface get failed");
   376         goto failed;
   377     }
   378 
   379     /* register callback on the buffer queue */
   380     /* context is '(SDL_PrivateAudioData *)this->hidden' */
   381     result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, this->hidden);
   382     if (SL_RESULT_SUCCESS != result) {
   383         LOGE("RegisterCallback failed");
   384         goto failed;
   385     }
   386 
   387 #if 0
   388     /* get the effect send interface */
   389     result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_EFFECTSEND, &bqPlayerEffectSend);
   390     if (SL_RESULT_SUCCESS != result)
   391     {
   392 
   393         LOGE("SL_IID_EFFECTSEND interface get failed");
   394         goto failed;
   395     }
   396 #endif
   397 
   398 #if 0   /* mute/solo is not supported for sources that are known to be mono, as this is */
   399     /* get the mute/solo interface */
   400     result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_MUTESOLO, &bqPlayerMuteSolo);
   401     assert(SL_RESULT_SUCCESS == result);
   402     (void) result;
   403 #endif
   404 
   405 #if 0
   406     /* get the volume interface */
   407     result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume);
   408     if (SL_RESULT_SUCCESS != result) {
   409         LOGE("SL_IID_VOLUME interface get failed");
   410         /* goto failed; */
   411     }
   412 #endif
   413 
   414     /* Create the audio buffer semaphore */
   415     audiodata->playsem = SDL_CreateSemaphore(NUM_BUFFERS - 1);
   416     if (!audiodata->playsem) {
   417         LOGE("cannot create Semaphore!");
   418         goto failed;
   419     }
   420 
   421     /* Create the sound buffers */
   422     audiodata->mixbuff = (Uint8 *) SDL_malloc(NUM_BUFFERS * this->spec.size);
   423     if (audiodata->mixbuff == NULL) {
   424         LOGE("mixbuffer allocate - out of memory");
   425         goto failed;
   426     }
   427 
   428     for (i = 0; i < NUM_BUFFERS; i++) {
   429         audiodata->pmixbuff[i] = audiodata->mixbuff + i * this->spec.size;
   430     }
   431 
   432     /* set the player's state to playing */
   433     result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
   434     if (SL_RESULT_SUCCESS != result) {
   435         LOGE("Play set state failed");
   436         goto failed;
   437     }
   438 
   439     return 0;
   440 
   441 failed:
   442 
   443     openslES_DestroyPCMPlayer(this);
   444 
   445     return SDL_SetError("Open device failed!");
   446 }
   447 
   448 static void
   449 openslES_DestroyPCMPlayer(_THIS)
   450 {
   451     struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) this->hidden;
   452     SLresult result;
   453 
   454     /* set the player's state to 'stopped' */
   455     if (bqPlayerPlay != NULL) {
   456         result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_STOPPED);
   457         if (SL_RESULT_SUCCESS != result) {
   458             SDL_SetError("Stopped set state failed");
   459         }
   460     }
   461 
   462     /* destroy buffer queue audio player object, and invalidate all associated interfaces */
   463     if (bqPlayerObject != NULL) {
   464 
   465         (*bqPlayerObject)->Destroy(bqPlayerObject);
   466 
   467         bqPlayerObject = NULL;
   468         bqPlayerPlay = NULL;
   469         bqPlayerBufferQueue = NULL;
   470 #if 0
   471         bqPlayerEffectSend = NULL;
   472         bqPlayerMuteSolo = NULL;
   473         bqPlayerVolume = NULL;
   474 #endif
   475     }
   476 
   477     if (audiodata->playsem) {
   478         SDL_DestroySemaphore(audiodata->playsem);
   479         audiodata->playsem = NULL;
   480     }
   481 
   482     if (audiodata->mixbuff) {
   483         SDL_free(audiodata->mixbuff);
   484     }
   485 
   486     return;
   487 }
   488 
   489 static int
   490 openslES_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
   491 {
   492     this->hidden = (struct SDL_PrivateAudioData *) SDL_calloc(1, (sizeof *this->hidden));
   493     if (this->hidden == NULL) {
   494         return SDL_OutOfMemory();
   495     }
   496 
   497     if (iscapture) {
   498         LOGI("openslES_OpenDevice( ) %s for capture", devname);
   499         return openslES_CreatePCMRecorder(this);
   500     } else {
   501         LOGI("openslES_OpenDevice( ) %s for playing", devname);
   502         return openslES_CreatePCMPlayer(this);
   503     }
   504 }
   505 
   506 static void
   507 openslES_CloseDevice(_THIS)
   508 {
   509     /* struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) this->hidden; */
   510 
   511     if (this->iscapture) {
   512         LOGI("openslES_CloseDevice( ) for capture");
   513         openslES_DestroyPCMRecorder(this);
   514     } else {
   515         LOGI("openslES_CloseDevice( ) for playing");
   516         openslES_DestroyPCMPlayer(this);
   517     }
   518 
   519     SDL_free(this->hidden);
   520 
   521     return;
   522 }
   523 
   524 static void
   525 openslES_WaitDevice(_THIS)
   526 {
   527     struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) this->hidden;
   528 
   529     LOGV("openslES_WaitDevice( )");
   530 
   531     /* Wait for an audio chunk to finish */
   532     /* WaitForSingleObject(this->hidden->audio_sem, INFINITE); */
   533     SDL_SemWait(audiodata->playsem);
   534 
   535     return;
   536 }
   537 
   538 /*/           n   playn sem */
   539 /* getbuf     0   -     1 */
   540 /* fill buff  0   -     1 */
   541 /* play       0 - 0     1 */
   542 /* wait       1   0     0 */
   543 /* getbuf     1   0     0 */
   544 /* fill buff  1   0     0 */
   545 /* play       0   0     0 */
   546 /* wait */
   547 /* */
   548 /* okay.. */
   549 
   550 static Uint8 *
   551 openslES_GetDeviceBuf(_THIS)
   552 {
   553     struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) this->hidden;
   554 
   555     LOGV("openslES_GetDeviceBuf( )");
   556     return audiodata->pmixbuff[audiodata->next_buffer];
   557 }
   558 
   559 static void
   560 openslES_PlayDevice(_THIS)
   561 {
   562     struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) this->hidden;
   563     SLresult result;
   564 
   565     LOGV("======openslES_PlayDevice( )======");
   566 
   567     /* Queue it up */
   568     result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, audiodata->pmixbuff[audiodata->next_buffer], this->spec.size);
   569 
   570     audiodata->next_buffer++;
   571     if (audiodata->next_buffer >= NUM_BUFFERS) {
   572         audiodata->next_buffer = 0;
   573     }
   574 
   575     /* If Enqueue fails, callback won't be called.
   576      * Post the semphore, not to run out of buffer */
   577     if (SL_RESULT_SUCCESS != result) {
   578         SDL_SemPost(audiodata->playsem);
   579     }
   580 
   581     return;
   582 }
   583 
   584 static int
   585 openslES_Init(SDL_AudioDriverImpl * impl)
   586 {
   587     LOGI("openslES_Init() called");
   588 
   589     if (!openslES_CreateEngine()) {
   590         return 0;
   591     }
   592 
   593     LOGI("openslES_Init() - set pointers");
   594 
   595     /* Set the function pointers */
   596     /* impl->DetectDevices = openslES_DetectDevices; */
   597     impl->OpenDevice    = openslES_OpenDevice;
   598     impl->CloseDevice   = openslES_CloseDevice;
   599     impl->PlayDevice    = openslES_PlayDevice;
   600     impl->GetDeviceBuf  = openslES_GetDeviceBuf;
   601     impl->Deinitialize  = openslES_DestroyEngine;
   602     impl->WaitDevice    = openslES_WaitDevice;
   603 
   604     /* and the capabilities */
   605     impl->HasCaptureSupport             = 0;        /* TODO */
   606     impl->OnlyHasDefaultOutputDevice    = 1;
   607     /* impl->OnlyHasDefaultInputDevice  = 1; */
   608 
   609     LOGI("openslES_Init() - succes");
   610 
   611     /* this audio target is available. */
   612     return 1;
   613 }
   614 
   615 AudioBootStrap openslES_bootstrap = {
   616     "openslES", "opensl ES audio driver", openslES_Init, 0
   617 };
   618 
   619 void openslES_ResumeDevices()
   620 {
   621     if (bqPlayerPlay != NULL) {
   622         /* set the player's state to 'playing' */
   623         SLresult result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
   624         if (SL_RESULT_SUCCESS != result) {
   625             SDL_SetError("openslES_ResumeDevices failed");
   626         }
   627     }
   628 }
   629 
   630 void openslES_PauseDevices()
   631 {
   632     if (bqPlayerPlay != NULL) {
   633         /* set the player's state to 'paused' */
   634         SLresult result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PAUSED);
   635         if (SL_RESULT_SUCCESS != result) {
   636             SDL_SetError("openslES_PauseDevices failed");
   637         }
   638     }
   639 }
   640 
   641 #endif /* SDL_AUDIO_DRIVER_OPENSLES */
   642 
   643 /* vi: set ts=4 sw=4 expandtab: */