Implemented OpenSL-ES audio recording on Android
authorSam Lantinga <slouken@libsdl.org>
Tue, 11 Feb 2020 16:14:02 -0800
changeset 135094439a13420fb
parent 13508 a6d3d330dedc
child 13510 8a356f708f40
Implemented OpenSL-ES audio recording on Android
android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
src/audio/SDL_audio.c
src/audio/openslES/SDL_openslES.c
src/audio/openslES/SDL_openslES.h
src/core/android/SDL_android.h
     1.1 --- a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java	Tue Feb 11 10:35:14 2020 -0800
     1.2 +++ b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java	Tue Feb 11 16:14:02 2020 -0800
     1.3 @@ -783,6 +783,7 @@
     1.4      public static native void nativeSetenv(String name, String value);
     1.5      public static native void onNativeOrientationChanged(int orientation);
     1.6      public static native void nativeAddTouch(int touchId, String name);
     1.7 +    public static native void nativePermissionResult(int requestCode, boolean result);
     1.8  
     1.9      /**
    1.10       * This method is called by SDL using JNI.
    1.11 @@ -1600,6 +1601,42 @@
    1.12          }
    1.13          return true;
    1.14      }
    1.15 +
    1.16 +    /**
    1.17 +     * This method is called by SDL using JNI.
    1.18 +     */
    1.19 +    public static void requestPermission(String permission, int requestCode) {
    1.20 +        if (mSingleton != null) {
    1.21 +            mSingleton.checkPermission(permission, requestCode);
    1.22 +        } else {
    1.23 +            nativePermissionResult(requestCode, false);
    1.24 +        }
    1.25 +    }
    1.26 +
    1.27 +    /**
    1.28 +     * This can be overridden
    1.29 +     */
    1.30 +    public void checkPermission(String permission, int requestCode) {
    1.31 +        if (Build.VERSION.SDK_INT < 23) {
    1.32 +            nativePermissionResult(requestCode, true);
    1.33 +            return;
    1.34 +        }
    1.35 +
    1.36 +        if (this.checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
    1.37 +            this.requestPermissions(new String[]{permission}, requestCode);
    1.38 +        } else {
    1.39 +            nativePermissionResult(requestCode, true);
    1.40 +        }
    1.41 +    }
    1.42 +
    1.43 +    @Override
    1.44 +    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    1.45 +        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
    1.46 +            nativePermissionResult(requestCode, true);
    1.47 +        } else {
    1.48 +            nativePermissionResult(requestCode, false);
    1.49 +        }
    1.50 +    }
    1.51  }
    1.52  
    1.53  /**
     2.1 --- a/src/audio/SDL_audio.c	Tue Feb 11 10:35:14 2020 -0800
     2.2 +++ b/src/audio/SDL_audio.c	Tue Feb 11 16:14:02 2020 -0800
     2.3 @@ -1076,7 +1076,7 @@
     2.4          return NULL;
     2.5      }
     2.6  
     2.7 -    if ((iscapture) && (!current_audio.impl.HasCaptureSupport)) {
     2.8 +    if (iscapture && !current_audio.impl.HasCaptureSupport) {
     2.9          SDL_SetError("No capture support");
    2.10          return NULL;
    2.11      }
    2.12 @@ -1230,7 +1230,7 @@
    2.13          return 0;
    2.14      }
    2.15  
    2.16 -    if ((iscapture) && (!current_audio.impl.HasCaptureSupport)) {
    2.17 +    if (iscapture && !current_audio.impl.HasCaptureSupport) {
    2.18          SDL_SetError("No capture support");
    2.19          return 0;
    2.20      }
     3.1 --- a/src/audio/openslES/SDL_openslES.c	Tue Feb 11 10:35:14 2020 -0800
     3.2 +++ b/src/audio/openslES/SDL_openslES.c	Tue Feb 11 16:14:02 2020 -0800
     3.3 @@ -26,8 +26,10 @@
     3.4     https://googlesamples.github.io/android-audio-high-performance/guides/opensl_es.html
     3.5  */
     3.6  
     3.7 +#include "SDL_assert.h"
     3.8  #include "SDL_audio.h"
     3.9  #include "../SDL_audio_c.h"
    3.10 +#include "../../core/android/SDL_android.h"
    3.11  #include "SDL_openslES.h"
    3.12  
    3.13  /* for native audio */
    3.14 @@ -48,42 +50,50 @@
    3.15  #define LOGV(...)
    3.16  #endif
    3.17  
    3.18 +/*
    3.19 +#define SL_SPEAKER_FRONT_LEFT            ((SLuint32) 0x00000001)
    3.20 +#define SL_SPEAKER_FRONT_RIGHT           ((SLuint32) 0x00000002)
    3.21 +#define SL_SPEAKER_FRONT_CENTER          ((SLuint32) 0x00000004)
    3.22 +#define SL_SPEAKER_LOW_FREQUENCY         ((SLuint32) 0x00000008)
    3.23 +#define SL_SPEAKER_BACK_LEFT             ((SLuint32) 0x00000010)
    3.24 +#define SL_SPEAKER_BACK_RIGHT            ((SLuint32) 0x00000020)
    3.25 +#define SL_SPEAKER_FRONT_LEFT_OF_CENTER  ((SLuint32) 0x00000040)
    3.26 +#define SL_SPEAKER_FRONT_RIGHT_OF_CENTER ((SLuint32) 0x00000080)
    3.27 +#define SL_SPEAKER_BACK_CENTER           ((SLuint32) 0x00000100)
    3.28 +#define SL_SPEAKER_SIDE_LEFT             ((SLuint32) 0x00000200)
    3.29 +#define SL_SPEAKER_SIDE_RIGHT            ((SLuint32) 0x00000400)
    3.30 +#define SL_SPEAKER_TOP_CENTER            ((SLuint32) 0x00000800)
    3.31 +#define SL_SPEAKER_TOP_FRONT_LEFT        ((SLuint32) 0x00001000)
    3.32 +#define SL_SPEAKER_TOP_FRONT_CENTER      ((SLuint32) 0x00002000)
    3.33 +#define SL_SPEAKER_TOP_FRONT_RIGHT       ((SLuint32) 0x00004000)
    3.34 +#define SL_SPEAKER_TOP_BACK_LEFT         ((SLuint32) 0x00008000)
    3.35 +#define SL_SPEAKER_TOP_BACK_CENTER       ((SLuint32) 0x00010000)
    3.36 +#define SL_SPEAKER_TOP_BACK_RIGHT        ((SLuint32) 0x00020000)
    3.37 +*/
    3.38 +#define SL_ANDROID_SPEAKER_STEREO (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT)
    3.39 +#define SL_ANDROID_SPEAKER_QUAD (SL_ANDROID_SPEAKER_STEREO | SL_SPEAKER_BACK_LEFT | SL_SPEAKER_BACK_RIGHT)
    3.40 +#define SL_ANDROID_SPEAKER_5DOT1 (SL_ANDROID_SPEAKER_QUAD | SL_SPEAKER_FRONT_CENTER  | SL_SPEAKER_LOW_FREQUENCY)
    3.41 +#define SL_ANDROID_SPEAKER_7DOT1 (SL_ANDROID_SPEAKER_5DOT1 | SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT)
    3.42 +
    3.43  /* engine interfaces */
    3.44 -static SLObjectItf engineObject = NULL;
    3.45 -static SLEngineItf engineEngine = NULL;
    3.46 +static SLObjectItf engineObject;
    3.47 +static SLEngineItf engineEngine;
    3.48  
    3.49  /* output mix interfaces */
    3.50 -static SLObjectItf outputMixObject = NULL;
    3.51 -// static SLEnvironmentalReverbItf outputMixEnvironmentalReverb = NULL;
    3.52 -
    3.53 -/* aux effect on the output mix, used by the buffer queue player */
    3.54 -/* static const SLEnvironmentalReverbSettings reverbSettings = SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR; */
    3.55 +static SLObjectItf outputMixObject;
    3.56  
    3.57  /* buffer queue player interfaces */
    3.58 -static SLObjectItf                   bqPlayerObject      = NULL;
    3.59 -static SLPlayItf                     bqPlayerPlay        = NULL;
    3.60 -static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue = NULL;
    3.61 +static SLObjectItf bqPlayerObject;
    3.62 +static SLPlayItf bqPlayerPlay;
    3.63 +static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue;
    3.64  #if 0
    3.65 -static SLEffectSendItf               bqPlayerEffectSend  = NULL;
    3.66 -static SLMuteSoloItf                 bqPlayerMuteSolo    = NULL;
    3.67 -static SLVolumeItf                   bqPlayerVolume      = NULL;
    3.68 +static SLVolumeItf bqPlayerVolume;
    3.69  #endif
    3.70  
    3.71 -#if 0
    3.72 -/* recorder interfaces TODO */
    3.73 -static SLObjectItf                   recorderObject = NULL;
    3.74 -static SLRecordItf                   recorderRecord;
    3.75 +/* recorder interfaces */
    3.76 +static SLObjectItf recorderObject;
    3.77 +static SLRecordItf recorderRecord;
    3.78  static SLAndroidSimpleBufferQueueItf recorderBufferQueue;
    3.79 -#endif
    3.80 -
    3.81 -/* pointer and size of the next player buffer to enqueue, and number of remaining buffers */
    3.82 -#if 0
    3.83 -static short      *nextBuffer;
    3.84 -static unsigned    nextSize;
    3.85 -static int         nextCount;
    3.86 -#endif
    3.87 -
    3.88 -// static SDL_AudioDevice* audioDevice = NULL;
    3.89  
    3.90  #if 0
    3.91  static const char *sldevaudiorecorderstr = "SLES Audio Recorder";
    3.92 @@ -93,19 +103,34 @@
    3.93  #define  SLES_DEV_AUDIO_PLAYER  sldevaudioplayerstr
    3.94  static void openslES_DetectDevices( int iscapture )
    3.95  {
    3.96 -  LOGI( "openSLES_DetectDevices()" );
    3.97 +    LOGI( "openSLES_DetectDevices()" );
    3.98      if ( iscapture )
    3.99              addfn( SLES_DEV_AUDIO_RECORDER );
   3.100 -  else
   3.101 +    else
   3.102              addfn( SLES_DEV_AUDIO_PLAYER );
   3.103 -  return;
   3.104  }
   3.105  #endif
   3.106  
   3.107 -static void openslES_DestroyEngine(void);
   3.108 +static void openslES_DestroyEngine(void)
   3.109 +{
   3.110 +    LOGI("openslES_DestroyEngine()");
   3.111 +
   3.112 +    /* destroy output mix object, and invalidate all associated interfaces */
   3.113 +    if (outputMixObject != NULL) {
   3.114 +        (*outputMixObject)->Destroy(outputMixObject);
   3.115 +        outputMixObject = NULL;
   3.116 +    }
   3.117 +
   3.118 +    /* destroy engine object, and invalidate all associated interfaces */
   3.119 +    if (engineObject != NULL) {
   3.120 +        (*engineObject)->Destroy(engineObject);
   3.121 +        engineObject = NULL;
   3.122 +        engineEngine = NULL;
   3.123 +    }
   3.124 +}
   3.125  
   3.126  static int
   3.127 -openslES_CreateEngine()
   3.128 +openslES_CreateEngine(void)
   3.129  {
   3.130      SLresult result;
   3.131  
   3.132 @@ -114,40 +139,33 @@
   3.133      /* create engine */
   3.134      result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
   3.135      if (SL_RESULT_SUCCESS != result) {
   3.136 -        LOGE("slCreateEngine failed");
   3.137 +        LOGE("slCreateEngine failed: %d", result);
   3.138          goto error;
   3.139      }
   3.140 -
   3.141      LOGI("slCreateEngine OK");
   3.142  
   3.143      /* realize the engine */
   3.144      result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
   3.145      if (SL_RESULT_SUCCESS != result) {
   3.146 -        LOGE("RealizeEngine failed");
   3.147 +        LOGE("RealizeEngine failed: %d", result);
   3.148          goto error;
   3.149      }
   3.150 -
   3.151      LOGI("RealizeEngine OK");
   3.152  
   3.153      /* get the engine interface, which is needed in order to create other objects */
   3.154      result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
   3.155      if (SL_RESULT_SUCCESS != result) {
   3.156 -        LOGE("EngineGetInterface failed");
   3.157 +        LOGE("EngineGetInterface failed: %d", result);
   3.158          goto error;
   3.159      }
   3.160 -
   3.161      LOGI("EngineGetInterface OK");
   3.162  
   3.163 -    /* create output mix, with environmental reverb specified as a non-required interface */
   3.164 -    /* const SLInterfaceID ids[1] = { SL_IID_ENVIRONMENTALREVERB }; */
   3.165 -    /* const SLboolean req[1] = { SL_BOOLEAN_FALSE }; */
   3.166 -
   3.167 +    /* create output mix */
   3.168      const SLInterfaceID ids[1] = { SL_IID_VOLUME };
   3.169      const SLboolean req[1] = { SL_BOOLEAN_FALSE };
   3.170      result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, ids, req);
   3.171 -
   3.172      if (SL_RESULT_SUCCESS != result) {
   3.173 -        LOGE("CreateOutputMix failed");
   3.174 +        LOGE("CreateOutputMix failed: %d", result);
   3.175          goto error;
   3.176      }
   3.177      LOGI("CreateOutputMix OK");
   3.178 @@ -155,7 +173,7 @@
   3.179      /* realize the output mix */
   3.180      result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
   3.181      if (SL_RESULT_SUCCESS != result) {
   3.182 -        LOGE("RealizeOutputMix failed");
   3.183 +        LOGE("RealizeOutputMix failed: %d", result);
   3.184          goto error;
   3.185      }
   3.186      return 1;
   3.187 @@ -165,31 +183,181 @@
   3.188      return 0;
   3.189  }
   3.190  
   3.191 -static void openslES_DestroyPCMPlayer(_THIS);
   3.192 -static void openslES_DestroyPCMRecorder(_THIS);
   3.193 +/* this callback handler is called every time a buffer finishes recording */
   3.194 +static void
   3.195 +bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
   3.196 +{
   3.197 +    struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) context;
   3.198  
   3.199 -static void openslES_DestroyEngine()
   3.200 +    LOGV("SLES: Recording Callback");
   3.201 +    SDL_SemPost(audiodata->playsem);
   3.202 +}
   3.203 +
   3.204 +static void
   3.205 +openslES_DestroyPCMRecorder(_THIS)
   3.206  {
   3.207 -    LOGI("openslES_DestroyEngine()");
   3.208 +    struct SDL_PrivateAudioData *audiodata = this->hidden;
   3.209 +    SLresult result;
   3.210  
   3.211 -//        openslES_DestroyPCMPlayer(this);
   3.212 -//    openslES_DestroyPCMRecorder(this);
   3.213 -
   3.214 -    /* destroy output mix object, and invalidate all associated interfaces */
   3.215 -    if (outputMixObject != NULL) {
   3.216 -        (*outputMixObject)->Destroy(outputMixObject);
   3.217 -        outputMixObject = NULL;
   3.218 -        /* outputMixEnvironmentalReverb = NULL; */
   3.219 +    /* stop recording */
   3.220 +    if (recorderRecord != NULL) {
   3.221 +        result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_STOPPED);
   3.222 +        if (SL_RESULT_SUCCESS != result) {
   3.223 +            LOGE("SetRecordState stopped: %d", result);
   3.224 +        }
   3.225      }
   3.226  
   3.227 -    /* destroy engine object, and invalidate all associated interfaces */
   3.228 -    if (engineObject != NULL) {
   3.229 -        (*engineObject)->Destroy(engineObject);
   3.230 -        engineObject = NULL;
   3.231 -        engineEngine = NULL;
   3.232 +    /* destroy audio recorder object, and invalidate all associated interfaces */
   3.233 +    if (recorderObject != NULL) {
   3.234 +        (*recorderObject)->Destroy(recorderObject);
   3.235 +        recorderObject = NULL;
   3.236 +        recorderRecord = NULL;
   3.237 +        recorderBufferQueue = NULL;
   3.238      }
   3.239  
   3.240 -    return;
   3.241 +    if (audiodata->playsem) {
   3.242 +        SDL_DestroySemaphore(audiodata->playsem);
   3.243 +        audiodata->playsem = NULL;
   3.244 +    }
   3.245 +
   3.246 +    if (audiodata->mixbuff) {
   3.247 +        SDL_free(audiodata->mixbuff);
   3.248 +    }
   3.249 +}
   3.250 +
   3.251 +static int
   3.252 +openslES_CreatePCMRecorder(_THIS)
   3.253 +{
   3.254 +    struct SDL_PrivateAudioData *audiodata = this->hidden;
   3.255 +    SLDataFormat_PCM format_pcm;
   3.256 +    SLresult result;
   3.257 +    int i;
   3.258 +
   3.259 +    if (!Android_JNI_RequestPermission("android.permission.RECORD_AUDIO")) {
   3.260 +        return SDL_SetError("This app doesn't have RECORD_AUDIO permission");
   3.261 +    }
   3.262 +
   3.263 +    /* Just go with signed 16-bit audio as it's the most compatible */
   3.264 +    this->spec.format = AUDIO_S16SYS;
   3.265 +    this->spec.channels = 1;
   3.266 +    /*this->spec.freq = SL_SAMPLINGRATE_16 / 1000;*/
   3.267 +
   3.268 +    /* Update the fragment size as size in bytes */
   3.269 +    SDL_CalculateAudioSpec(&this->spec);
   3.270 +
   3.271 +    LOGI("Try to open %u hz %u bit chan %u %s samples %u",
   3.272 +          this->spec.freq, SDL_AUDIO_BITSIZE(this->spec.format),
   3.273 +          this->spec.channels, (this->spec.format & 0x1000) ? "BE" : "LE", this->spec.samples);
   3.274 +
   3.275 +    /* configure audio source */
   3.276 +    SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, SL_DEFAULTDEVICEID_AUDIOINPUT, NULL};
   3.277 +    SLDataSource audioSrc = {&loc_dev, NULL};
   3.278 +
   3.279 +    /* configure audio sink */
   3.280 +    SLDataLocator_AndroidSimpleBufferQueue loc_bufq = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, NUM_BUFFERS };
   3.281 +
   3.282 +    format_pcm.formatType    = SL_DATAFORMAT_PCM;
   3.283 +    format_pcm.numChannels   = this->spec.channels;
   3.284 +    format_pcm.samplesPerSec = this->spec.freq * 1000;  /* / kilo Hz to milli Hz */
   3.285 +    format_pcm.bitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
   3.286 +    format_pcm.containerSize = SDL_AUDIO_BITSIZE(this->spec.format);
   3.287 +    format_pcm.endianness    = SL_BYTEORDER_LITTLEENDIAN;
   3.288 +    format_pcm.channelMask   = SL_SPEAKER_FRONT_CENTER;
   3.289 +
   3.290 +    SLDataSink audioSnk = { &loc_bufq, &format_pcm };
   3.291 +
   3.292 +    /* create audio recorder */
   3.293 +    /* (requires the RECORD_AUDIO permission) */
   3.294 +    const SLInterfaceID ids[1] = {
   3.295 +        SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
   3.296 +    };
   3.297 +    const SLboolean req[1] = {
   3.298 +        SL_BOOLEAN_TRUE,
   3.299 +    };
   3.300 +
   3.301 +    result = (*engineEngine)->CreateAudioRecorder(engineEngine, &recorderObject, &audioSrc, &audioSnk, 1, ids, req);
   3.302 +    if (SL_RESULT_SUCCESS != result) {
   3.303 +        LOGE("CreateAudioRecorder failed: %d", result);
   3.304 +        goto failed;
   3.305 +    }
   3.306 +
   3.307 +    /* realize the recorder */
   3.308 +    result = (*recorderObject)->Realize(recorderObject, SL_BOOLEAN_FALSE);
   3.309 +    if (SL_RESULT_SUCCESS != result) {
   3.310 +        LOGE("RealizeAudioPlayer failed: %d", result);
   3.311 +        goto failed;
   3.312 +    }
   3.313 +
   3.314 +    /* get the record interface */
   3.315 +    result = (*recorderObject)->GetInterface(recorderObject, SL_IID_RECORD, &recorderRecord);
   3.316 +    if (SL_RESULT_SUCCESS != result) {
   3.317 +        LOGE("SL_IID_RECORD interface get failed: %d", result);
   3.318 +        goto failed;
   3.319 +    }
   3.320 +
   3.321 +    /* get the buffer queue interface */
   3.322 +    result = (*recorderObject)->GetInterface(recorderObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &recorderBufferQueue);
   3.323 +    if (SL_RESULT_SUCCESS != result) {
   3.324 +        LOGE("SL_IID_BUFFERQUEUE interface get failed: %d", result);
   3.325 +        goto failed;
   3.326 +    }
   3.327 +
   3.328 +    /* register callback on the buffer queue */
   3.329 +    /* context is '(SDL_PrivateAudioData *)this->hidden' */
   3.330 +    result = (*recorderBufferQueue)->RegisterCallback(recorderBufferQueue, bqRecorderCallback, this->hidden);
   3.331 +    if (SL_RESULT_SUCCESS != result) {
   3.332 +        LOGE("RegisterCallback failed: %d", result);
   3.333 +        goto failed;
   3.334 +    }
   3.335 +
   3.336 +    /* Create the audio buffer semaphore */
   3.337 +    audiodata->playsem = SDL_CreateSemaphore(0);
   3.338 +    if (!audiodata->playsem) {
   3.339 +        LOGE("cannot create Semaphore!");
   3.340 +        goto failed;
   3.341 +    }
   3.342 +
   3.343 +    /* Create the sound buffers */
   3.344 +    audiodata->mixbuff = (Uint8 *) SDL_malloc(NUM_BUFFERS * this->spec.size);
   3.345 +    if (audiodata->mixbuff == NULL) {
   3.346 +        LOGE("mixbuffer allocate - out of memory");
   3.347 +        goto failed;
   3.348 +    }
   3.349 +
   3.350 +    for (i = 0; i < NUM_BUFFERS; i++) {
   3.351 +        audiodata->pmixbuff[i] = audiodata->mixbuff + i * this->spec.size;
   3.352 +    }
   3.353 +
   3.354 +    /* in case already recording, stop recording and clear buffer queue */
   3.355 +    result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_STOPPED);
   3.356 +    if (SL_RESULT_SUCCESS != result) {
   3.357 +        LOGE("Record set state failed: %d", result);
   3.358 +        goto failed;
   3.359 +    }
   3.360 +
   3.361 +    /* enqueue empty buffers to be filled by the recorder */
   3.362 +    for (i = 0; i < NUM_BUFFERS; i++) {
   3.363 +        result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, audiodata->pmixbuff[i], this->spec.size);
   3.364 +        if (SL_RESULT_SUCCESS != result) {
   3.365 +            LOGE("Record enqueue buffers failed: %d", result);
   3.366 +            goto failed;
   3.367 +        }
   3.368 +    }
   3.369 +
   3.370 +    /* start recording */
   3.371 +    result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_RECORDING);
   3.372 +    if (SL_RESULT_SUCCESS != result) {
   3.373 +        LOGE("Record set state failed: %d", result);
   3.374 +        goto failed;
   3.375 +    }
   3.376 +
   3.377 +    return 0;
   3.378 +
   3.379 +failed:
   3.380 +
   3.381 +    openslES_DestroyPCMRecorder(this);
   3.382 +
   3.383 +    return SDL_SetError("Open device failed!");
   3.384  }
   3.385  
   3.386  /* this callback handler is called every time a buffer finishes playing */
   3.387 @@ -197,32 +365,49 @@
   3.388  bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
   3.389  {
   3.390      struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) context;
   3.391 -    LOGV("SLES: Playback Callmeback");
   3.392 +
   3.393 +    LOGV("SLES: Playback Callback");
   3.394      SDL_SemPost(audiodata->playsem);
   3.395 -    return;
   3.396 -}
   3.397 -
   3.398 -static int
   3.399 -openslES_CreatePCMRecorder(_THIS)
   3.400 -{
   3.401 -/*    struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) this->hidden; */
   3.402 -
   3.403 -    LOGE("openslES_CreatePCMRecorder not implimented yet!");
   3.404 -    return SDL_SetError("openslES_CreatePCMRecorder not implimented yet!");
   3.405  }
   3.406  
   3.407  static void
   3.408 -openslES_DestroyPCMRecorder(_THIS)
   3.409 +openslES_DestroyPCMPlayer(_THIS)
   3.410  {
   3.411 -/*    struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) this->hidden; */
   3.412 +    struct SDL_PrivateAudioData *audiodata = this->hidden;
   3.413 +    SLresult result;
   3.414  
   3.415 -    return;
   3.416 +    /* set the player's state to 'stopped' */
   3.417 +    if (bqPlayerPlay != NULL) {
   3.418 +        result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_STOPPED);
   3.419 +        if (SL_RESULT_SUCCESS != result) {
   3.420 +            LOGE("SetPlayState stopped failed: %d", result);
   3.421 +        }
   3.422 +    }
   3.423 +
   3.424 +    /* destroy buffer queue audio player object, and invalidate all associated interfaces */
   3.425 +    if (bqPlayerObject != NULL) {
   3.426 +
   3.427 +        (*bqPlayerObject)->Destroy(bqPlayerObject);
   3.428 +
   3.429 +        bqPlayerObject = NULL;
   3.430 +        bqPlayerPlay = NULL;
   3.431 +        bqPlayerBufferQueue = NULL;
   3.432 +    }
   3.433 +
   3.434 +    if (audiodata->playsem) {
   3.435 +        SDL_DestroySemaphore(audiodata->playsem);
   3.436 +        audiodata->playsem = NULL;
   3.437 +    }
   3.438 +
   3.439 +    if (audiodata->mixbuff) {
   3.440 +        SDL_free(audiodata->mixbuff);
   3.441 +    }
   3.442  }
   3.443  
   3.444  static int
   3.445  openslES_CreatePCMPlayer(_THIS)
   3.446  {
   3.447 -    struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) this->hidden;
   3.448 +    struct SDL_PrivateAudioData *audiodata = this->hidden;
   3.449      SLDataFormat_PCM format_pcm;
   3.450      SLresult result;
   3.451      int i;
   3.452 @@ -273,31 +458,6 @@
   3.453          format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
   3.454      }
   3.455  
   3.456 -/*
   3.457 -#define SL_SPEAKER_FRONT_LEFT            ((SLuint32) 0x00000001)
   3.458 -#define SL_SPEAKER_FRONT_RIGHT           ((SLuint32) 0x00000002)
   3.459 -#define SL_SPEAKER_FRONT_CENTER          ((SLuint32) 0x00000004)
   3.460 -#define SL_SPEAKER_LOW_FREQUENCY         ((SLuint32) 0x00000008)
   3.461 -#define SL_SPEAKER_BACK_LEFT             ((SLuint32) 0x00000010)
   3.462 -#define SL_SPEAKER_BACK_RIGHT            ((SLuint32) 0x00000020)
   3.463 -#define SL_SPEAKER_FRONT_LEFT_OF_CENTER  ((SLuint32) 0x00000040)
   3.464 -#define SL_SPEAKER_FRONT_RIGHT_OF_CENTER ((SLuint32) 0x00000080)
   3.465 -#define SL_SPEAKER_BACK_CENTER           ((SLuint32) 0x00000100)
   3.466 -#define SL_SPEAKER_SIDE_LEFT             ((SLuint32) 0x00000200)
   3.467 -#define SL_SPEAKER_SIDE_RIGHT            ((SLuint32) 0x00000400)
   3.468 -#define SL_SPEAKER_TOP_CENTER            ((SLuint32) 0x00000800)
   3.469 -#define SL_SPEAKER_TOP_FRONT_LEFT        ((SLuint32) 0x00001000)
   3.470 -#define SL_SPEAKER_TOP_FRONT_CENTER      ((SLuint32) 0x00002000)
   3.471 -#define SL_SPEAKER_TOP_FRONT_RIGHT       ((SLuint32) 0x00004000)
   3.472 -#define SL_SPEAKER_TOP_BACK_LEFT         ((SLuint32) 0x00008000)
   3.473 -#define SL_SPEAKER_TOP_BACK_CENTER       ((SLuint32) 0x00010000)
   3.474 -#define SL_SPEAKER_TOP_BACK_RIGHT        ((SLuint32) 0x00020000)
   3.475 -*/
   3.476 -#define SL_ANDROID_SPEAKER_STEREO (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT)
   3.477 -#define SL_ANDROID_SPEAKER_QUAD (SL_ANDROID_SPEAKER_STEREO | SL_SPEAKER_BACK_LEFT | SL_SPEAKER_BACK_RIGHT)
   3.478 -#define SL_ANDROID_SPEAKER_5DOT1 (SL_ANDROID_SPEAKER_QUAD | SL_SPEAKER_FRONT_CENTER  | SL_SPEAKER_LOW_FREQUENCY)
   3.479 -#define SL_ANDROID_SPEAKER_7DOT1 (SL_ANDROID_SPEAKER_5DOT1 | SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT)
   3.480 -
   3.481      switch (this->spec.channels)
   3.482      {
   3.483      case 1:
   3.484 @@ -350,28 +510,28 @@
   3.485  
   3.486      result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk, 2, ids, req);
   3.487      if (SL_RESULT_SUCCESS != result) {
   3.488 -        LOGE("CreateAudioPlayer failed");
   3.489 +        LOGE("CreateAudioPlayer failed: %d", result);
   3.490          goto failed;
   3.491      }
   3.492  
   3.493      /* realize the player */
   3.494      result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
   3.495      if (SL_RESULT_SUCCESS != result) {
   3.496 -        LOGE("RealizeAudioPlayer failed");
   3.497 +        LOGE("RealizeAudioPlayer failed: %d", result);
   3.498          goto failed;
   3.499      }
   3.500  
   3.501      /* get the play interface */
   3.502      result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);
   3.503      if (SL_RESULT_SUCCESS != result) {
   3.504 -        LOGE("SL_IID_PLAY interface get failed");
   3.505 +        LOGE("SL_IID_PLAY interface get failed: %d", result);
   3.506          goto failed;
   3.507      }
   3.508  
   3.509      /* get the buffer queue interface */
   3.510      result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bqPlayerBufferQueue);
   3.511      if (SL_RESULT_SUCCESS != result) {
   3.512 -        LOGE("SL_IID_BUFFERQUEUE interface get failed");
   3.513 +        LOGE("SL_IID_BUFFERQUEUE interface get failed: %d", result);
   3.514          goto failed;
   3.515      }
   3.516  
   3.517 @@ -379,33 +539,15 @@
   3.518      /* context is '(SDL_PrivateAudioData *)this->hidden' */
   3.519      result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, this->hidden);
   3.520      if (SL_RESULT_SUCCESS != result) {
   3.521 -        LOGE("RegisterCallback failed");
   3.522 +        LOGE("RegisterCallback failed: %d", result);
   3.523          goto failed;
   3.524      }
   3.525  
   3.526  #if 0
   3.527 -    /* get the effect send interface */
   3.528 -    result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_EFFECTSEND, &bqPlayerEffectSend);
   3.529 -    if (SL_RESULT_SUCCESS != result)
   3.530 -    {
   3.531 -
   3.532 -        LOGE("SL_IID_EFFECTSEND interface get failed");
   3.533 -        goto failed;
   3.534 -    }
   3.535 -#endif
   3.536 -
   3.537 -#if 0   /* mute/solo is not supported for sources that are known to be mono, as this is */
   3.538 -    /* get the mute/solo interface */
   3.539 -    result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_MUTESOLO, &bqPlayerMuteSolo);
   3.540 -    assert(SL_RESULT_SUCCESS == result);
   3.541 -    (void) result;
   3.542 -#endif
   3.543 -
   3.544 -#if 0
   3.545      /* get the volume interface */
   3.546      result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume);
   3.547      if (SL_RESULT_SUCCESS != result) {
   3.548 -        LOGE("SL_IID_VOLUME interface get failed");
   3.549 +        LOGE("SL_IID_VOLUME interface get failed: %d", result);
   3.550          /* goto failed; */
   3.551      }
   3.552  #endif
   3.553 @@ -431,7 +573,7 @@
   3.554      /* set the player's state to playing */
   3.555      result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
   3.556      if (SL_RESULT_SUCCESS != result) {
   3.557 -        LOGE("Play set state failed");
   3.558 +        LOGE("Play set state failed: %d", result);
   3.559          goto failed;
   3.560      }
   3.561  
   3.562 @@ -444,47 +586,6 @@
   3.563      return SDL_SetError("Open device failed!");
   3.564  }
   3.565  
   3.566 -static void
   3.567 -openslES_DestroyPCMPlayer(_THIS)
   3.568 -{
   3.569 -    struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) this->hidden;
   3.570 -    SLresult result;
   3.571 -
   3.572 -    /* set the player's state to 'stopped' */
   3.573 -    if (bqPlayerPlay != NULL) {
   3.574 -        result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_STOPPED);
   3.575 -        if (SL_RESULT_SUCCESS != result) {
   3.576 -            SDL_SetError("Stopped set state failed");
   3.577 -        }
   3.578 -    }
   3.579 -
   3.580 -    /* destroy buffer queue audio player object, and invalidate all associated interfaces */
   3.581 -    if (bqPlayerObject != NULL) {
   3.582 -
   3.583 -        (*bqPlayerObject)->Destroy(bqPlayerObject);
   3.584 -
   3.585 -        bqPlayerObject = NULL;
   3.586 -        bqPlayerPlay = NULL;
   3.587 -        bqPlayerBufferQueue = NULL;
   3.588 -#if 0
   3.589 -        bqPlayerEffectSend = NULL;
   3.590 -        bqPlayerMuteSolo = NULL;
   3.591 -        bqPlayerVolume = NULL;
   3.592 -#endif
   3.593 -    }
   3.594 -
   3.595 -    if (audiodata->playsem) {
   3.596 -        SDL_DestroySemaphore(audiodata->playsem);
   3.597 -        audiodata->playsem = NULL;
   3.598 -    }
   3.599 -
   3.600 -    if (audiodata->mixbuff) {
   3.601 -        SDL_free(audiodata->mixbuff);
   3.602 -    }
   3.603 -
   3.604 -    return;
   3.605 -}
   3.606 -
   3.607  static int
   3.608  openslES_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
   3.609  {
   3.610 @@ -494,44 +595,46 @@
   3.611      }
   3.612  
   3.613      if (iscapture) {
   3.614 -        LOGI("openslES_OpenDevice( ) %s for capture", devname);
   3.615 +        LOGI("openslES_OpenDevice() %s for capture", devname);
   3.616          return openslES_CreatePCMRecorder(this);
   3.617      } else {
   3.618 -        LOGI("openslES_OpenDevice( ) %s for playing", devname);
   3.619 +        LOGI("openslES_OpenDevice() %s for playing", devname);
   3.620          return openslES_CreatePCMPlayer(this);
   3.621      }
   3.622  }
   3.623  
   3.624  static void
   3.625 -openslES_CloseDevice(_THIS)
   3.626 +openslES_WaitDevice(_THIS)
   3.627  {
   3.628 -    /* struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) this->hidden; */
   3.629 +    struct SDL_PrivateAudioData *audiodata = this->hidden;
   3.630  
   3.631 -    if (this->iscapture) {
   3.632 -        LOGI("openslES_CloseDevice( ) for capture");
   3.633 -        openslES_DestroyPCMRecorder(this);
   3.634 -    } else {
   3.635 -        LOGI("openslES_CloseDevice( ) for playing");
   3.636 -        openslES_DestroyPCMPlayer(this);
   3.637 -    }
   3.638 +    LOGV("openslES_WaitDevice()");
   3.639  
   3.640 -    SDL_free(this->hidden);
   3.641 -
   3.642 -    return;
   3.643 +    /* Wait for an audio chunk to finish */
   3.644 +    SDL_SemWait(audiodata->playsem);
   3.645  }
   3.646  
   3.647  static void
   3.648 -openslES_WaitDevice(_THIS)
   3.649 +openslES_PlayDevice(_THIS)
   3.650  {
   3.651 -    struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) this->hidden;
   3.652 +    struct SDL_PrivateAudioData *audiodata = this->hidden;
   3.653 +    SLresult result;
   3.654  
   3.655 -    LOGV("openslES_WaitDevice( )");
   3.656 +    LOGV("======openslES_PlayDevice()======");
   3.657  
   3.658 -    /* Wait for an audio chunk to finish */
   3.659 -    /* WaitForSingleObject(this->hidden->audio_sem, INFINITE); */
   3.660 -    SDL_SemWait(audiodata->playsem);
   3.661 +    /* Queue it up */
   3.662 +    result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, audiodata->pmixbuff[audiodata->next_buffer], this->spec.size);
   3.663  
   3.664 -    return;
   3.665 +    audiodata->next_buffer++;
   3.666 +    if (audiodata->next_buffer >= NUM_BUFFERS) {
   3.667 +        audiodata->next_buffer = 0;
   3.668 +    }
   3.669 +
   3.670 +    /* If Enqueue fails, callback won't be called.
   3.671 +     * Post the semphore, not to run out of buffer */
   3.672 +    if (SL_RESULT_SUCCESS != result) {
   3.673 +        SDL_SemPost(audiodata->playsem);
   3.674 +    }
   3.675  }
   3.676  
   3.677  /*/           n   playn sem */
   3.678 @@ -549,35 +652,54 @@
   3.679  static Uint8 *
   3.680  openslES_GetDeviceBuf(_THIS)
   3.681  {
   3.682 -    struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) this->hidden;
   3.683 +    struct SDL_PrivateAudioData *audiodata = this->hidden;
   3.684  
   3.685 -    LOGV("openslES_GetDeviceBuf( )");
   3.686 +    LOGV("openslES_GetDeviceBuf()");
   3.687      return audiodata->pmixbuff[audiodata->next_buffer];
   3.688  }
   3.689  
   3.690 -static void
   3.691 -openslES_PlayDevice(_THIS)
   3.692 +static int
   3.693 +openslES_CaptureFromDevice(_THIS, void *buffer, int buflen)
   3.694  {
   3.695 -    struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) this->hidden;
   3.696 +    struct SDL_PrivateAudioData *audiodata = this->hidden;
   3.697      SLresult result;
   3.698  
   3.699 -    LOGV("======openslES_PlayDevice( )======");
   3.700 +    /* Wait for new recorded data */
   3.701 +    SDL_SemWait(audiodata->playsem);
   3.702  
   3.703 -    /* Queue it up */
   3.704 -    result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, audiodata->pmixbuff[audiodata->next_buffer], this->spec.size);
   3.705 +    /* Copy it to the output buffer */
   3.706 +    SDL_assert(buflen == this->spec.size);
   3.707 +    SDL_memcpy(buffer, audiodata->pmixbuff[audiodata->next_buffer], this->spec.size);
   3.708 +
   3.709 +    /* Re-enqueue the buffer */
   3.710 +    result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, audiodata->pmixbuff[audiodata->next_buffer], this->spec.size);
   3.711 +    if (SL_RESULT_SUCCESS != result) {
   3.712 +        LOGE("Record enqueue buffers failed: %d", result);
   3.713 +        return -1;
   3.714 +    }
   3.715  
   3.716      audiodata->next_buffer++;
   3.717      if (audiodata->next_buffer >= NUM_BUFFERS) {
   3.718          audiodata->next_buffer = 0;
   3.719      }
   3.720  
   3.721 -    /* If Enqueue fails, callback won't be called.
   3.722 -     * Post the semphore, not to run out of buffer */
   3.723 -    if (SL_RESULT_SUCCESS != result) {
   3.724 -        SDL_SemPost(audiodata->playsem);
   3.725 +    return this->spec.size;
   3.726 +}
   3.727 +
   3.728 +static void
   3.729 +openslES_CloseDevice(_THIS)
   3.730 +{
   3.731 +    /* struct SDL_PrivateAudioData *audiodata = this->hidden; */
   3.732 +
   3.733 +    if (this->iscapture) {
   3.734 +        LOGI("openslES_CloseDevice() for capture");
   3.735 +        openslES_DestroyPCMRecorder(this);
   3.736 +    } else {
   3.737 +        LOGI("openslES_CloseDevice() for playing");
   3.738 +        openslES_DestroyPCMPlayer(this);
   3.739      }
   3.740  
   3.741 -    return;
   3.742 +    SDL_free(this->hidden);
   3.743  }
   3.744  
   3.745  static int
   3.746 @@ -594,18 +716,19 @@
   3.747      /* Set the function pointers */
   3.748      /* impl->DetectDevices = openslES_DetectDevices; */
   3.749      impl->OpenDevice    = openslES_OpenDevice;
   3.750 -    impl->CloseDevice   = openslES_CloseDevice;
   3.751 +    impl->WaitDevice    = openslES_WaitDevice;
   3.752      impl->PlayDevice    = openslES_PlayDevice;
   3.753      impl->GetDeviceBuf  = openslES_GetDeviceBuf;
   3.754 +    impl->CaptureFromDevice = openslES_CaptureFromDevice;
   3.755 +    impl->CloseDevice   = openslES_CloseDevice;
   3.756      impl->Deinitialize  = openslES_DestroyEngine;
   3.757 -    impl->WaitDevice    = openslES_WaitDevice;
   3.758  
   3.759      /* and the capabilities */
   3.760 -    impl->HasCaptureSupport             = 0;        /* TODO */
   3.761 -    impl->OnlyHasDefaultOutputDevice    = 1;
   3.762 -    /* impl->OnlyHasDefaultInputDevice  = 1; */
   3.763 +    impl->HasCaptureSupport = 1;
   3.764 +    impl->OnlyHasDefaultOutputDevice = 1;
   3.765 +    impl->OnlyHasDefaultCaptureDevice = 1;
   3.766  
   3.767 -    LOGI("openslES_Init() - succes");
   3.768 +    LOGI("openslES_Init() - success");
   3.769  
   3.770      /* this audio target is available. */
   3.771      return 1;
   3.772 @@ -615,24 +738,24 @@
   3.773      "openslES", "opensl ES audio driver", openslES_Init, 0
   3.774  };
   3.775  
   3.776 -void openslES_ResumeDevices()
   3.777 +void openslES_ResumeDevices(void)
   3.778  {
   3.779      if (bqPlayerPlay != NULL) {
   3.780          /* set the player's state to 'playing' */
   3.781          SLresult result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
   3.782          if (SL_RESULT_SUCCESS != result) {
   3.783 -            SDL_SetError("openslES_ResumeDevices failed");
   3.784 +            LOGE("openslES_ResumeDevices failed: %d", result);
   3.785          }
   3.786      }
   3.787  }
   3.788  
   3.789 -void openslES_PauseDevices()
   3.790 +void openslES_PauseDevices(void)
   3.791  {
   3.792      if (bqPlayerPlay != NULL) {
   3.793          /* set the player's state to 'paused' */
   3.794          SLresult result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PAUSED);
   3.795          if (SL_RESULT_SUCCESS != result) {
   3.796 -            SDL_SetError("openslES_PauseDevices failed");
   3.797 +            LOGE("openslES_PauseDevices failed: %d", result);
   3.798          }
   3.799      }
   3.800  }
     4.1 --- a/src/audio/openslES/SDL_openslES.h	Tue Feb 11 10:35:14 2020 -0800
     4.2 +++ b/src/audio/openslES/SDL_openslES.h	Tue Feb 11 16:14:02 2020 -0800
     4.3 @@ -32,14 +32,10 @@
     4.4  
     4.5  struct SDL_PrivateAudioData
     4.6  {
     4.7 -    /* The file descriptor for the audio device */
     4.8      Uint8   *mixbuff;
     4.9      int      next_buffer;
    4.10      Uint8   *pmixbuff[NUM_BUFFERS];
    4.11      SDL_sem *playsem;
    4.12 -#if 0
    4.13 -    SDL_sem *recsem;
    4.14 -#endif
    4.15  };
    4.16  
    4.17  void openslES_ResumeDevices(void);
     5.1 --- a/src/core/android/SDL_android.h	Tue Feb 11 10:35:14 2020 -0800
     5.2 +++ b/src/core/android/SDL_android.h	Tue Feb 11 16:14:02 2020 -0800
     5.3 @@ -123,6 +123,8 @@
     5.4  SDL_bool Android_JNI_SupportsRelativeMouse(void);
     5.5  SDL_bool Android_JNI_SetRelativeMouseEnabled(SDL_bool enabled);
     5.6  
     5.7 +/* Request permission */
     5.8 +SDL_bool Android_JNI_RequestPermission(const char *permission);
     5.9  
    5.10  int SDL_GetAndroidSDKVersion(void);
    5.11