Modification for Android build (NDK r14b, build-tools 21.1.2 and gradle 2.2.1) (#2585)

This commit is contained in:
Miso Kim 2017-08-23 12:09:38 +09:00 committed by Vas Crabb
parent 1de4735438
commit 41e044ae01
15 changed files with 1237 additions and 63 deletions

View File

@ -31,10 +31,13 @@
#include "../../core/android/SDL_android.h"
#include "opensl_io.h"
#include <android/log.h>
static SDL_AudioDevice* audioDevice = NULL;
static SDL_AudioDevice* captureDevice = NULL;
static OPENSL_STREAM *sl = NULL;
static int
ANDROIDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
@ -57,7 +60,8 @@ ANDROIDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
test_format = SDL_FirstAudioFormat(this->spec.format);
while (test_format != 0) { /* no "UNKNOWN" constant */
if ((test_format == AUDIO_U8) || (test_format == AUDIO_S16LSB)) {
// if ((test_format == AUDIO_U8) || (test_format == AUDIO_S16LSB)) {
if (test_format == AUDIO_S16MSB) {
this->spec.format = test_format;
break;
}
@ -75,20 +79,32 @@ ANDROIDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
this->spec.channels = 1;
}
#if 0
if (this->spec.freq < 8000) {
this->spec.freq = 8000;
}
if (this->spec.freq > 48000) {
this->spec.freq = 48000;
}
#endif
/* TODO: pass in/return a (Java) device ID */
this->spec.samples = Android_JNI_OpenAudioDevice(iscapture, this->spec.freq, this->spec.format == AUDIO_U8 ? 0 : 1, this->spec.channels, this->spec.samples);
if (this->spec.samples == 0) {
/* Init failed? */
return SDL_SetError("Java-side initialization failed!");
}
//this->spec.samples = Android_JNI_OpenAudioDevice(iscapture, this->spec.freq, this->spec.format == AUDIO_U8 ? 0 : 1, this->spec.channels, this->spec.samples);
if (!sl & !iscapture)
{
if (this->spec.size != 0)
{
// this->spec.samples = this->spec.size / this->spec.channels / 2;
} else {
this->spec.samples = 400;
this->spec.size = this->spec.channels * this->spec.samples;
}
sl = android_OpenAudioDevice(this->spec.freq, this->spec.channels, this->spec.channels, this->spec.samples);
__android_log_print(ANDROID_LOG_INFO, "SDL", "android_OpenAudioDevice: %x, freq=%d, channels=%d, %d samples", (int)sl, this->spec.freq, this->spec.channels, this->spec.samples);
if (!sl) {
/* Init failed? */
return SDL_SetError("Java-side initialization failed!");
}
}
SDL_CalculateAudioSpec(&this->spec);
@ -98,13 +114,17 @@ ANDROIDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
static void
ANDROIDAUDIO_PlayDevice(_THIS)
{
Android_JNI_WriteAudioBuffer();
//Android_JNI_WriteAudioBuffer();
android_AudioOut2(sl);
}
static Uint8 *
ANDROIDAUDIO_GetDeviceBuf(_THIS)
{
return Android_JNI_GetAudioBuffer();
//return Android_JNI_GetAudioBuffer();
Uint8 *buf = android_GetDeviceBuffer(sl);
// __android_log_print(ANDROID_LOG_INFO, "SDL", "GetDeviceBuf: %x", (int) buf);
return buf;
}
static int
@ -148,9 +168,9 @@ ANDROIDAUDIO_Init(SDL_AudioDriverImpl * impl)
impl->FlushCapture = ANDROIDAUDIO_FlushCapture;
/* and the capabilities */
impl->HasCaptureSupport = SDL_TRUE;
impl->HasCaptureSupport = SDL_FALSE;
impl->OnlyHasDefaultOutputDevice = 1;
impl->OnlyHasDefaultCaptureDevice = 1;
impl->OnlyHasDefaultCaptureDevice = 0;
return 1; /* this audio target is available. */
}

View File

@ -0,0 +1,557 @@
/*
opensl_io.c:
Android OpenSL input/output module
Copyright (c) 2012, Victor Lazzarini
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the <organization> nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <limits.h>
#include "opensl_io.h"
#define CONV16BIT 32768
#define CONVMYFLT (1./32768.)
#include <android/log.h>
#define LOG_TAG "SDL_android"
static void* createThreadLock(void);
static int waitThreadLock(void *lock);
static void notifyThreadLock(void *lock);
static void destroyThreadLock(void *lock);
static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context);
static void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void *context);
// creates the OpenSL ES audio engine
static SLresult openSLCreateEngine(OPENSL_STREAM *p)
{
SLresult result;
// create engine
result = slCreateEngine(&(p->engineObject), 0, NULL, 0, NULL, NULL);
if(result != SL_RESULT_SUCCESS) goto engine_end;
// realize the engine
result = (*p->engineObject)->Realize(p->engineObject, SL_BOOLEAN_FALSE);
if(result != SL_RESULT_SUCCESS) goto engine_end;
// get the engine interface, which is needed in order to create other objects
result = (*p->engineObject)->GetInterface(p->engineObject, SL_IID_ENGINE, &(p->engineEngine));
if(result != SL_RESULT_SUCCESS) goto engine_end;
engine_end:
return result;
}
// opens the OpenSL ES device for output
static SLresult openSLPlayOpen(OPENSL_STREAM *p)
{
SLresult result;
SLuint32 sr = p->sr;
SLuint32 channels = p->outchannels;
if(channels){
// configure audio source
SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};
switch(sr){
case 8000:
sr = SL_SAMPLINGRATE_8;
break;
case 11025:
sr = SL_SAMPLINGRATE_11_025;
break;
case 16000:
sr = SL_SAMPLINGRATE_16;
break;
case 22050:
sr = SL_SAMPLINGRATE_22_05;
break;
case 24000:
sr = SL_SAMPLINGRATE_24;
break;
case 32000:
sr = SL_SAMPLINGRATE_32;
break;
case 44100:
sr = SL_SAMPLINGRATE_44_1;
break;
case 48000:
sr = SL_SAMPLINGRATE_48;
break;
case 64000:
sr = SL_SAMPLINGRATE_64;
break;
case 88200:
sr = SL_SAMPLINGRATE_88_2;
break;
case 96000:
sr = SL_SAMPLINGRATE_96;
break;
case 192000:
sr = SL_SAMPLINGRATE_192;
break;
default:
return -1;
}
const SLInterfaceID ids[] = {SL_IID_VOLUME};
const SLboolean req[] = {SL_BOOLEAN_FALSE};
result = (*p->engineEngine)->CreateOutputMix(p->engineEngine, &(p->outputMixObject), 1, ids, req);
if(result != SL_RESULT_SUCCESS) goto end_openaudio;
// realize the output mix
result = (*p->outputMixObject)->Realize(p->outputMixObject, SL_BOOLEAN_FALSE);
int speakers;
if(channels > 1)
speakers = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
else speakers = SL_SPEAKER_FRONT_CENTER;
SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM,channels, sr,
SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16,
speakers, SL_BYTEORDER_LITTLEENDIAN};
SLDataSource audioSrc = {&loc_bufq, &format_pcm};
// configure audio sink
SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, p->outputMixObject};
SLDataSink audioSnk = {&loc_outmix, NULL};
// create audio player
const SLInterfaceID ids1[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
const SLboolean req1[] = {SL_BOOLEAN_TRUE};
result = (*p->engineEngine)->CreateAudioPlayer(p->engineEngine, &(p->bqPlayerObject), &audioSrc, &audioSnk,
1, ids1, req1);
if(result != SL_RESULT_SUCCESS) goto end_openaudio;
// realize the player
result = (*p->bqPlayerObject)->Realize(p->bqPlayerObject, SL_BOOLEAN_FALSE);
if(result != SL_RESULT_SUCCESS) goto end_openaudio;
// get the play interface
result = (*p->bqPlayerObject)->GetInterface(p->bqPlayerObject, SL_IID_PLAY, &(p->bqPlayerPlay));
if(result != SL_RESULT_SUCCESS) goto end_openaudio;
// get the buffer queue interface
result = (*p->bqPlayerObject)->GetInterface(p->bqPlayerObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
&(p->bqPlayerBufferQueue));
if(result != SL_RESULT_SUCCESS) goto end_openaudio;
// register callback on the buffer queue
result = (*p->bqPlayerBufferQueue)->RegisterCallback(p->bqPlayerBufferQueue, bqPlayerCallback, p);
if(result != SL_RESULT_SUCCESS) goto end_openaudio;
// set the player's state to playing
result = (*p->bqPlayerPlay)->SetPlayState(p->bqPlayerPlay, SL_PLAYSTATE_PLAYING);
end_openaudio:
return result;
}
return SL_RESULT_SUCCESS;
}
// Open the OpenSL ES device for input
static SLresult openSLRecOpen(OPENSL_STREAM *p){
SLresult result;
SLuint32 sr = p->sr;
SLuint32 channels = p->inchannels;
if(channels){
switch(sr){
case 8000:
sr = SL_SAMPLINGRATE_8;
break;
case 11025:
sr = SL_SAMPLINGRATE_11_025;
break;
case 16000:
sr = SL_SAMPLINGRATE_16;
break;
case 22050:
sr = SL_SAMPLINGRATE_22_05;
break;
case 24000:
sr = SL_SAMPLINGRATE_24;
break;
case 32000:
sr = SL_SAMPLINGRATE_32;
break;
case 44100:
sr = SL_SAMPLINGRATE_44_1;
break;
case 48000:
sr = SL_SAMPLINGRATE_48;
break;
case 64000:
sr = SL_SAMPLINGRATE_64;
break;
case 88200:
sr = SL_SAMPLINGRATE_88_2;
break;
case 96000:
sr = SL_SAMPLINGRATE_96;
break;
case 192000:
sr = SL_SAMPLINGRATE_192;
break;
default:
return -1;
}
// 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
int speakers;
if(channels > 1)
speakers = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
else speakers = SL_SPEAKER_FRONT_CENTER;
SLDataLocator_AndroidSimpleBufferQueue loc_bq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};
SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, channels, sr,
SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16,
speakers, SL_BYTEORDER_LITTLEENDIAN};
SLDataSink audioSnk = {&loc_bq, &format_pcm};
// create audio recorder
// (requires the RECORD_AUDIO permission)
const SLInterfaceID id[1] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
const SLboolean req[1] = {SL_BOOLEAN_TRUE};
result = (*p->engineEngine)->CreateAudioRecorder(p->engineEngine, &(p->recorderObject), &audioSrc,
&audioSnk, 1, id, req);
if (SL_RESULT_SUCCESS != result) goto end_recopen;
// realize the audio recorder
result = (*p->recorderObject)->Realize(p->recorderObject, SL_BOOLEAN_FALSE);
if (SL_RESULT_SUCCESS != result) goto end_recopen;
// get the record interface
result = (*p->recorderObject)->GetInterface(p->recorderObject, SL_IID_RECORD, &(p->recorderRecord));
if (SL_RESULT_SUCCESS != result) goto end_recopen;
// get the buffer queue interface
result = (*p->recorderObject)->GetInterface(p->recorderObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
&(p->recorderBufferQueue));
if (SL_RESULT_SUCCESS != result) goto end_recopen;
// register callback on the buffer queue
result = (*p->recorderBufferQueue)->RegisterCallback(p->recorderBufferQueue, bqRecorderCallback,
p);
if (SL_RESULT_SUCCESS != result) goto end_recopen;
result = (*p->recorderRecord)->SetRecordState(p->recorderRecord, SL_RECORDSTATE_RECORDING);
end_recopen:
return result;
}
else return SL_RESULT_SUCCESS;
}
// close the OpenSL IO and destroy the audio engine
static void openSLDestroyEngine(OPENSL_STREAM *p){
// destroy buffer queue audio player object, and invalidate all associated interfaces
if (p->bqPlayerObject != NULL) {
(*p->bqPlayerObject)->Destroy(p->bqPlayerObject);
p->bqPlayerObject = NULL;
p->bqPlayerPlay = NULL;
p->bqPlayerBufferQueue = NULL;
p->bqPlayerEffectSend = NULL;
}
// destroy audio recorder object, and invalidate all associated interfaces
if (p->recorderObject != NULL) {
(*p->recorderObject)->Destroy(p->recorderObject);
p->recorderObject = NULL;
p->recorderRecord = NULL;
p->recorderBufferQueue = NULL;
}
// destroy output mix object, and invalidate all associated interfaces
if (p->outputMixObject != NULL) {
(*p->outputMixObject)->Destroy(p->outputMixObject);
p->outputMixObject = NULL;
}
// destroy engine object, and invalidate all associated interfaces
if (p->engineObject != NULL) {
(*p->engineObject)->Destroy(p->engineObject);
p->engineObject = NULL;
p->engineEngine = NULL;
}
}
// open the android audio device for input and/or output
OPENSL_STREAM *android_OpenAudioDevice(int sr, int inchannels, int outchannels, int bufferframes){
OPENSL_STREAM *p;
p = (OPENSL_STREAM *) calloc(sizeof(OPENSL_STREAM),1);
p->inchannels = inchannels;
p->outchannels = outchannels;
p->sr = sr;
p->inlock = createThreadLock();
p->outlock = createThreadLock();
if((p->outBufSamples = bufferframes*outchannels) != 0) {
if((p->outputBuffer[0] = (short *) calloc(p->outBufSamples, sizeof(short))) == NULL ||
(p->outputBuffer[1] = (short *) calloc(p->outBufSamples, sizeof(short))) == NULL) {
android_CloseAudioDevice(p);
return NULL;
}
__android_log_print(ANDROID_LOG_INFO, "OPENSL", "android_OpenAudioDevice: outBufSamples(%d), %x, %x", p->outBufSamples, (int) p->outputBuffer[0], (int) p->outputBuffer[1]);
}
if((p->inBufSamples = bufferframes*inchannels) != 0){
if((p->inputBuffer[0] = (short *) calloc(p->inBufSamples, sizeof(short))) == NULL ||
(p->inputBuffer[1] = (short *) calloc(p->inBufSamples, sizeof(short))) == NULL){
android_CloseAudioDevice(p);
return NULL;
}
__android_log_print(ANDROID_LOG_INFO, "OPENSL", "android_OpenAudioDevice: inBufSamples(%d)", p->inBufSamples);
}
p->currentInputIndex = 0;
p->currentOutputBuffer = 0;
p->currentInputIndex = p->inBufSamples;
p->currentInputBuffer = 0;
if(openSLCreateEngine(p) != SL_RESULT_SUCCESS) {
android_CloseAudioDevice(p);
return NULL;
}
// __android_log_print(ANDROID_LOG_INFO, "OPENSL", "android_OpenAudioDevice: openSLCreateEngine");
#if 1
if(openSLRecOpen(p) != SL_RESULT_SUCCESS) {
// android_CloseAudioDevice(p);
// return NULL;
}
// __android_log_print(ANDROID_LOG_INFO, "OPENSL", "android_OpenAudioDevice: openSLRecOpen");
#endif
if(openSLPlayOpen(p) != SL_RESULT_SUCCESS) {
android_CloseAudioDevice(p);
return NULL;
}
// __android_log_print(ANDROID_LOG_INFO, "OPENSL", "android_OpenAudioDevice: openSLPlayOpen");
notifyThreadLock(p->outlock);
notifyThreadLock(p->inlock);
p->time = 0.;
return p;
}
// close the android audio device
void android_CloseAudioDevice(OPENSL_STREAM *p){
if (p == NULL)
return;
openSLDestroyEngine(p);
if (p->inlock != NULL) {
notifyThreadLock(p->inlock);
destroyThreadLock(p->inlock);
p->inlock = NULL;
}
if (p->outlock != NULL) {
notifyThreadLock(p->outlock);
destroyThreadLock(p->outlock);
p->inlock = NULL;
}
if (p->outputBuffer[0] != NULL) {
free(p->outputBuffer[0]);
p->outputBuffer[0] = NULL;
}
if (p->outputBuffer[1] != NULL) {
free(p->outputBuffer[1]);
p->outputBuffer[1] = NULL;
}
if (p->inputBuffer[0] != NULL) {
free(p->inputBuffer[0]);
p->inputBuffer[0] = NULL;
}
if (p->inputBuffer[1] != NULL) {
free(p->inputBuffer[1]);
p->inputBuffer[1] = NULL;
}
free(p);
}
// returns timestamp of the processed stream
double android_GetTimestamp(OPENSL_STREAM *p){
return p->time;
}
// this callback handler is called every time a buffer finishes recording
void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
{
OPENSL_STREAM *p = (OPENSL_STREAM *) context;
notifyThreadLock(p->inlock);
}
// gets a buffer of size samples from the device
int android_AudioIn(OPENSL_STREAM *p,float *buffer,int size){
short *inBuffer;
int i, bufsamps = p->inBufSamples, index = p->currentInputIndex;
if(p == NULL || bufsamps == 0) return 0;
inBuffer = p->inputBuffer[p->currentInputBuffer];
for(i=0; i < size; i++){
if (index >= bufsamps) {
waitThreadLock(p->inlock);
(*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue,
inBuffer,bufsamps*sizeof(short));
p->currentInputBuffer = (p->currentInputBuffer ? 0 : 1);
index = 0;
inBuffer = p->inputBuffer[p->currentInputBuffer];
}
buffer[i] = (float) inBuffer[index++]*CONVMYFLT;
}
p->currentInputIndex = index;
if(p->outchannels == 0) p->time += (double) size/(p->sr*p->inchannels);
return i;
}
// this callback handler is called every time a buffer finishes playing
void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
{
OPENSL_STREAM *p = (OPENSL_STREAM *) context;
notifyThreadLock(p->outlock);
}
unsigned char *android_GetDeviceBuffer(OPENSL_STREAM *p)
{
p->currentOutputBuffer = (p->currentOutputBuffer ? 0 : 1);
waitThreadLock(p->outlock);
// __android_log_print(ANDROID_LOG_INFO, "OPENSL", "android_GetDeviceBuffer: buf[%d]=%x", p->currentOutputBuffer, (int) p->outputBuffer[p->currentOutputBuffer]);
return (unsigned char *)p->outputBuffer[p->currentOutputBuffer];
}
void android_AudioOut2(OPENSL_STREAM *p)
{
short *outBuffer = p->outputBuffer[p->currentOutputBuffer];
int bufsamps = p->outBufSamples;
(*p->bqPlayerBufferQueue)->Enqueue(p->bqPlayerBufferQueue, outBuffer, bufsamps*sizeof(short));
}
// puts a buffer of size samples to the device
int android_AudioOut(OPENSL_STREAM *p, float *buffer, int size){
short *outBuffer;
int i, bufsamps = p->outBufSamples, index = p->currentOutputIndex;
if(p == NULL || bufsamps == 0) return 0;
outBuffer = p->outputBuffer[p->currentOutputBuffer];
for (i=0; i < size; i++) {
// clean conversion from float to short int
float x = buffer[i];
if (x>1.0) { x=1.0; } else if (x<-1.0) { x=-1.0; };
outBuffer[index++] = (short)( x * 32767.0 );
if (index >= p->outBufSamples) {
waitThreadLock(p->outlock);
(*p->bqPlayerBufferQueue)->Enqueue(p->bqPlayerBufferQueue,
outBuffer,bufsamps*sizeof(short));
p->currentOutputBuffer = (p->currentOutputBuffer ? 0 : 1);
index = 0;
outBuffer = p->outputBuffer[p->currentOutputBuffer];
}
}
p->currentOutputIndex = index;
p->time += (double) size/(p->sr*p->outchannels);
return i;
}
//----------------------------------------------------------------------
// thread Locks
// to ensure synchronisation between callbacks and processing code
void* createThreadLock(void)
{
threadLock *p;
p = (threadLock*) malloc(sizeof(threadLock));
if (p == NULL)
return NULL;
memset(p, 0, sizeof(threadLock));
if (pthread_mutex_init(&(p->m), (pthread_mutexattr_t*) NULL) != 0) {
free((void*) p);
return NULL;
}
if (pthread_cond_init(&(p->c), (pthread_condattr_t*) NULL) != 0) {
pthread_mutex_destroy(&(p->m));
free((void*) p);
return NULL;
}
p->s = (unsigned char) 1;
return p;
}
int waitThreadLock(void *lock)
{
threadLock *p;
p = (threadLock*) lock;
pthread_mutex_lock(&(p->m));
while (!p->s) {
pthread_cond_wait(&(p->c), &(p->m));
}
p->s = (unsigned char) 0;
pthread_mutex_unlock(&(p->m));
return 0;
}
void notifyThreadLock(void *lock)
{
threadLock *p;
p = (threadLock*) lock;
pthread_mutex_lock(&(p->m));
p->s = (unsigned char) 1;
pthread_cond_signal(&(p->c));
pthread_mutex_unlock(&(p->m));
}
void destroyThreadLock(void *lock)
{
threadLock *p;
p = (threadLock*) lock;
if (p == NULL)
return;
notifyThreadLock(p);
pthread_cond_destroy(&(p->c));
pthread_mutex_destroy(&(p->m));
free(p);
}

View File

@ -0,0 +1,129 @@
/*
opensl_io.c:
Android OpenSL input/output module header
Copyright (c) 2012, Victor Lazzarini
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the <organization> nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef OPENSL_IO
#define OPENSL_IO
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>
#include <pthread.h>
#include <stdlib.h>
typedef struct threadLock_{
pthread_mutex_t m;
pthread_cond_t c;
unsigned char s;
} threadLock;
#ifdef __cplusplus
extern "C" {
#endif
typedef struct opensl_stream {
// engine interfaces
SLObjectItf engineObject;
SLEngineItf engineEngine;
// output mix interfaces
SLObjectItf outputMixObject;
// buffer queue player interfaces
SLObjectItf bqPlayerObject;
SLPlayItf bqPlayerPlay;
SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue;
SLEffectSendItf bqPlayerEffectSend;
// recorder interfaces
SLObjectItf recorderObject;
SLRecordItf recorderRecord;
SLAndroidSimpleBufferQueueItf recorderBufferQueue;
// buffer indexes
int currentInputIndex;
int currentOutputIndex;
// current buffer half (0, 1)
int currentOutputBuffer;
int currentInputBuffer;
// buffers
short *outputBuffer[2];
short *inputBuffer[2];
// size of buffers
int outBufSamples;
int inBufSamples;
// locks
void* inlock;
void* outlock;
double time;
int inchannels;
int outchannels;
int sr;
} OPENSL_STREAM;
/*
Open the audio device with a given sampling rate (sr), input and output channels and IO buffer size
in frames. Returns a handle to the OpenSL stream
*/
OPENSL_STREAM* android_OpenAudioDevice(int sr, int inchannels, int outchannels, int bufferframes);
/*
Close the audio device
*/
void android_CloseAudioDevice(OPENSL_STREAM *p);
/*
Read a buffer from the OpenSL stream *p, of size samples. Returns the number of samples read.
*/
int android_AudioIn(OPENSL_STREAM *p, float *buffer,int size);
/*
Write a buffer to the OpenSL stream *p, of size samples. Returns the number of samples written.
*/
int android_AudioOut(OPENSL_STREAM *p, float *buffer,int size);
/*
Get the current IO block time in seconds
*/
double android_GetTimestamp(OPENSL_STREAM *p);
/*
Android SDL interface for playing
*/
void android_AudioOut2(OPENSL_STREAM *p);
/*
Android SDL interface for getBuffer
*/
unsigned char *android_GetDeviceBuffer(OPENSL_STREAM *p);
#ifdef __cplusplus
};
#endif
#endif // #ifndef OPENSL_IO

View File

@ -1,13 +1,13 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 18
buildToolsVersion "23.0.3"
compileSdkVersion 21
buildToolsVersion "21.1.2"
defaultConfig {
applicationId "org.mamedev.mame"
minSdkVersion 18
targetSdkVersion 18
minSdkVersion 21
targetSdkVersion 21
ndk {
moduleName 'main'

View File

@ -33,7 +33,7 @@
android:hardwareAccelerated="true" >
<activity android:name="MAME"
android:label="@string/app_name"
android:configChanges="keyboardHidden|orientation"
android:configChanges="keyboardHidden|orientation|screenSize"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />

View File

@ -0,0 +1,201 @@
#
# CORE CONFIGURATION OPTIONS
#
readconfig 1
writeconfig 0
#
# CORE SEARCH PATH OPTIONS
#
homepath .
rompath roms;/sdcard/Download;/sdcard/mame/roms
hashpath hash
samplepath samples
artpath artwork
ctrlrpath ctrlr
inipath .
fontpath .
cheatpath cheat
crosshairpath crosshair
pluginspath plugins
languagepath language
swpath software
#
# CORE OUTPUT DIRECTORY OPTIONS
#
cfg_directory cfg
nvram_directory nvram
input_directory inp
state_directory sta
snapshot_directory snap
diff_directory diff
comment_directory comments
#
# CORE STATE/PLAYBACK OPTIONS
#
state
autosave 1
playback
record
record_timecode 0
exit_after_playback 0
mngwrite
aviwrite
wavwrite
snapname %g/%i
snapsize auto
snapview internal
snapbilinear 1
statename %g
burnin 0
#
# CORE PERFORMANCE OPTIONS
#
autoframeskip 1
frameskip 8
seconds_to_run 0
throttle 1
sleep 0
speed 1.0
refreshspeed 30
#
# CORE RENDER OPTIONS
#
keepaspect 1
unevenstretch 1
unevenstretchx 0
unevenstretchy 0
autostretchxy 0
intoverscan 0
intscalex 0
intscaley 0
#
# CORE ROTATION OPTIONS
#
rotate 1
ror 0
rol 0
autoror 0
autorol 0
flipx 0
flipy 0
#
# CORE ARTWORK OPTIONS
#
artwork_crop 0
use_backdrops 1
use_overlays 1
use_bezels 1
use_cpanels 1
use_marquees 1
#
# CORE SCREEN OPTIONS
#
brightness 1.0
contrast 1.0
gamma 1.0
pause_brightness 0.65
effect none
#
# CORE VECTOR OPTIONS
#
beam_width_min 1.0
beam_width_max 1.0
beam_intensity_weight 0
flicker 0
#
# CORE SOUND OPTIONS
#
samplerate 48000
samples 1
volume 0
#
# CORE INPUT OPTIONS
#
coin_lockout 1
ctrlr
mouse 0
joystick 1
lightgun 0
multikeyboard 0
multimouse 0
steadykey 0
ui_active 1
offscreen_reload 0
joystick_map auto
joystick_deadzone 0.3
joystick_saturation 0.85
natural 0
joystick_contradictory 0
coin_impulse 0
#
# CORE INPUT AUTOMATIC ENABLE OPTIONS
#
paddle_device keyboard
adstick_device keyboard
pedal_device keyboard
dial_device keyboard
trackball_device keyboard
lightgun_device keyboard
positional_device keyboard
mouse_device mouse
#
# CORE DEBUGGING OPTIONS
#
verbose 0
log 0
oslog 0
debug 0
update_in_pause 0
debugscript
#
# CORE COMM OPTIONS
#
comm_localhost 0.0.0.0
comm_localport 15112
comm_remotehost 127.0.0.1
comm_remoteport 15112
#
# CORE MISC OPTIONS
#
drc 1
drc_use_c 0
drc_log_uml 0
drc_log_native 0
bios
cheat 0
skip_gameinfo 1
uifont default
ui cabinet
ramsize
confirm_quit 0
ui_mouse 1
autoboot_command
autoboot_delay 0
autoboot_script
console 0
plugins 1
plugin
noplugin
language English
#
# HTTP SERVER OPTIONS
#
http 0
http_port 8080
http_root web

View File

@ -0,0 +1,60 @@
#
# UI SEARCH PATH OPTIONS
#
historypath history;dats;.
extrainipath folders
cabinets_directory cabinets;cabdevs
cpanels_directory cpanel
pcbs_directory pcb
flyers_directory flyers
titles_directory titles
ends_directory ends
marquees_directory marquees
artwork_preview_directory "artwork preview;artpreview"
bosses_directory bosses
logos_directory logo
scores_directory scores
versus_directory versus
gameover_directory gameover
howto_directory howto
select_directory select
icons_directory icons
covers_directory covers
ui_path ui
#
# UI MISC OPTIONS
#
remember_last 1
enlarge_snaps 1
forced4x3 1
use_background 1
skip_biosmenu 1
skip_partsmenu 1
last_used_filter Available
last_used_machine narc
info_audit_enabled 0
hide_romless 1
#
# UI OPTIONS
#
infos_text_size 1
font_rows 30
hide_main_panel 0
ui_border_color ffffffff
ui_bg_color ef101030
ui_clone_color ff808080
ui_dipsw_color ffffff00
ui_gfxviewer_color ef101030
ui_mousedown_bg_color b0606000
ui_mousedown_color ffffff80
ui_mouseover_bg_color 70404000
ui_mouseover_color ffffff80
ui_selected_bg_color ef808000
ui_selected_color ffffff00
ui_slider_color ffffffff
ui_subitem_color ffffffff
ui_text_bg_color ef000000
ui_text_color ffffffff
ui_unavail_color ff404040

View File

@ -17,7 +17,7 @@ import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import android.widget.AbsoluteLayout;
import android.widget.RelativeLayout;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
@ -29,6 +29,9 @@ import android.graphics.drawable.Drawable;
import android.media.*;
import android.hardware.*;
import android.content.pm.ActivityInfo;
import java.io.*;
import android.content.res.AssetManager;
import android.content.res.Configuration;
/**
SDL Activity
@ -59,6 +62,7 @@ public class SDLActivity extends Activity {
// Audio
protected static AudioTrack mAudioTrack;
protected static AudioRecord mAudioRecord;
/**
* This method is called by SDL before loading the native shared libraries.
@ -106,13 +110,14 @@ public class SDLActivity extends Activity {
mJoystickHandler = null;
mSDLThread = null;
mAudioTrack = null;
mAudioRecord = null;
mExitCalledFromJava = false;
mBrokenLibraries = false;
mIsPaused = false;
mIsSurfaceReady = false;
mHasFocus = true;
}
// Setup
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -171,7 +176,7 @@ public class SDLActivity extends Activity {
mJoystickHandler = new SDLJoystickHandler();
}
mLayout = new AbsoluteLayout(this);
mLayout = new RelativeLayout(this);
mLayout.addView(mSurface);
setContentView(mLayout);
@ -186,6 +191,15 @@ public class SDLActivity extends Activity {
SDLActivity.onNativeDropFile(filename);
}
}
View decorView = getWindow().getDecorView();
// Hide both the navigation bar and the status bar.
// SYSTEM_UI_FLAG_FULLSCREEN is only available on Android 4.1 and higher, but as
// a general rule, you should design your app to hide the status bar whenever you
// hide the navigation bar.
int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);
}
// Events
@ -272,6 +286,11 @@ public class SDLActivity extends Activity {
// Reset everything in case the user re opens the app
SDLActivity.initialize();
}
@Override
public void onBackPressed() {
super.onBackPressed();
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
@ -367,10 +386,13 @@ public class SDLActivity extends Activity {
break;
case COMMAND_TEXTEDIT_HIDE:
if (mTextEdit != null) {
mTextEdit.setVisibility(View.GONE);
// Note: On some devices setting view to GONE creates a flicker in landscape.
// Setting the View's sizes to 0 is similar to GONE but without the flicker.
// The sizes will be set to useful values when the keyboard is shown again.
mTextEdit.setLayoutParams(new RelativeLayout.LayoutParams(0, 0));
InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(mTextEdit.getWindowToken(), 0);
// InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
// imm.hideSoftInputFromWindow(mTextEdit.getWindowToken(), 0);
}
break;
case COMMAND_SET_KEEP_SCREEN_ON:
@ -504,8 +526,9 @@ public class SDLActivity extends Activity {
@Override
public void run() {
AbsoluteLayout.LayoutParams params = new AbsoluteLayout.LayoutParams(
w, h + HEIGHT_PADDING, x, y);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(w, h + HEIGHT_PADDING);
params.leftMargin = x;
params.topMargin = y;
if (mTextEdit == null) {
mTextEdit = new DummyEdit(getContext());
@ -528,7 +551,8 @@ public class SDLActivity extends Activity {
*/
public static boolean showTextInput(int x, int y, int w, int h) {
// Transfer the task to the main thread as a Runnable
return mSingleton.commandHandler.post(new ShowTextInputTask(x, y, w, h));
// return mSingleton.commandHandler.post(new ShowTextInputTask(x, y, w, h));
return true;
}
/**
@ -543,7 +567,7 @@ public class SDLActivity extends Activity {
/**
* This method is called by SDL using JNI.
*/
public static int audioInit(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) {
public static int audioOpen(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) {
int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO;
int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT;
int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1);
@ -622,13 +646,72 @@ public class SDLActivity extends Activity {
/**
* This method is called by SDL using JNI.
*/
public static void audioQuit() {
public static int captureOpen(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) {
int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO;
int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT;
int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1);
Log.v(TAG, "SDL capture: wanted " + (isStereo ? "stereo" : "mono") + " " + (is16Bit ? "16-bit" : "8-bit") + " " + (sampleRate / 1000f) + "kHz, " + desiredFrames + " frames buffer");
// Let the user pick a larger buffer if they really want -- but ye
// gods they probably shouldn't, the minimums are horrifyingly high
// latency already
desiredFrames = Math.max(desiredFrames, (AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize);
if (mAudioRecord == null) {
mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, sampleRate,
channelConfig, audioFormat, desiredFrames * frameSize);
// see notes about AudioTrack state in audioOpen(), above. Probably also applies here.
if (mAudioRecord.getState() != AudioRecord.STATE_INITIALIZED) {
Log.e(TAG, "Failed during initialization of AudioRecord");
mAudioRecord.release();
mAudioRecord = null;
return -1;
}
mAudioRecord.startRecording();
}
Log.v(TAG, "SDL capture: got " + ((mAudioRecord.getChannelCount() >= 2) ? "stereo" : "mono") + " " + ((mAudioRecord.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit" : "8-bit") + " " + (mAudioRecord.getSampleRate() / 1000f) + "kHz, " + desiredFrames + " frames buffer");
return 0;
}
/** This method is called by SDL using JNI. */
public static int captureReadShortBuffer(short[] buffer, boolean blocking) {
// !!! FIXME: this is available in API Level 23. Until then, we always block. :(
//return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
return mAudioRecord.read(buffer, 0, buffer.length);
}
/** This method is called by SDL using JNI. */
public static int captureReadByteBuffer(byte[] buffer, boolean blocking) {
// !!! FIXME: this is available in API Level 23. Until then, we always block. :(
//return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
return mAudioRecord.read(buffer, 0, buffer.length);
}
/** This method is called by SDL using JNI. */
public static void audioClose() {
if (mAudioTrack != null) {
mAudioTrack.stop();
mAudioTrack.release();
mAudioTrack = null;
}
}
/** This method is called by SDL using JNI. */
public static void captureClose() {
if (mAudioRecord != null) {
mAudioRecord.stop();
mAudioRecord.release();
mAudioRecord = null;
}
}
// Input
/**
@ -662,6 +745,21 @@ public class SDLActivity extends Activity {
}
}
// Check if a given device is considered a possible SDL joystick
public static boolean isDeviceSDLJoystick(int deviceId) {
InputDevice device = InputDevice.getDevice(deviceId);
// We cannot use InputDevice.isVirtual before API 16, so let's accept
// only nonnegative device ids (VIRTUAL_KEYBOARD equals -1)
if ((device == null) || (deviceId < 0)) {
return false;
}
int sources = device.getSources();
return (((sources & InputDevice.SOURCE_CLASS_JOYSTICK) == InputDevice.SOURCE_CLASS_JOYSTICK) ||
((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD) ||
((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD)
);
}
// APK expansion files support
/** com.android.vending.expansion.zipfile.ZipResourceFile object or null. */
@ -976,6 +1074,7 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
// Keep track of the surface size to normalize touch events
protected static float mWidth, mHeight;
static float[] px, py;
// Startup
public SDLSurface(Context context) {
@ -994,10 +1093,11 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
if(Build.VERSION.SDK_INT >= 12) {
setOnGenericMotionListener(new SDLGenericMotionListener_API12());
}
// Some arbitrary defaults to avoid a potential division by zero
mWidth = 1.0f;
mHeight = 1.0f;
px = new float[10];
py = new float[10];
}
public void handlePause() {
@ -1014,6 +1114,7 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
}
public Surface getNativeSurface() {
Log.v("SDL", "getNativeSurface()");
return getHolder().getSurface();
}
@ -1033,7 +1134,7 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
SDLActivity.mIsSurfaceReady = false;
SDLActivity.onNativeSurfaceDestroyed();
}
// Called when the surface is resized
@Override
public void surfaceChanged(SurfaceHolder holder,
@ -1088,8 +1189,7 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
mWidth = width;
mHeight = height;
SDLActivity.onNativeResize(width, height, sdlFormat, mDisplay.getRefreshRate());
Log.v("SDL", "Window size: " + width + "x" + height);
//Log.v("SDL", "Window size: " + width + "x" + height);
boolean skip = false;
int requestedOrientation = SDLActivity.mSingleton.getRequestedOrientation();
@ -1137,13 +1237,13 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
final Thread sdlThread = new Thread(new SDLMain(), "SDLThread");
enableSensor(Sensor.TYPE_ACCELEROMETER, true);
sdlThread.start();
// Set up a listener thread to catch when the native thread ends
SDLActivity.mSDLThread = new Thread(new Runnable(){
@Override
public void run(){
try {
sdlThread.start();
sdlThread.join();
}
catch(Exception e){}
@ -1167,11 +1267,14 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
// Dispatch the different events depending on where they come from
// Some SOURCE_DPAD or SOURCE_GAMEPAD are also SOURCE_KEYBOARD
// So, we try to process them as DPAD or GAMEPAD events first, if that fails we try them as KEYBOARD
if ( (event.getSource() & InputDevice.SOURCE_GAMEPAD) != 0 ||
(event.getSource() & InputDevice.SOURCE_DPAD) != 0 ) {
// Some SOURCE_JOYSTICK, SOURCE_DPAD or SOURCE_GAMEPAD are also SOURCE_KEYBOARD
// So, we try to process them as JOYSTICK/DPAD/GAMEPAD events first, if that fails we try them as KEYBOARD
//
// Furthermore, it's possible a game controller has SOURCE_KEYBOARD and
// SOURCE_JOYSTICK, while its key events arrive from the keyboard source
// So, retrieve the device itself and check all of its sources
if (SDLActivity.isDeviceSDLJoystick(event.getDeviceId())) {
// Note that we process events with specific key codes here
if (event.getAction() == KeyEvent.ACTION_DOWN) {
if (SDLActivity.onNativePadDown(event.getDeviceId(), keyCode) == 0) {
return true;
@ -1183,7 +1286,7 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
}
}
if( (event.getSource() & InputDevice.SOURCE_KEYBOARD) != 0) {
if ((event.getSource() & InputDevice.SOURCE_KEYBOARD) != 0) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
//Log.v("SDL", "key down: " + keyCode);
SDLActivity.onNativeKeyDown(keyCode);
@ -1196,6 +1299,20 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
}
}
if ((event.getSource() & InputDevice.SOURCE_MOUSE) != 0) {
// on some devices key events are sent for mouse BUTTON_BACK/FORWARD presses
// they are ignored here because sending them as mouse input to SDL is messy
if ((keyCode == KeyEvent.KEYCODE_BACK) || (keyCode == KeyEvent.KEYCODE_FORWARD)) {
switch (event.getAction()) {
case KeyEvent.ACTION_DOWN:
case KeyEvent.ACTION_UP:
// mark the event as handled or it will be handled by system
// handling KEYCODE_BACK by system will call onBackPressed()
return true;
}
}
}
return false;
}
@ -1214,7 +1331,7 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
// !!! FIXME: dump this SDK check after 2.0.4 ships and require API14.
if (event.getSource() == InputDevice.SOURCE_MOUSE && SDLActivity.mSeparateMouseAndTouch) {
if (Build.VERSION.SDK_INT < 14) {
mouseButton = 1; // For Android==12 all mouse buttons are the left button
mouseButton = 1; // all mouse buttons are the left button
} else {
try {
mouseButton = (Integer) event.getClass().getMethod("getButtonState").invoke(event);
@ -1236,12 +1353,16 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
// see the documentation of getPressure(i)
p = 1.0f;
}
SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p);
// SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p);
SDLActivity.onNativeMouse(1, action, event.getX(i) - px[i], event.getY(i) - py[i]);
px[i] = event.getX(i);
py[i] = event.getY(i);
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_DOWN:
//SDLActivity.onNativeKeyDown(KeyEvent.KEYCODE_ENTER);
// Primary pointer up/down, the index is always zero
i = 0;
case MotionEvent.ACTION_POINTER_UP:
@ -1260,7 +1381,8 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
// see the documentation of getPressure(i)
p = 1.0f;
}
SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p);
SDLActivity.onNativeMouse(1, action, 0, 0);
//SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p);
break;
case MotionEvent.ACTION_CANCEL:
@ -1274,7 +1396,7 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
// see the documentation of getPressure(i)
p = 1.0f;
}
SDLActivity.onNativeTouch(touchDevId, pointerFingerId, MotionEvent.ACTION_UP, x, y, p);
//SDLActivity.onNativeTouch(touchDevId, pointerFingerId, MotionEvent.ACTION_UP, x, y, p);
}
break;
@ -1328,7 +1450,7 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
}
SDLActivity.onNativeAccel(-x / SensorManager.GRAVITY_EARTH,
y / SensorManager.GRAVITY_EARTH,
event.values[2] / SensorManager.GRAVITY_EARTH - 1);
event.values[2] / SensorManager.GRAVITY_EARTH);
}
}
}
@ -1355,7 +1477,7 @@ class DummyEdit extends View implements View.OnKeyListener {
public boolean onKey(View v, int keyCode, KeyEvent event) {
// This handles the hardware keyboard input
if (event.isPrintingKey()) {
if (event.isPrintingKey() || keyCode == KeyEvent.KEYCODE_SPACE) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
ic.commitText(String.valueOf((char) event.getUnicodeChar()), 1);
}
@ -1368,8 +1490,7 @@ class DummyEdit extends View implements View.OnKeyListener {
} else if (event.getAction() == KeyEvent.ACTION_UP) {
SDLActivity.onNativeKeyUp(keyCode);
return true;
}
}
return false;
}
@ -1418,7 +1539,7 @@ class SDLInputConnection extends BaseInputConnection {
*/
int keyCode = event.getKeyCode();
if (event.getAction() == KeyEvent.ACTION_DOWN) {
if (event.isPrintingKey()) {
if (event.isPrintingKey() || keyCode == KeyEvent.KEYCODE_SPACE) {
commitText(String.valueOf((char) event.getUnicodeChar()), 1);
}
SDLActivity.onNativeKeyDown(keyCode);
@ -1519,13 +1640,7 @@ class SDLJoystickHandler_API12 extends SDLJoystickHandler {
if (joystick == null) {
joystick = new SDLJoystick();
InputDevice joystickDevice = InputDevice.getDevice(deviceIds[i]);
if (
(joystickDevice.getSources() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0
||
(joystickDevice.getSources() & InputDevice.SOURCE_CLASS_BUTTON) != 0
)
{
if (SDLActivity.isDeviceSDLJoystick(deviceIds[i])) {
joystick.device_id = deviceIds[i];
joystick.name = joystickDevice.getName();
joystick.axes = new ArrayList<InputDevice.MotionRange>();
@ -1534,7 +1649,7 @@ class SDLJoystickHandler_API12 extends SDLJoystickHandler {
List<InputDevice.MotionRange> ranges = joystickDevice.getMotionRanges();
Collections.sort(ranges, new RangeComparator());
for (InputDevice.MotionRange range : ranges ) {
if ((range.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0 ) {
if ((range.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
if (range.getAxis() == MotionEvent.AXIS_HAT_X ||
range.getAxis() == MotionEvent.AXIS_HAT_Y) {
joystick.hats.add(range);
@ -1588,7 +1703,7 @@ class SDLJoystickHandler_API12 extends SDLJoystickHandler {
@Override
public boolean handleMotionEvent(MotionEvent event) {
if ( (event.getSource() & InputDevice.SOURCE_JOYSTICK) != 0) {
if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) != 0) {
int actionPointerIndex = event.getActionIndex();
int action = event.getActionMasked();
switch(action) {
@ -1627,8 +1742,7 @@ class SDLGenericMotionListener_API12 implements View.OnGenericMotionListener {
case InputDevice.SOURCE_JOYSTICK:
case InputDevice.SOURCE_GAMEPAD:
case InputDevice.SOURCE_DPAD:
SDLActivity.handleJoystickMotionEvent(event);
return true;
return SDLActivity.handleJoystickMotionEvent(event);
case InputDevice.SOURCE_MOUSE:
action = event.getActionMasked();

View File

@ -1,9 +1,84 @@
package org.mamedev.mame;
import java.io.*;
import android.app.*;
import android.os.*;
import android.content.res.AssetManager;
import android.util.Log;
import org.libsdl.app.SDLActivity;
import android.view.*;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
/**
SDL Activity
*/
public class MAME extends SDLActivity {
private static final String TAG = "MAME";
// Setup
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
copyAssetAll("mame.ini");
copyAssetAll("ui.ini");
copyAssetAll("roms");
}
public void copyAssetAll(String srcPath) {
AssetManager assetMgr = this.getAssets();
String assets[] = null;
try {
String destPath = getExternalFilesDir(null) + File.separator + srcPath;
assets = assetMgr.list(srcPath);
if (assets.length == 0) {
copyFile(srcPath, destPath);
} else {
File dir = new File(destPath);
if (!dir.exists())
dir.mkdir();
for (String element : assets) {
copyAssetAll(srcPath + File.separator + element);
}
}
}
catch (IOException e) {
e.printStackTrace();
}
}
public void copyFile(String srcFile, String destFile) {
AssetManager assetMgr = this.getAssets();
InputStream is = null;
OutputStream os = null;
try {
is = assetMgr.open(srcFile);
if (new File(destFile).exists() == false)
{
os = new FileOutputStream(destFile);
byte[] buffer = new byte[1024];
int read;
while ((read = is.read(buffer)) != -1) {
os.write(buffer, 0, read);
}
is.close();
os.flush();
os.close();
Log.v(TAG, "copy from Asset:" + destFile);
}
}
catch (IOException e) {
e.printStackTrace();
}
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
}
int keyCode = event.getKeyCode();
// Ignore certain special keys so they're handled by Android
if (((event.getSource() & InputDevice.SOURCE_CLASS_BUTTON) != 0) && (keyCode == KeyEvent.KEYCODE_BACK)) {
android.os.Process.killProcess(android.os.Process.myPid());
}
return super.dispatchKeyEvent(event);
}
}

View File

@ -1 +1,3 @@
gradle.ext.sdkVersion = 21
include ':app'

View File

@ -1533,7 +1533,7 @@ generate: \
$(GENDIR)/includes/SDL2:
-$(call MKDIR,$@)
-$(call COPY,3rdparty/SDL2/include/,$(GENDIR)/includes/SDL2)
-$(call COPY,3rdparty/SDL2/include,$(GENDIR)/includes/SDL2)
ifneq ($(NEW_GIT_VERSION),$(OLD_GIT_VERSION))
stale:

View File

@ -1051,6 +1051,7 @@ configuration { "android*" }
"-Wno-undef",
"-Wno-typedef-redefinition",
"-Wno-unknown-warning-option",
"-Wno-incompatible-ms-struct",
}
buildoptions_cpp {
"-x c++",

View File

@ -1138,9 +1138,11 @@ if _OPTIONS["targetos"]=="android" then
"GLESv1_CM",
"GLESv2",
"log",
"OpenSLES",
"c++_static"
}
linkoptions {
"-Wl,-soname,libSDL2.so"
"-Wl,-soname,libSDL2.so",
}
if _OPTIONS["SEPARATE_BIN"]~="1" then
@ -1414,8 +1416,10 @@ end
if _OPTIONS["targetos"]=="android" then
files {
MAME_DIR .. "3rdparty/SDL2/src/audio/android/SDL_androidaudio.c",
MAME_DIR .. "3rdparty/SDL2/src/audio/android/opensl_io.h",
MAME_DIR .. "3rdparty/SDL2/src/audio/android/opensl_io.c",
MAME_DIR .. "3rdparty/SDL2/src/audio/android/SDL_androidaudio.h",
MAME_DIR .. "3rdparty/SDL2/src/audio/android/SDL_androidaudio.c",
MAME_DIR .. "3rdparty/SDL2/src/core/android/SDL_android.c",
MAME_DIR .. "3rdparty/SDL2/src/core/android/SDL_android.h",
MAME_DIR .. "3rdparty/SDL2/src/filesystem/android/SDL_sysfilesystem.c",

View File

@ -836,6 +836,7 @@ function toolchain(_buildDir, _subDir)
includedirs {
MAME_DIR .. "3rdparty/bgfx/3rdparty/khronos",
"$(ANDROID_NDK_ROOT)/sources/cxx-stl/llvm-libc++/libcxx/include",
"$(ANDROID_NDK_ROOT)/sources/cxx-stl/llvm-libc++/include",
"$(ANDROID_NDK_ROOT)/sources/android/support/include",
"$(ANDROID_NDK_ROOT)/sources/android/native_app_glue",
}
@ -852,6 +853,9 @@ function toolchain(_buildDir, _subDir)
"android",
"log",
"c++_static",
"c++abi",
"android_support",
"stdc++",
"gcc",
}
buildoptions {
@ -879,6 +883,7 @@ function toolchain(_buildDir, _subDir)
configuration { "android-arm" }
libdirs {
"$(ANDROID_NDK_ROOT)/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a",
"$(ANDROID_NDK_ARM)/lib/gcc/arm-linux-androideabi/4.9.x/armv7-a",
"$(ANDROID_NDK_ROOT)/platforms/" .. androidPlatform .. "/arch-arm/usr/lib",
}
includedirs {
@ -892,6 +897,9 @@ function toolchain(_buildDir, _subDir)
"-mfpu=vfpv3-d16",
"-mthumb",
}
links {
"unwind",
}
linkoptions {
"-gcc-toolchain $(ANDROID_NDK_ARM)",
"--sysroot=$(ANDROID_NDK_ROOT)/platforms/" .. androidPlatform .. "/arch-arm",

View File

@ -163,6 +163,9 @@ const options_entry sdl_options::s_option_entries[] =
sdl_options::sdl_options()
: osd_options()
{
#if defined (SDLMAME_ANDROID)
chdir (SDL_AndroidGetExternalStoragePath());
#endif
std::string ini_path(INI_PATH);
add_entries(sdl_options::s_option_entries);
strreplace(ini_path,"APP_NAME", emulator_info::get_appname_lower());