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