mirror of https://github.com/encounter/SDL.git
Initial Android OpenSL ES implementation, contributed by ANTA
This commit is contained in:
parent
fb8cb95fbc
commit
7dc92a7669
|
@ -20,6 +20,7 @@ LOCAL_SRC_FILES := \
|
||||||
$(wildcard $(LOCAL_PATH)/src/audio/*.c) \
|
$(wildcard $(LOCAL_PATH)/src/audio/*.c) \
|
||||||
$(wildcard $(LOCAL_PATH)/src/audio/android/*.c) \
|
$(wildcard $(LOCAL_PATH)/src/audio/android/*.c) \
|
||||||
$(wildcard $(LOCAL_PATH)/src/audio/dummy/*.c) \
|
$(wildcard $(LOCAL_PATH)/src/audio/dummy/*.c) \
|
||||||
|
$(wildcard $(LOCAL_PATH)/src/audio/openslES/*.c) \
|
||||||
$(LOCAL_PATH)/src/atomic/SDL_atomic.c.arm \
|
$(LOCAL_PATH)/src/atomic/SDL_atomic.c.arm \
|
||||||
$(LOCAL_PATH)/src/atomic/SDL_spinlock.c.arm \
|
$(LOCAL_PATH)/src/atomic/SDL_spinlock.c.arm \
|
||||||
$(wildcard $(LOCAL_PATH)/src/core/android/*.c) \
|
$(wildcard $(LOCAL_PATH)/src/core/android/*.c) \
|
||||||
|
@ -69,7 +70,7 @@ LOCAL_CFLAGS += \
|
||||||
LOCAL_CFLAGS += -Wno-unused-parameter -Wno-sign-compare
|
LOCAL_CFLAGS += -Wno-unused-parameter -Wno-sign-compare
|
||||||
|
|
||||||
|
|
||||||
LOCAL_LDLIBS := -ldl -lGLESv1_CM -lGLESv2 -llog -landroid
|
LOCAL_LDLIBS := -ldl -lGLESv1_CM -lGLESv2 -lOpenSLES -llog -landroid
|
||||||
|
|
||||||
ifeq ($(NDK_DEBUG),1)
|
ifeq ($(NDK_DEBUG),1)
|
||||||
cmd-strip :=
|
cmd-strip :=
|
||||||
|
|
|
@ -130,6 +130,7 @@
|
||||||
|
|
||||||
/* Enable various audio drivers */
|
/* Enable various audio drivers */
|
||||||
#define SDL_AUDIO_DRIVER_ANDROID 1
|
#define SDL_AUDIO_DRIVER_ANDROID 1
|
||||||
|
#define SDL_AUDIO_DRIVER_OPENSLES 1
|
||||||
#define SDL_AUDIO_DRIVER_DUMMY 1
|
#define SDL_AUDIO_DRIVER_DUMMY 1
|
||||||
|
|
||||||
/* Enable various input drivers */
|
/* Enable various input drivers */
|
||||||
|
|
|
@ -92,6 +92,9 @@ static const AudioBootStrap *const bootstrap[] = {
|
||||||
#if SDL_AUDIO_DRIVER_ANDROID
|
#if SDL_AUDIO_DRIVER_ANDROID
|
||||||
&ANDROIDAUDIO_bootstrap,
|
&ANDROIDAUDIO_bootstrap,
|
||||||
#endif
|
#endif
|
||||||
|
#if SDL_AUDIO_DRIVER_OPENSLES
|
||||||
|
&openslES_bootstrap,
|
||||||
|
#endif
|
||||||
#if SDL_AUDIO_DRIVER_PSP
|
#if SDL_AUDIO_DRIVER_PSP
|
||||||
&PSPAUDIO_bootstrap,
|
&PSPAUDIO_bootstrap,
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -205,6 +205,7 @@ extern AudioBootStrap DISKAUDIO_bootstrap;
|
||||||
extern AudioBootStrap DUMMYAUDIO_bootstrap;
|
extern AudioBootStrap DUMMYAUDIO_bootstrap;
|
||||||
extern AudioBootStrap FUSIONSOUND_bootstrap;
|
extern AudioBootStrap FUSIONSOUND_bootstrap;
|
||||||
extern AudioBootStrap ANDROIDAUDIO_bootstrap;
|
extern AudioBootStrap ANDROIDAUDIO_bootstrap;
|
||||||
|
extern AudioBootStrap openslES_bootstrap;
|
||||||
extern AudioBootStrap PSPAUDIO_bootstrap;
|
extern AudioBootStrap PSPAUDIO_bootstrap;
|
||||||
extern AudioBootStrap EMSCRIPTENAUDIO_bootstrap;
|
extern AudioBootStrap EMSCRIPTENAUDIO_bootstrap;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,573 @@
|
||||||
|
/*
|
||||||
|
Simple DirectMedia Layer
|
||||||
|
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
#include "../../SDL_internal.h"
|
||||||
|
|
||||||
|
#if SDL_AUDIO_DRIVER_OPENSLES
|
||||||
|
|
||||||
|
#include "SDL_audio.h"
|
||||||
|
#include "../SDL_audio_c.h"
|
||||||
|
#include "SDL_openslES.h"
|
||||||
|
|
||||||
|
// for native audio
|
||||||
|
#include <SLES/OpenSLES.h>
|
||||||
|
#include <SLES/OpenSLES_Android.h>
|
||||||
|
|
||||||
|
#include <android/log.h>
|
||||||
|
|
||||||
|
#define LOG_TAG "SDL_openslES"
|
||||||
|
|
||||||
|
//#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
|
||||||
|
//#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
|
||||||
|
//#define LOGI(...) do {} while (0)
|
||||||
|
//#define LOGE(...) do {} while (0)
|
||||||
|
#define LOGI(...)
|
||||||
|
#define LOGE(...)
|
||||||
|
|
||||||
|
// engine interfaces
|
||||||
|
static SLObjectItf engineObject = NULL;
|
||||||
|
static SLEngineItf engineEngine;
|
||||||
|
|
||||||
|
// output mix interfaces
|
||||||
|
static SLObjectItf outputMixObject = NULL;
|
||||||
|
//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
|
||||||
|
static SLObjectItf bqPlayerObject = NULL;
|
||||||
|
static SLPlayItf bqPlayerPlay;
|
||||||
|
static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue;
|
||||||
|
//static SLEffectSendItf bqPlayerEffectSend;
|
||||||
|
static SLMuteSoloItf bqPlayerMuteSolo;
|
||||||
|
static SLVolumeItf bqPlayerVolume;
|
||||||
|
|
||||||
|
// recorder interfaces TODO
|
||||||
|
static SLObjectItf recorderObject = NULL;
|
||||||
|
static SLRecordItf recorderRecord;
|
||||||
|
static SLAndroidSimpleBufferQueueItf recorderBufferQueue;
|
||||||
|
|
||||||
|
// pointer and size of the next player buffer to enqueue, and number of remaining buffers
|
||||||
|
static short *nextBuffer;
|
||||||
|
static unsigned nextSize;
|
||||||
|
static int nextCount;
|
||||||
|
|
||||||
|
static const char *sldevaudiorecorderstr = "SLES Audio Recorder";
|
||||||
|
static const char *sldevaudioplayerstr = "SLES Audio Player";
|
||||||
|
|
||||||
|
#define SLES_DEV_AUDIO_RECORDER sldevaudiorecorderstr
|
||||||
|
#define SLES_DEV_AUDIO_PLAYER sldevaudioplayerstr
|
||||||
|
|
||||||
|
#define NUM_BUFFERS 2 /* -- Don't lower this! */
|
||||||
|
|
||||||
|
static Uint8 *mixbuff = NULL;
|
||||||
|
static int next_buffer = 0;
|
||||||
|
static Uint8 *pmixbuff[NUM_BUFFERS];
|
||||||
|
|
||||||
|
static SDL_sem *playsem = NULL, *recsem = NULL;
|
||||||
|
|
||||||
|
//static SDL_AudioDevice* audioDevice = NULL;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static void openslES_DetectDevices( int iscapture )
|
||||||
|
{
|
||||||
|
LOGI( "openSLES_DetectDevices()" );
|
||||||
|
if ( iscapture )
|
||||||
|
addfn( SLES_DEV_AUDIO_RECORDER );
|
||||||
|
else
|
||||||
|
addfn( SLES_DEV_AUDIO_PLAYER );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void openslES_DestroyEngine( void );
|
||||||
|
|
||||||
|
static int openslES_CreateEngine( void )
|
||||||
|
{
|
||||||
|
SLresult result;
|
||||||
|
|
||||||
|
LOGI( "openSLES_CreateEngine()" );
|
||||||
|
|
||||||
|
// create engine
|
||||||
|
result = slCreateEngine( &engineObject, 0, NULL, 0, NULL, NULL );
|
||||||
|
if ( SL_RESULT_SUCCESS != result ) {
|
||||||
|
|
||||||
|
LOGE( "slCreateEngine failed" );
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGI( "slCreateEngine OK" );
|
||||||
|
|
||||||
|
// realize the engine
|
||||||
|
result = (*engineObject)->Realize( engineObject, SL_BOOLEAN_FALSE );
|
||||||
|
if ( SL_RESULT_SUCCESS != result ) {
|
||||||
|
|
||||||
|
LOGE( "RealizeEngine failed" );
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGI( "RealizeEngine OK" );
|
||||||
|
|
||||||
|
// get the engine interface, which is needed in order to create other objects
|
||||||
|
result = (*engineObject)->GetInterface( engineObject, SL_IID_ENGINE, &engineEngine );
|
||||||
|
if ( SL_RESULT_SUCCESS != result ) {
|
||||||
|
|
||||||
|
LOGE( "EngineGetInterface failed" );
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGI( "EngineGetInterface OK" );
|
||||||
|
|
||||||
|
// create output mix, with environmental reverb specified as a non-required interface
|
||||||
|
// const SLInterfaceID ids[1] = { SL_IID_ENVIRONMENTALREVERB };
|
||||||
|
// const SLboolean req[1] = { SL_BOOLEAN_FALSE };
|
||||||
|
|
||||||
|
const SLInterfaceID ids[1] = { SL_IID_VOLUME };
|
||||||
|
const SLboolean req[1] = { SL_BOOLEAN_FALSE };
|
||||||
|
result = (*engineEngine)->CreateOutputMix( engineEngine, &outputMixObject, 1, ids, req );
|
||||||
|
|
||||||
|
if ( SL_RESULT_SUCCESS != result ) {
|
||||||
|
|
||||||
|
LOGE( "CreateOutputMix failed" );
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
LOGI( "CreateOutputMix OK" );
|
||||||
|
|
||||||
|
// realize the output mix
|
||||||
|
result = (*outputMixObject)->Realize( outputMixObject, SL_BOOLEAN_FALSE );
|
||||||
|
if ( SL_RESULT_SUCCESS != result ) {
|
||||||
|
|
||||||
|
LOGE( "RealizeOutputMix failed" );
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
error:;
|
||||||
|
openslES_DestroyEngine( );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void openslES_DestroyPCMPlayer( void );
|
||||||
|
static void openslES_DestroyPCMRecorder( void );
|
||||||
|
|
||||||
|
static void openslES_DestroyEngine( void )
|
||||||
|
{
|
||||||
|
LOGI( "openslES_DestroyEngine()" );
|
||||||
|
|
||||||
|
openslES_DestroyPCMPlayer( );
|
||||||
|
openslES_DestroyPCMRecorder( );
|
||||||
|
|
||||||
|
// destroy output mix object, and invalidate all associated interfaces
|
||||||
|
if ( outputMixObject != NULL ) {
|
||||||
|
|
||||||
|
(*outputMixObject)->Destroy( outputMixObject );
|
||||||
|
outputMixObject = NULL;
|
||||||
|
// outputMixEnvironmentalReverb = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// destroy engine object, and invalidate all associated interfaces
|
||||||
|
if (engineObject != NULL) {
|
||||||
|
|
||||||
|
(*engineObject)->Destroy( engineObject );
|
||||||
|
engineObject = NULL;
|
||||||
|
engineEngine = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this callback handler is called every time a buffer finishes playing
|
||||||
|
static void bqPlayerCallback( SLAndroidSimpleBufferQueueItf bq, void *context )
|
||||||
|
{
|
||||||
|
static int t = 0;
|
||||||
|
// assert(bq == bqPlayerBufferQueue);
|
||||||
|
// assert(NULL == context);
|
||||||
|
|
||||||
|
// for streaming playback, replace this test by logic to find and fill the next buffer
|
||||||
|
#if 0
|
||||||
|
if (--nextCount > 0 && NULL != nextBuffer && 0 != nextSize) {
|
||||||
|
SLresult result;
|
||||||
|
// enqueue another buffer
|
||||||
|
result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, nextBuffer, nextSize);
|
||||||
|
// the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT,
|
||||||
|
// which for this code example would indicate a programming error
|
||||||
|
assert(SL_RESULT_SUCCESS == result);
|
||||||
|
(void)result;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
LOGI( "SLES: Playback Callmeback %u", t++ );
|
||||||
|
|
||||||
|
SDL_SemPost( playsem );
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int openslES_CreatePCMRecorder( _THIS )
|
||||||
|
{
|
||||||
|
LOGE( "openslES_CreatePCMRecorder not implimented yet!" );
|
||||||
|
return SDL_SetError( "openslES_CreatePCMRecorder not implimented yet!" );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void openslES_DestroyPCMRecorder( void )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int openslES_CreatePCMPlayer( _THIS )
|
||||||
|
{
|
||||||
|
SLDataFormat_PCM format_pcm;
|
||||||
|
SDL_AudioFormat test_format;
|
||||||
|
SLresult result;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
test_format = SDL_FirstAudioFormat( this->spec.format );
|
||||||
|
|
||||||
|
while ( test_format != 0 ) {
|
||||||
|
|
||||||
|
if ( SDL_AUDIO_ISSIGNED(test_format) && SDL_AUDIO_ISINT(test_format ) ) break;
|
||||||
|
test_format = SDL_NextAudioFormat( );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( test_format == 0 ) {
|
||||||
|
|
||||||
|
// Didn't find a compatible format :(
|
||||||
|
LOGI( "No compatible audio format!" );
|
||||||
|
return SDL_SetError("No compatible audio format!");
|
||||||
|
}
|
||||||
|
|
||||||
|
this->spec.format = test_format;
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 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, (test_format&0x1000) ? "BE" : "LE", this->spec.samples
|
||||||
|
);
|
||||||
|
|
||||||
|
// configure audio source
|
||||||
|
SLDataLocator_AndroidSimpleBufferQueue loc_bufq = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2 };
|
||||||
|
// SLDataLocator_AndroidSimpleBufferQueue loc_bufq = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, OPENSLES_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 );
|
||||||
|
|
||||||
|
if ( SDL_AUDIO_ISBIGENDIAN( this->spec.format ) )
|
||||||
|
format_pcm.endianness = SL_BYTEORDER_BIGENDIAN;
|
||||||
|
else
|
||||||
|
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)
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ( this->spec.channels == 1 )
|
||||||
|
format_pcm.channelMask = SL_SPEAKER_FRONT_CENTER;
|
||||||
|
else if ( this->spec.channels == 2 )
|
||||||
|
format_pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
|
||||||
|
else if ( this->spec.channels == 3 )
|
||||||
|
format_pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | SL_SPEAKER_FRONT_CENTER;
|
||||||
|
else if ( this->spec.channels == 4 )
|
||||||
|
format_pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT |
|
||||||
|
SL_SPEAKER_BACK_LEFT | SL_SPEAKER_BACK_RIGHT;
|
||||||
|
else
|
||||||
|
format_pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT |
|
||||||
|
SL_SPEAKER_BACK_LEFT | SL_SPEAKER_BACK_RIGHT |
|
||||||
|
SL_SPEAKER_FRONT_CENTER;
|
||||||
|
|
||||||
|
SLDataSource audioSrc = { &loc_bufq, &format_pcm };
|
||||||
|
|
||||||
|
// configure audio sink
|
||||||
|
SLDataLocator_OutputMix loc_outmix = { SL_DATALOCATOR_OUTPUTMIX, outputMixObject };
|
||||||
|
SLDataSink audioSnk = { &loc_outmix, NULL };
|
||||||
|
|
||||||
|
// create audio player
|
||||||
|
const SLInterfaceID ids[2] = {
|
||||||
|
SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
|
||||||
|
SL_IID_VOLUME
|
||||||
|
};
|
||||||
|
|
||||||
|
const SLboolean req[2] = {
|
||||||
|
SL_BOOLEAN_TRUE,
|
||||||
|
SL_BOOLEAN_FALSE,
|
||||||
|
};
|
||||||
|
|
||||||
|
result = (*engineEngine)->CreateAudioPlayer( engineEngine, &bqPlayerObject, &audioSrc, &audioSnk,
|
||||||
|
2, ids, req );
|
||||||
|
if ( SL_RESULT_SUCCESS != result ) {
|
||||||
|
|
||||||
|
LOGE( "CreateAudioPlayer failed" );
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// realize the player
|
||||||
|
result = (*bqPlayerObject)->Realize( bqPlayerObject, SL_BOOLEAN_FALSE );
|
||||||
|
if ( SL_RESULT_SUCCESS != result ) {
|
||||||
|
|
||||||
|
LOGE( "RealizeAudioPlayer failed" );
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the play interface
|
||||||
|
result = (*bqPlayerObject)->GetInterface( bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay );
|
||||||
|
if ( SL_RESULT_SUCCESS != result ) {
|
||||||
|
|
||||||
|
LOGE( "SL_IID_PLAY interface get failed" );
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the buffer queue interface
|
||||||
|
result = (*bqPlayerObject)->GetInterface( bqPlayerObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bqPlayerBufferQueue );
|
||||||
|
if ( SL_RESULT_SUCCESS != result ) {
|
||||||
|
|
||||||
|
LOGE( "SL_IID_BUFFERQUEUE interface get failed" );
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// register callback on the buffer queue
|
||||||
|
result = (*bqPlayerBufferQueue)->RegisterCallback( bqPlayerBufferQueue, bqPlayerCallback, NULL );
|
||||||
|
if ( SL_RESULT_SUCCESS != result ) {
|
||||||
|
|
||||||
|
LOGE( "RegisterCallback 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
|
||||||
|
|
||||||
|
// get the volume interface
|
||||||
|
result = (*bqPlayerObject)->GetInterface( bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume );
|
||||||
|
if ( SL_RESULT_SUCCESS != result ) {
|
||||||
|
|
||||||
|
LOGE( "SL_IID_VOLUME interface get failed" );
|
||||||
|
// goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the player's state to playing
|
||||||
|
result = (*bqPlayerPlay)->SetPlayState( bqPlayerPlay, SL_PLAYSTATE_PLAYING );
|
||||||
|
if ( SL_RESULT_SUCCESS != result ) {
|
||||||
|
|
||||||
|
LOGE( "Play set state failed" );
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create the audio buffer semaphore */
|
||||||
|
playsem = SDL_CreateSemaphore( NUM_BUFFERS - 1 );
|
||||||
|
if ( !playsem ) {
|
||||||
|
|
||||||
|
LOGE( "cannot create Semaphore!" );
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create the sound buffers */
|
||||||
|
mixbuff = (Uint8 *) SDL_malloc( NUM_BUFFERS * this->spec.size );
|
||||||
|
if ( mixbuff == NULL) {
|
||||||
|
|
||||||
|
LOGE( "mixbuffer allocate - out of memory" );
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( i = 0; i < NUM_BUFFERS; i ++ )
|
||||||
|
pmixbuff[i] = mixbuff + i * this->spec.size;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
failed:;
|
||||||
|
|
||||||
|
openslES_DestroyPCMPlayer( );
|
||||||
|
|
||||||
|
return SDL_SetError( "Open device failed!" );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void openslES_DestroyPCMPlayer( void )
|
||||||
|
{
|
||||||
|
// destroy buffer queue audio player object, and invalidate all associated interfaces
|
||||||
|
if ( bqPlayerObject != NULL ) {
|
||||||
|
|
||||||
|
(*bqPlayerObject)->Destroy( bqPlayerObject );
|
||||||
|
|
||||||
|
bqPlayerObject = NULL;
|
||||||
|
bqPlayerPlay = NULL;
|
||||||
|
bqPlayerBufferQueue = NULL;
|
||||||
|
// bqPlayerEffectSend = NULL;
|
||||||
|
bqPlayerMuteSolo = NULL;
|
||||||
|
bqPlayerVolume = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( playsem ) {
|
||||||
|
|
||||||
|
SDL_DestroySemaphore( playsem );
|
||||||
|
playsem = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( mixbuff )
|
||||||
|
SDL_free( mixbuff );
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int openslES_OpenDevice( _THIS, void *handle, const char *devname, int iscapture )
|
||||||
|
{
|
||||||
|
if ( iscapture ) {
|
||||||
|
LOGI( "openslES_OpenDevice( ) %s for capture", devname );
|
||||||
|
return openslES_CreatePCMRecorder( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGI( "openslES_OpenDevice( ) %s for playing", devname );
|
||||||
|
|
||||||
|
return openslES_CreatePCMPlayer( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void openslES_CloseDevice( _THIS )
|
||||||
|
{
|
||||||
|
if ( this->iscapture ) {
|
||||||
|
LOGI( "openslES_CloseDevice( ) for capture" );
|
||||||
|
return openslES_DestroyPCMRecorder( );
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGI( "openslES_CloseDevice( ) for playing" );
|
||||||
|
openslES_DestroyPCMPlayer( );
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void openslES_WaitDevice( _THIS )
|
||||||
|
{
|
||||||
|
LOGI( "openslES_WaitDevice( )" );
|
||||||
|
|
||||||
|
/* Wait for an audio chunk to finish */
|
||||||
|
// WaitForSingleObject(this->hidden->audio_sem, INFINITE);
|
||||||
|
SDL_SemWait( playsem );
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// n playn sem
|
||||||
|
// getbuf 0 - 1
|
||||||
|
// fill buff 0 - 1
|
||||||
|
// play 0 - 0 1
|
||||||
|
// wait 1 0 0
|
||||||
|
// getbuf 1 0 0
|
||||||
|
// fill buff 1 0 0
|
||||||
|
// play 0 0 0
|
||||||
|
// wait
|
||||||
|
//
|
||||||
|
// okay..
|
||||||
|
|
||||||
|
|
||||||
|
static Uint8 *openslES_GetDeviceBuf( _THIS )
|
||||||
|
{
|
||||||
|
LOGI( "openslES_GetDeviceBuf( )" );
|
||||||
|
|
||||||
|
return pmixbuff[next_buffer];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void openslES_PlayDevice( _THIS )
|
||||||
|
{
|
||||||
|
SLresult result;
|
||||||
|
|
||||||
|
LOGI( "======openslES_PlayDevice( )======" );
|
||||||
|
/* Queue it up */
|
||||||
|
|
||||||
|
result = (*bqPlayerBufferQueue)->Enqueue( bqPlayerBufferQueue, pmixbuff[next_buffer], this->spec.size );
|
||||||
|
if ( SL_RESULT_SUCCESS != result ) {
|
||||||
|
// just puk here
|
||||||
|
// next !
|
||||||
|
}
|
||||||
|
|
||||||
|
next_buffer ++;
|
||||||
|
if ( next_buffer >= NUM_BUFFERS ) next_buffer = 0;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int openslES_Init( SDL_AudioDriverImpl * impl )
|
||||||
|
{
|
||||||
|
LOGI( "openslES_Init() called" );
|
||||||
|
|
||||||
|
if ( !openslES_CreateEngine() ) return 0;
|
||||||
|
|
||||||
|
LOGI( "openslES_Init() - set pointers" );
|
||||||
|
|
||||||
|
/* Set the function pointers */
|
||||||
|
// impl->DetectDevices = openslES_DetectDevices;
|
||||||
|
impl->OpenDevice = openslES_OpenDevice;
|
||||||
|
impl->PlayDevice = openslES_PlayDevice;
|
||||||
|
impl->GetDeviceBuf = openslES_GetDeviceBuf;
|
||||||
|
impl->Deinitialize = openslES_DestroyEngine;
|
||||||
|
impl->WaitDevice = openslES_WaitDevice;
|
||||||
|
|
||||||
|
/* and the capabilities */
|
||||||
|
impl->HasCaptureSupport = 0; /* TODO */
|
||||||
|
impl->OnlyHasDefaultOutputDevice = 1;
|
||||||
|
// impl->OnlyHasDefaultInputDevice = 1;
|
||||||
|
|
||||||
|
LOGI( "openslES_Init() - succes" );
|
||||||
|
|
||||||
|
return 1; /* this audio target is available. */
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioBootStrap openslES_bootstrap = {
|
||||||
|
"openslES", "opensl ES audio driver", openslES_Init, 0
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* SDL_AUDIO_DRIVER_OPENSLES */
|
||||||
|
|
||||||
|
/* vi: set ts=4 sw=4 expandtab: */
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
Simple DirectMedia Layer
|
||||||
|
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
#include "../../SDL_internal.h"
|
||||||
|
|
||||||
|
#ifndef _SDL_openslesaudio_h
|
||||||
|
#define _SDL_openslesaudio_h
|
||||||
|
|
||||||
|
#include "../SDL_sysaudio.h"
|
||||||
|
|
||||||
|
/* Hidden "this" pointer for the audio functions */
|
||||||
|
#define _THIS SDL_AudioDevice *this
|
||||||
|
|
||||||
|
struct SDL_PrivateAudioData
|
||||||
|
{
|
||||||
|
/* The file descriptor for the audio device */
|
||||||
|
Uint8 *mixbuf;
|
||||||
|
Uint32 mixlen;
|
||||||
|
Uint32 write_delay;
|
||||||
|
Uint32 initial_calls;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _SDL_openslesaudio_h */
|
||||||
|
|
||||||
|
/* vi: set ts=4 sw=4 expandtab: */
|
Loading…
Reference in New Issue