|
|
@ -26,8 +26,10 @@
|
|
|
|
https://googlesamples.github.io/android-audio-high-performance/guides/opensl_es.html
|
|
|
|
https://googlesamples.github.io/android-audio-high-performance/guides/opensl_es.html
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "SDL_assert.h"
|
|
|
|
#include "SDL_audio.h"
|
|
|
|
#include "SDL_audio.h"
|
|
|
|
#include "../SDL_audio_c.h"
|
|
|
|
#include "../SDL_audio_c.h"
|
|
|
|
|
|
|
|
#include "../../core/android/SDL_android.h"
|
|
|
|
#include "SDL_openslES.h"
|
|
|
|
#include "SDL_openslES.h"
|
|
|
|
|
|
|
|
|
|
|
|
/* for native audio */
|
|
|
|
/* for native audio */
|
|
|
@ -48,42 +50,50 @@
|
|
|
|
#define LOGV(...)
|
|
|
|
#define LOGV(...)
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
#define SL_SPEAKER_FRONT_LEFT ((SLuint32) 0x00000001)
|
|
|
|
|
|
|
|
#define SL_SPEAKER_FRONT_RIGHT ((SLuint32) 0x00000002)
|
|
|
|
|
|
|
|
#define SL_SPEAKER_FRONT_CENTER ((SLuint32) 0x00000004)
|
|
|
|
|
|
|
|
#define SL_SPEAKER_LOW_FREQUENCY ((SLuint32) 0x00000008)
|
|
|
|
|
|
|
|
#define SL_SPEAKER_BACK_LEFT ((SLuint32) 0x00000010)
|
|
|
|
|
|
|
|
#define SL_SPEAKER_BACK_RIGHT ((SLuint32) 0x00000020)
|
|
|
|
|
|
|
|
#define SL_SPEAKER_FRONT_LEFT_OF_CENTER ((SLuint32) 0x00000040)
|
|
|
|
|
|
|
|
#define SL_SPEAKER_FRONT_RIGHT_OF_CENTER ((SLuint32) 0x00000080)
|
|
|
|
|
|
|
|
#define SL_SPEAKER_BACK_CENTER ((SLuint32) 0x00000100)
|
|
|
|
|
|
|
|
#define SL_SPEAKER_SIDE_LEFT ((SLuint32) 0x00000200)
|
|
|
|
|
|
|
|
#define SL_SPEAKER_SIDE_RIGHT ((SLuint32) 0x00000400)
|
|
|
|
|
|
|
|
#define SL_SPEAKER_TOP_CENTER ((SLuint32) 0x00000800)
|
|
|
|
|
|
|
|
#define SL_SPEAKER_TOP_FRONT_LEFT ((SLuint32) 0x00001000)
|
|
|
|
|
|
|
|
#define SL_SPEAKER_TOP_FRONT_CENTER ((SLuint32) 0x00002000)
|
|
|
|
|
|
|
|
#define SL_SPEAKER_TOP_FRONT_RIGHT ((SLuint32) 0x00004000)
|
|
|
|
|
|
|
|
#define SL_SPEAKER_TOP_BACK_LEFT ((SLuint32) 0x00008000)
|
|
|
|
|
|
|
|
#define SL_SPEAKER_TOP_BACK_CENTER ((SLuint32) 0x00010000)
|
|
|
|
|
|
|
|
#define SL_SPEAKER_TOP_BACK_RIGHT ((SLuint32) 0x00020000)
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define SL_ANDROID_SPEAKER_STEREO (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT)
|
|
|
|
|
|
|
|
#define SL_ANDROID_SPEAKER_QUAD (SL_ANDROID_SPEAKER_STEREO | SL_SPEAKER_BACK_LEFT | SL_SPEAKER_BACK_RIGHT)
|
|
|
|
|
|
|
|
#define SL_ANDROID_SPEAKER_5DOT1 (SL_ANDROID_SPEAKER_QUAD | SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY)
|
|
|
|
|
|
|
|
#define SL_ANDROID_SPEAKER_7DOT1 (SL_ANDROID_SPEAKER_5DOT1 | SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT)
|
|
|
|
|
|
|
|
|
|
|
|
/* engine interfaces */
|
|
|
|
/* engine interfaces */
|
|
|
|
static SLObjectItf engineObject = NULL;
|
|
|
|
static SLObjectItf engineObject;
|
|
|
|
static SLEngineItf engineEngine = NULL;
|
|
|
|
static SLEngineItf engineEngine;
|
|
|
|
|
|
|
|
|
|
|
|
/* output mix interfaces */
|
|
|
|
/* output mix interfaces */
|
|
|
|
static SLObjectItf outputMixObject = NULL;
|
|
|
|
static SLObjectItf outputMixObject;
|
|
|
|
// static SLEnvironmentalReverbItf outputMixEnvironmentalReverb = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* aux effect on the output mix, used by the buffer queue player */
|
|
|
|
|
|
|
|
/* static const SLEnvironmentalReverbSettings reverbSettings = SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR; */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* buffer queue player interfaces */
|
|
|
|
/* buffer queue player interfaces */
|
|
|
|
static SLObjectItf bqPlayerObject = NULL;
|
|
|
|
static SLObjectItf bqPlayerObject;
|
|
|
|
static SLPlayItf bqPlayerPlay = NULL;
|
|
|
|
static SLPlayItf bqPlayerPlay;
|
|
|
|
static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue = NULL;
|
|
|
|
static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue;
|
|
|
|
#if 0
|
|
|
|
#if 0
|
|
|
|
static SLEffectSendItf bqPlayerEffectSend = NULL;
|
|
|
|
static SLVolumeItf bqPlayerVolume;
|
|
|
|
static SLMuteSoloItf bqPlayerMuteSolo = NULL;
|
|
|
|
|
|
|
|
static SLVolumeItf bqPlayerVolume = NULL;
|
|
|
|
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
/* recorder interfaces */
|
|
|
|
/* recorder interfaces TODO */
|
|
|
|
static SLObjectItf recorderObject;
|
|
|
|
static SLObjectItf recorderObject = NULL;
|
|
|
|
static SLRecordItf recorderRecord;
|
|
|
|
static SLRecordItf recorderRecord;
|
|
|
|
|
|
|
|
static SLAndroidSimpleBufferQueueItf recorderBufferQueue;
|
|
|
|
static SLAndroidSimpleBufferQueueItf recorderBufferQueue;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* pointer and size of the next player buffer to enqueue, and number of remaining buffers */
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
|
|
|
static short *nextBuffer;
|
|
|
|
|
|
|
|
static unsigned nextSize;
|
|
|
|
|
|
|
|
static int nextCount;
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// static SDL_AudioDevice* audioDevice = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
#if 0
|
|
|
|
static const char *sldevaudiorecorderstr = "SLES Audio Recorder";
|
|
|
|
static const char *sldevaudiorecorderstr = "SLES Audio Recorder";
|
|
|
@ -93,19 +103,34 @@ static const char *sldevaudioplayerstr = "SLES Audio Player";
|
|
|
|
#define SLES_DEV_AUDIO_PLAYER sldevaudioplayerstr
|
|
|
|
#define SLES_DEV_AUDIO_PLAYER sldevaudioplayerstr
|
|
|
|
static void openslES_DetectDevices( int iscapture )
|
|
|
|
static void openslES_DetectDevices( int iscapture )
|
|
|
|
{
|
|
|
|
{
|
|
|
|
LOGI( "openSLES_DetectDevices()" );
|
|
|
|
LOGI( "openSLES_DetectDevices()" );
|
|
|
|
if ( iscapture )
|
|
|
|
if ( iscapture )
|
|
|
|
addfn( SLES_DEV_AUDIO_RECORDER );
|
|
|
|
addfn( SLES_DEV_AUDIO_RECORDER );
|
|
|
|
else
|
|
|
|
else
|
|
|
|
addfn( SLES_DEV_AUDIO_PLAYER );
|
|
|
|
addfn( SLES_DEV_AUDIO_PLAYER );
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
static void openslES_DestroyEngine(void);
|
|
|
|
static void openslES_DestroyEngine(void)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
LOGI("openslES_DestroyEngine()");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* destroy output mix object, and invalidate all associated interfaces */
|
|
|
|
|
|
|
|
if (outputMixObject != NULL) {
|
|
|
|
|
|
|
|
(*outputMixObject)->Destroy(outputMixObject);
|
|
|
|
|
|
|
|
outputMixObject = NULL;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* destroy engine object, and invalidate all associated interfaces */
|
|
|
|
|
|
|
|
if (engineObject != NULL) {
|
|
|
|
|
|
|
|
(*engineObject)->Destroy(engineObject);
|
|
|
|
|
|
|
|
engineObject = NULL;
|
|
|
|
|
|
|
|
engineEngine = NULL;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
static int
|
|
|
|
openslES_CreateEngine()
|
|
|
|
openslES_CreateEngine(void)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
SLresult result;
|
|
|
|
SLresult result;
|
|
|
|
|
|
|
|
|
|
|
@ -114,40 +139,33 @@ openslES_CreateEngine()
|
|
|
|
/* create engine */
|
|
|
|
/* create engine */
|
|
|
|
result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
|
|
|
|
result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
LOGE("slCreateEngine failed");
|
|
|
|
LOGE("slCreateEngine failed: %d", result);
|
|
|
|
goto error;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LOGI("slCreateEngine OK");
|
|
|
|
LOGI("slCreateEngine OK");
|
|
|
|
|
|
|
|
|
|
|
|
/* realize the engine */
|
|
|
|
/* realize the engine */
|
|
|
|
result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
|
|
|
|
result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
LOGE("RealizeEngine failed");
|
|
|
|
LOGE("RealizeEngine failed: %d", result);
|
|
|
|
goto error;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LOGI("RealizeEngine OK");
|
|
|
|
LOGI("RealizeEngine OK");
|
|
|
|
|
|
|
|
|
|
|
|
/* get the engine interface, which is needed in order to create other objects */
|
|
|
|
/* get the engine interface, which is needed in order to create other objects */
|
|
|
|
result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
|
|
|
|
result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
LOGE("EngineGetInterface failed");
|
|
|
|
LOGE("EngineGetInterface failed: %d", result);
|
|
|
|
goto error;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LOGI("EngineGetInterface OK");
|
|
|
|
LOGI("EngineGetInterface OK");
|
|
|
|
|
|
|
|
|
|
|
|
/* create output mix, with environmental reverb specified as a non-required interface */
|
|
|
|
/* create output mix */
|
|
|
|
/* const SLInterfaceID ids[1] = { SL_IID_ENVIRONMENTALREVERB }; */
|
|
|
|
|
|
|
|
/* const SLboolean req[1] = { SL_BOOLEAN_FALSE }; */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const SLInterfaceID ids[1] = { SL_IID_VOLUME };
|
|
|
|
const SLInterfaceID ids[1] = { SL_IID_VOLUME };
|
|
|
|
const SLboolean req[1] = { SL_BOOLEAN_FALSE };
|
|
|
|
const SLboolean req[1] = { SL_BOOLEAN_FALSE };
|
|
|
|
result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, ids, req);
|
|
|
|
result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, ids, req);
|
|
|
|
|
|
|
|
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
LOGE("CreateOutputMix failed");
|
|
|
|
LOGE("CreateOutputMix failed: %d", result);
|
|
|
|
goto error;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
LOGI("CreateOutputMix OK");
|
|
|
|
LOGI("CreateOutputMix OK");
|
|
|
@ -155,7 +173,7 @@ openslES_CreateEngine()
|
|
|
|
/* realize the output mix */
|
|
|
|
/* realize the output mix */
|
|
|
|
result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
|
|
|
|
result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
LOGE("RealizeOutputMix failed");
|
|
|
|
LOGE("RealizeOutputMix failed: %d", result);
|
|
|
|
goto error;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
return 1;
|
|
|
@ -165,31 +183,181 @@ error:
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void openslES_DestroyPCMPlayer(_THIS);
|
|
|
|
/* this callback handler is called every time a buffer finishes recording */
|
|
|
|
static void openslES_DestroyPCMRecorder(_THIS);
|
|
|
|
static void
|
|
|
|
|
|
|
|
bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
|
|
|
|
static void openslES_DestroyEngine()
|
|
|
|
|
|
|
|
{
|
|
|
|
{
|
|
|
|
LOGI("openslES_DestroyEngine()");
|
|
|
|
struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) context;
|
|
|
|
|
|
|
|
|
|
|
|
// openslES_DestroyPCMPlayer(this);
|
|
|
|
LOGV("SLES: Recording Callback");
|
|
|
|
// openslES_DestroyPCMRecorder(this);
|
|
|
|
SDL_SemPost(audiodata->playsem);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* destroy output mix object, and invalidate all associated interfaces */
|
|
|
|
static void
|
|
|
|
if (outputMixObject != NULL) {
|
|
|
|
openslES_DestroyPCMRecorder(_THIS)
|
|
|
|
(*outputMixObject)->Destroy(outputMixObject);
|
|
|
|
{
|
|
|
|
outputMixObject = NULL;
|
|
|
|
struct SDL_PrivateAudioData *audiodata = this->hidden;
|
|
|
|
/* outputMixEnvironmentalReverb = NULL; */
|
|
|
|
SLresult result;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* stop recording */
|
|
|
|
|
|
|
|
if (recorderRecord != NULL) {
|
|
|
|
|
|
|
|
result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_STOPPED);
|
|
|
|
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
|
|
|
|
LOGE("SetRecordState stopped: %d", result);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* destroy engine object, and invalidate all associated interfaces */
|
|
|
|
/* destroy audio recorder object, and invalidate all associated interfaces */
|
|
|
|
if (engineObject != NULL) {
|
|
|
|
if (recorderObject != NULL) {
|
|
|
|
(*engineObject)->Destroy(engineObject);
|
|
|
|
(*recorderObject)->Destroy(recorderObject);
|
|
|
|
engineObject = NULL;
|
|
|
|
recorderObject = NULL;
|
|
|
|
engineEngine = NULL;
|
|
|
|
recorderRecord = NULL;
|
|
|
|
|
|
|
|
recorderBufferQueue = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
if (audiodata->playsem) {
|
|
|
|
|
|
|
|
SDL_DestroySemaphore(audiodata->playsem);
|
|
|
|
|
|
|
|
audiodata->playsem = NULL;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (audiodata->mixbuff) {
|
|
|
|
|
|
|
|
SDL_free(audiodata->mixbuff);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
|
|
|
openslES_CreatePCMRecorder(_THIS)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
struct SDL_PrivateAudioData *audiodata = this->hidden;
|
|
|
|
|
|
|
|
SLDataFormat_PCM format_pcm;
|
|
|
|
|
|
|
|
SLresult result;
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!Android_JNI_RequestPermission("android.permission.RECORD_AUDIO")) {
|
|
|
|
|
|
|
|
return SDL_SetError("This app doesn't have RECORD_AUDIO permission");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Just go with signed 16-bit audio as it's the most compatible */
|
|
|
|
|
|
|
|
this->spec.format = AUDIO_S16SYS;
|
|
|
|
|
|
|
|
this->spec.channels = 1;
|
|
|
|
|
|
|
|
/*this->spec.freq = SL_SAMPLINGRATE_16 / 1000;*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Update the fragment size as size in bytes */
|
|
|
|
|
|
|
|
SDL_CalculateAudioSpec(&this->spec);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LOGI("Try to open %u hz %u bit chan %u %s samples %u",
|
|
|
|
|
|
|
|
this->spec.freq, SDL_AUDIO_BITSIZE(this->spec.format),
|
|
|
|
|
|
|
|
this->spec.channels, (this->spec.format & 0x1000) ? "BE" : "LE", this->spec.samples);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* configure audio source */
|
|
|
|
|
|
|
|
SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, SL_DEFAULTDEVICEID_AUDIOINPUT, NULL};
|
|
|
|
|
|
|
|
SLDataSource audioSrc = {&loc_dev, NULL};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* configure audio sink */
|
|
|
|
|
|
|
|
SLDataLocator_AndroidSimpleBufferQueue loc_bufq = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, NUM_BUFFERS };
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
format_pcm.formatType = SL_DATAFORMAT_PCM;
|
|
|
|
|
|
|
|
format_pcm.numChannels = this->spec.channels;
|
|
|
|
|
|
|
|
format_pcm.samplesPerSec = this->spec.freq * 1000; /* / kilo Hz to milli Hz */
|
|
|
|
|
|
|
|
format_pcm.bitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
|
|
|
|
|
|
|
|
format_pcm.containerSize = SDL_AUDIO_BITSIZE(this->spec.format);
|
|
|
|
|
|
|
|
format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
|
|
|
|
|
|
|
|
format_pcm.channelMask = SL_SPEAKER_FRONT_CENTER;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SLDataSink audioSnk = { &loc_bufq, &format_pcm };
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* create audio recorder */
|
|
|
|
|
|
|
|
/* (requires the RECORD_AUDIO permission) */
|
|
|
|
|
|
|
|
const SLInterfaceID ids[1] = {
|
|
|
|
|
|
|
|
SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
const SLboolean req[1] = {
|
|
|
|
|
|
|
|
SL_BOOLEAN_TRUE,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
result = (*engineEngine)->CreateAudioRecorder(engineEngine, &recorderObject, &audioSrc, &audioSnk, 1, ids, req);
|
|
|
|
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
|
|
|
|
LOGE("CreateAudioRecorder failed: %d", result);
|
|
|
|
|
|
|
|
goto failed;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* realize the recorder */
|
|
|
|
|
|
|
|
result = (*recorderObject)->Realize(recorderObject, SL_BOOLEAN_FALSE);
|
|
|
|
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
|
|
|
|
LOGE("RealizeAudioPlayer failed: %d", result);
|
|
|
|
|
|
|
|
goto failed;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* get the record interface */
|
|
|
|
|
|
|
|
result = (*recorderObject)->GetInterface(recorderObject, SL_IID_RECORD, &recorderRecord);
|
|
|
|
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
|
|
|
|
LOGE("SL_IID_RECORD interface get failed: %d", result);
|
|
|
|
|
|
|
|
goto failed;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* get the buffer queue interface */
|
|
|
|
|
|
|
|
result = (*recorderObject)->GetInterface(recorderObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &recorderBufferQueue);
|
|
|
|
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
|
|
|
|
LOGE("SL_IID_BUFFERQUEUE interface get failed: %d", result);
|
|
|
|
|
|
|
|
goto failed;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* register callback on the buffer queue */
|
|
|
|
|
|
|
|
/* context is '(SDL_PrivateAudioData *)this->hidden' */
|
|
|
|
|
|
|
|
result = (*recorderBufferQueue)->RegisterCallback(recorderBufferQueue, bqRecorderCallback, this->hidden);
|
|
|
|
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
|
|
|
|
LOGE("RegisterCallback failed: %d", result);
|
|
|
|
|
|
|
|
goto failed;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Create the audio buffer semaphore */
|
|
|
|
|
|
|
|
audiodata->playsem = SDL_CreateSemaphore(0);
|
|
|
|
|
|
|
|
if (!audiodata->playsem) {
|
|
|
|
|
|
|
|
LOGE("cannot create Semaphore!");
|
|
|
|
|
|
|
|
goto failed;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Create the sound buffers */
|
|
|
|
|
|
|
|
audiodata->mixbuff = (Uint8 *) SDL_malloc(NUM_BUFFERS * this->spec.size);
|
|
|
|
|
|
|
|
if (audiodata->mixbuff == NULL) {
|
|
|
|
|
|
|
|
LOGE("mixbuffer allocate - out of memory");
|
|
|
|
|
|
|
|
goto failed;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < NUM_BUFFERS; i++) {
|
|
|
|
|
|
|
|
audiodata->pmixbuff[i] = audiodata->mixbuff + i * this->spec.size;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* in case already recording, stop recording and clear buffer queue */
|
|
|
|
|
|
|
|
result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_STOPPED);
|
|
|
|
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
|
|
|
|
LOGE("Record set state failed: %d", result);
|
|
|
|
|
|
|
|
goto failed;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* enqueue empty buffers to be filled by the recorder */
|
|
|
|
|
|
|
|
for (i = 0; i < NUM_BUFFERS; i++) {
|
|
|
|
|
|
|
|
result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, audiodata->pmixbuff[i], this->spec.size);
|
|
|
|
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
|
|
|
|
LOGE("Record enqueue buffers failed: %d", result);
|
|
|
|
|
|
|
|
goto failed;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* start recording */
|
|
|
|
|
|
|
|
result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_RECORDING);
|
|
|
|
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
|
|
|
|
LOGE("Record set state failed: %d", result);
|
|
|
|
|
|
|
|
goto failed;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
failed:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openslES_DestroyPCMRecorder(this);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return SDL_SetError("Open device failed!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* this callback handler is called every time a buffer finishes playing */
|
|
|
|
/* this callback handler is called every time a buffer finishes playing */
|
|
|
@ -197,32 +365,49 @@ static void
|
|
|
|
bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
|
|
|
|
bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) context;
|
|
|
|
struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) context;
|
|
|
|
LOGV("SLES: Playback Callmeback");
|
|
|
|
|
|
|
|
|
|
|
|
LOGV("SLES: Playback Callback");
|
|
|
|
SDL_SemPost(audiodata->playsem);
|
|
|
|
SDL_SemPost(audiodata->playsem);
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
|
|
|
openslES_CreatePCMRecorder(_THIS)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
/* struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) this->hidden; */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LOGE("openslES_CreatePCMRecorder not implimented yet!");
|
|
|
|
|
|
|
|
return SDL_SetError("openslES_CreatePCMRecorder not implimented yet!");
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
static void
|
|
|
|
openslES_DestroyPCMRecorder(_THIS)
|
|
|
|
openslES_DestroyPCMPlayer(_THIS)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
/* struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) this->hidden; */
|
|
|
|
struct SDL_PrivateAudioData *audiodata = this->hidden;
|
|
|
|
|
|
|
|
SLresult result;
|
|
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
/* set the player's state to 'stopped' */
|
|
|
|
|
|
|
|
if (bqPlayerPlay != NULL) {
|
|
|
|
|
|
|
|
result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_STOPPED);
|
|
|
|
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
|
|
|
|
LOGE("SetPlayState stopped failed: %d", result);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* destroy buffer queue audio player object, and invalidate all associated interfaces */
|
|
|
|
|
|
|
|
if (bqPlayerObject != NULL) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(*bqPlayerObject)->Destroy(bqPlayerObject);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bqPlayerObject = NULL;
|
|
|
|
|
|
|
|
bqPlayerPlay = NULL;
|
|
|
|
|
|
|
|
bqPlayerBufferQueue = NULL;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (audiodata->playsem) {
|
|
|
|
|
|
|
|
SDL_DestroySemaphore(audiodata->playsem);
|
|
|
|
|
|
|
|
audiodata->playsem = NULL;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (audiodata->mixbuff) {
|
|
|
|
|
|
|
|
SDL_free(audiodata->mixbuff);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
static int
|
|
|
|
openslES_CreatePCMPlayer(_THIS)
|
|
|
|
openslES_CreatePCMPlayer(_THIS)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) this->hidden;
|
|
|
|
struct SDL_PrivateAudioData *audiodata = this->hidden;
|
|
|
|
SLDataFormat_PCM format_pcm;
|
|
|
|
SLDataFormat_PCM format_pcm;
|
|
|
|
SLresult result;
|
|
|
|
SLresult result;
|
|
|
|
int i;
|
|
|
|
int i;
|
|
|
@ -273,31 +458,6 @@ openslES_CreatePCMPlayer(_THIS)
|
|
|
|
format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
|
|
|
|
format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
#define SL_SPEAKER_FRONT_LEFT ((SLuint32) 0x00000001)
|
|
|
|
|
|
|
|
#define SL_SPEAKER_FRONT_RIGHT ((SLuint32) 0x00000002)
|
|
|
|
|
|
|
|
#define SL_SPEAKER_FRONT_CENTER ((SLuint32) 0x00000004)
|
|
|
|
|
|
|
|
#define SL_SPEAKER_LOW_FREQUENCY ((SLuint32) 0x00000008)
|
|
|
|
|
|
|
|
#define SL_SPEAKER_BACK_LEFT ((SLuint32) 0x00000010)
|
|
|
|
|
|
|
|
#define SL_SPEAKER_BACK_RIGHT ((SLuint32) 0x00000020)
|
|
|
|
|
|
|
|
#define SL_SPEAKER_FRONT_LEFT_OF_CENTER ((SLuint32) 0x00000040)
|
|
|
|
|
|
|
|
#define SL_SPEAKER_FRONT_RIGHT_OF_CENTER ((SLuint32) 0x00000080)
|
|
|
|
|
|
|
|
#define SL_SPEAKER_BACK_CENTER ((SLuint32) 0x00000100)
|
|
|
|
|
|
|
|
#define SL_SPEAKER_SIDE_LEFT ((SLuint32) 0x00000200)
|
|
|
|
|
|
|
|
#define SL_SPEAKER_SIDE_RIGHT ((SLuint32) 0x00000400)
|
|
|
|
|
|
|
|
#define SL_SPEAKER_TOP_CENTER ((SLuint32) 0x00000800)
|
|
|
|
|
|
|
|
#define SL_SPEAKER_TOP_FRONT_LEFT ((SLuint32) 0x00001000)
|
|
|
|
|
|
|
|
#define SL_SPEAKER_TOP_FRONT_CENTER ((SLuint32) 0x00002000)
|
|
|
|
|
|
|
|
#define SL_SPEAKER_TOP_FRONT_RIGHT ((SLuint32) 0x00004000)
|
|
|
|
|
|
|
|
#define SL_SPEAKER_TOP_BACK_LEFT ((SLuint32) 0x00008000)
|
|
|
|
|
|
|
|
#define SL_SPEAKER_TOP_BACK_CENTER ((SLuint32) 0x00010000)
|
|
|
|
|
|
|
|
#define SL_SPEAKER_TOP_BACK_RIGHT ((SLuint32) 0x00020000)
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define SL_ANDROID_SPEAKER_STEREO (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT)
|
|
|
|
|
|
|
|
#define SL_ANDROID_SPEAKER_QUAD (SL_ANDROID_SPEAKER_STEREO | SL_SPEAKER_BACK_LEFT | SL_SPEAKER_BACK_RIGHT)
|
|
|
|
|
|
|
|
#define SL_ANDROID_SPEAKER_5DOT1 (SL_ANDROID_SPEAKER_QUAD | SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY)
|
|
|
|
|
|
|
|
#define SL_ANDROID_SPEAKER_7DOT1 (SL_ANDROID_SPEAKER_5DOT1 | SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
switch (this->spec.channels)
|
|
|
|
switch (this->spec.channels)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
case 1:
|
|
|
@ -350,28 +510,28 @@ openslES_CreatePCMPlayer(_THIS)
|
|
|
|
|
|
|
|
|
|
|
|
result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk, 2, ids, req);
|
|
|
|
result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk, 2, ids, req);
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
LOGE("CreateAudioPlayer failed");
|
|
|
|
LOGE("CreateAudioPlayer failed: %d", result);
|
|
|
|
goto failed;
|
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* realize the player */
|
|
|
|
/* realize the player */
|
|
|
|
result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
|
|
|
|
result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
LOGE("RealizeAudioPlayer failed");
|
|
|
|
LOGE("RealizeAudioPlayer failed: %d", result);
|
|
|
|
goto failed;
|
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* get the play interface */
|
|
|
|
/* get the play interface */
|
|
|
|
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);
|
|
|
|
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
LOGE("SL_IID_PLAY interface get failed");
|
|
|
|
LOGE("SL_IID_PLAY interface get failed: %d", result);
|
|
|
|
goto failed;
|
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* get the buffer queue interface */
|
|
|
|
/* get the buffer queue interface */
|
|
|
|
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bqPlayerBufferQueue);
|
|
|
|
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bqPlayerBufferQueue);
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
LOGE("SL_IID_BUFFERQUEUE interface get failed");
|
|
|
|
LOGE("SL_IID_BUFFERQUEUE interface get failed: %d", result);
|
|
|
|
goto failed;
|
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -379,33 +539,15 @@ openslES_CreatePCMPlayer(_THIS)
|
|
|
|
/* context is '(SDL_PrivateAudioData *)this->hidden' */
|
|
|
|
/* context is '(SDL_PrivateAudioData *)this->hidden' */
|
|
|
|
result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, this->hidden);
|
|
|
|
result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, this->hidden);
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
LOGE("RegisterCallback failed");
|
|
|
|
LOGE("RegisterCallback failed: %d", result);
|
|
|
|
goto failed;
|
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
|
|
|
/* get the effect send interface */
|
|
|
|
|
|
|
|
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_EFFECTSEND, &bqPlayerEffectSend);
|
|
|
|
|
|
|
|
if (SL_RESULT_SUCCESS != result)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LOGE("SL_IID_EFFECTSEND interface get failed");
|
|
|
|
|
|
|
|
goto failed;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if 0 /* mute/solo is not supported for sources that are known to be mono, as this is */
|
|
|
|
|
|
|
|
/* get the mute/solo interface */
|
|
|
|
|
|
|
|
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_MUTESOLO, &bqPlayerMuteSolo);
|
|
|
|
|
|
|
|
assert(SL_RESULT_SUCCESS == result);
|
|
|
|
|
|
|
|
(void) result;
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
#if 0
|
|
|
|
/* get the volume interface */
|
|
|
|
/* get the volume interface */
|
|
|
|
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume);
|
|
|
|
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume);
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
LOGE("SL_IID_VOLUME interface get failed");
|
|
|
|
LOGE("SL_IID_VOLUME interface get failed: %d", result);
|
|
|
|
/* goto failed; */
|
|
|
|
/* goto failed; */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
@ -431,7 +573,7 @@ openslES_CreatePCMPlayer(_THIS)
|
|
|
|
/* set the player's state to playing */
|
|
|
|
/* set the player's state to playing */
|
|
|
|
result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
|
|
|
|
result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
LOGE("Play set state failed");
|
|
|
|
LOGE("Play set state failed: %d", result);
|
|
|
|
goto failed;
|
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -444,47 +586,6 @@ failed:
|
|
|
|
return SDL_SetError("Open device failed!");
|
|
|
|
return SDL_SetError("Open device failed!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
|
|
|
openslES_DestroyPCMPlayer(_THIS)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) this->hidden;
|
|
|
|
|
|
|
|
SLresult result;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* set the player's state to 'stopped' */
|
|
|
|
|
|
|
|
if (bqPlayerPlay != NULL) {
|
|
|
|
|
|
|
|
result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_STOPPED);
|
|
|
|
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
|
|
|
|
SDL_SetError("Stopped set state failed");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* destroy buffer queue audio player object, and invalidate all associated interfaces */
|
|
|
|
|
|
|
|
if (bqPlayerObject != NULL) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(*bqPlayerObject)->Destroy(bqPlayerObject);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bqPlayerObject = NULL;
|
|
|
|
|
|
|
|
bqPlayerPlay = NULL;
|
|
|
|
|
|
|
|
bqPlayerBufferQueue = NULL;
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
|
|
|
bqPlayerEffectSend = NULL;
|
|
|
|
|
|
|
|
bqPlayerMuteSolo = NULL;
|
|
|
|
|
|
|
|
bqPlayerVolume = NULL;
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (audiodata->playsem) {
|
|
|
|
|
|
|
|
SDL_DestroySemaphore(audiodata->playsem);
|
|
|
|
|
|
|
|
audiodata->playsem = NULL;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (audiodata->mixbuff) {
|
|
|
|
|
|
|
|
SDL_free(audiodata->mixbuff);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
static int
|
|
|
|
openslES_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
|
|
|
openslES_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -494,44 +595,46 @@ openslES_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (iscapture) {
|
|
|
|
if (iscapture) {
|
|
|
|
LOGI("openslES_OpenDevice( ) %s for capture", devname);
|
|
|
|
LOGI("openslES_OpenDevice() %s for capture", devname);
|
|
|
|
return openslES_CreatePCMRecorder(this);
|
|
|
|
return openslES_CreatePCMRecorder(this);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
LOGI("openslES_OpenDevice( ) %s for playing", devname);
|
|
|
|
LOGI("openslES_OpenDevice() %s for playing", devname);
|
|
|
|
return openslES_CreatePCMPlayer(this);
|
|
|
|
return openslES_CreatePCMPlayer(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
static void
|
|
|
|
openslES_CloseDevice(_THIS)
|
|
|
|
openslES_WaitDevice(_THIS)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
/* struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) this->hidden; */
|
|
|
|
struct SDL_PrivateAudioData *audiodata = this->hidden;
|
|
|
|
|
|
|
|
|
|
|
|
if (this->iscapture) {
|
|
|
|
LOGV("openslES_WaitDevice()");
|
|
|
|
LOGI("openslES_CloseDevice( ) for capture");
|
|
|
|
|
|
|
|
openslES_DestroyPCMRecorder(this);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
LOGI("openslES_CloseDevice( ) for playing");
|
|
|
|
|
|
|
|
openslES_DestroyPCMPlayer(this);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SDL_free(this->hidden);
|
|
|
|
/* Wait for an audio chunk to finish */
|
|
|
|
|
|
|
|
SDL_SemWait(audiodata->playsem);
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
static void
|
|
|
|
openslES_WaitDevice(_THIS)
|
|
|
|
openslES_PlayDevice(_THIS)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) this->hidden;
|
|
|
|
struct SDL_PrivateAudioData *audiodata = this->hidden;
|
|
|
|
|
|
|
|
SLresult result;
|
|
|
|
|
|
|
|
|
|
|
|
LOGV("openslES_WaitDevice( )");
|
|
|
|
LOGV("======openslES_PlayDevice()======");
|
|
|
|
|
|
|
|
|
|
|
|
/* Wait for an audio chunk to finish */
|
|
|
|
/* Queue it up */
|
|
|
|
/* WaitForSingleObject(this->hidden->audio_sem, INFINITE); */
|
|
|
|
result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, audiodata->pmixbuff[audiodata->next_buffer], this->spec.size);
|
|
|
|
SDL_SemWait(audiodata->playsem);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
audiodata->next_buffer++;
|
|
|
|
|
|
|
|
if (audiodata->next_buffer >= NUM_BUFFERS) {
|
|
|
|
|
|
|
|
audiodata->next_buffer = 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* If Enqueue fails, callback won't be called.
|
|
|
|
|
|
|
|
* Post the semphore, not to run out of buffer */
|
|
|
|
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
|
|
|
|
SDL_SemPost(audiodata->playsem);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*/ n playn sem */
|
|
|
|
/*/ n playn sem */
|
|
|
@ -549,35 +652,54 @@ openslES_WaitDevice(_THIS)
|
|
|
|
static Uint8 *
|
|
|
|
static Uint8 *
|
|
|
|
openslES_GetDeviceBuf(_THIS)
|
|
|
|
openslES_GetDeviceBuf(_THIS)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) this->hidden;
|
|
|
|
struct SDL_PrivateAudioData *audiodata = this->hidden;
|
|
|
|
|
|
|
|
|
|
|
|
LOGV("openslES_GetDeviceBuf( )");
|
|
|
|
LOGV("openslES_GetDeviceBuf()");
|
|
|
|
return audiodata->pmixbuff[audiodata->next_buffer];
|
|
|
|
return audiodata->pmixbuff[audiodata->next_buffer];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
static int
|
|
|
|
openslES_PlayDevice(_THIS)
|
|
|
|
openslES_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) this->hidden;
|
|
|
|
struct SDL_PrivateAudioData *audiodata = this->hidden;
|
|
|
|
SLresult result;
|
|
|
|
SLresult result;
|
|
|
|
|
|
|
|
|
|
|
|
LOGV("======openslES_PlayDevice( )======");
|
|
|
|
/* Wait for new recorded data */
|
|
|
|
|
|
|
|
SDL_SemWait(audiodata->playsem);
|
|
|
|
|
|
|
|
|
|
|
|
/* Queue it up */
|
|
|
|
/* Copy it to the output buffer */
|
|
|
|
result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, audiodata->pmixbuff[audiodata->next_buffer], this->spec.size);
|
|
|
|
SDL_assert(buflen == this->spec.size);
|
|
|
|
|
|
|
|
SDL_memcpy(buffer, audiodata->pmixbuff[audiodata->next_buffer], this->spec.size);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Re-enqueue the buffer */
|
|
|
|
|
|
|
|
result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, audiodata->pmixbuff[audiodata->next_buffer], this->spec.size);
|
|
|
|
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
|
|
|
|
LOGE("Record enqueue buffers failed: %d", result);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
audiodata->next_buffer++;
|
|
|
|
audiodata->next_buffer++;
|
|
|
|
if (audiodata->next_buffer >= NUM_BUFFERS) {
|
|
|
|
if (audiodata->next_buffer >= NUM_BUFFERS) {
|
|
|
|
audiodata->next_buffer = 0;
|
|
|
|
audiodata->next_buffer = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* If Enqueue fails, callback won't be called.
|
|
|
|
return this->spec.size;
|
|
|
|
* Post the semphore, not to run out of buffer */
|
|
|
|
}
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
|
|
|
|
SDL_SemPost(audiodata->playsem);
|
|
|
|
static void
|
|
|
|
|
|
|
|
openslES_CloseDevice(_THIS)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
/* struct SDL_PrivateAudioData *audiodata = this->hidden; */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (this->iscapture) {
|
|
|
|
|
|
|
|
LOGI("openslES_CloseDevice() for capture");
|
|
|
|
|
|
|
|
openslES_DestroyPCMRecorder(this);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
LOGI("openslES_CloseDevice() for playing");
|
|
|
|
|
|
|
|
openslES_DestroyPCMPlayer(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
SDL_free(this->hidden);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
static int
|
|
|
@ -594,18 +716,19 @@ openslES_Init(SDL_AudioDriverImpl * impl)
|
|
|
|
/* Set the function pointers */
|
|
|
|
/* Set the function pointers */
|
|
|
|
/* impl->DetectDevices = openslES_DetectDevices; */
|
|
|
|
/* impl->DetectDevices = openslES_DetectDevices; */
|
|
|
|
impl->OpenDevice = openslES_OpenDevice;
|
|
|
|
impl->OpenDevice = openslES_OpenDevice;
|
|
|
|
impl->CloseDevice = openslES_CloseDevice;
|
|
|
|
impl->WaitDevice = openslES_WaitDevice;
|
|
|
|
impl->PlayDevice = openslES_PlayDevice;
|
|
|
|
impl->PlayDevice = openslES_PlayDevice;
|
|
|
|
impl->GetDeviceBuf = openslES_GetDeviceBuf;
|
|
|
|
impl->GetDeviceBuf = openslES_GetDeviceBuf;
|
|
|
|
|
|
|
|
impl->CaptureFromDevice = openslES_CaptureFromDevice;
|
|
|
|
|
|
|
|
impl->CloseDevice = openslES_CloseDevice;
|
|
|
|
impl->Deinitialize = openslES_DestroyEngine;
|
|
|
|
impl->Deinitialize = openslES_DestroyEngine;
|
|
|
|
impl->WaitDevice = openslES_WaitDevice;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* and the capabilities */
|
|
|
|
/* and the capabilities */
|
|
|
|
impl->HasCaptureSupport = 0; /* TODO */
|
|
|
|
impl->HasCaptureSupport = 1;
|
|
|
|
impl->OnlyHasDefaultOutputDevice = 1;
|
|
|
|
impl->OnlyHasDefaultOutputDevice = 1;
|
|
|
|
/* impl->OnlyHasDefaultInputDevice = 1; */
|
|
|
|
impl->OnlyHasDefaultCaptureDevice = 1;
|
|
|
|
|
|
|
|
|
|
|
|
LOGI("openslES_Init() - succes");
|
|
|
|
LOGI("openslES_Init() - success");
|
|
|
|
|
|
|
|
|
|
|
|
/* this audio target is available. */
|
|
|
|
/* this audio target is available. */
|
|
|
|
return 1;
|
|
|
|
return 1;
|
|
|
@ -615,24 +738,24 @@ AudioBootStrap openslES_bootstrap = {
|
|
|
|
"openslES", "opensl ES audio driver", openslES_Init, 0
|
|
|
|
"openslES", "opensl ES audio driver", openslES_Init, 0
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
void openslES_ResumeDevices()
|
|
|
|
void openslES_ResumeDevices(void)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (bqPlayerPlay != NULL) {
|
|
|
|
if (bqPlayerPlay != NULL) {
|
|
|
|
/* set the player's state to 'playing' */
|
|
|
|
/* set the player's state to 'playing' */
|
|
|
|
SLresult result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
|
|
|
|
SLresult result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
SDL_SetError("openslES_ResumeDevices failed");
|
|
|
|
LOGE("openslES_ResumeDevices failed: %d", result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void openslES_PauseDevices()
|
|
|
|
void openslES_PauseDevices(void)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (bqPlayerPlay != NULL) {
|
|
|
|
if (bqPlayerPlay != NULL) {
|
|
|
|
/* set the player's state to 'paused' */
|
|
|
|
/* set the player's state to 'paused' */
|
|
|
|
SLresult result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PAUSED);
|
|
|
|
SLresult result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PAUSED);
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
|
|
SDL_SetError("openslES_PauseDevices failed");
|
|
|
|
LOGE("openslES_PauseDevices failed: %d", result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|