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