Small fix for crashing, made audio to use Java byte array instead of copying bytes,

and made it to use array size returned from Java - seems to add latency to the audio
This commit is contained in:
pelya
2009-12-10 16:34:51 +02:00
parent 01cefc754c
commit 865e4f619b
3 changed files with 155 additions and 46 deletions

View File

@@ -22,6 +22,9 @@ using namespace std;
#include "surfaceDB.h"
#include <fstream>
#include <iostream>
#ifdef ANDROID
#include <android/log.h>
#endif
SurfaceDB surfaceDB;
@@ -56,6 +59,14 @@ SDL_Surface *SurfaceDB::loadSurface( string fn, bool alpha ) {
}
SDL_Surface *newSurface = SDL_LoadBMP( fn.c_str() );
if( newSurface == NULL )
{
cout << "ERROR: Cannot load image " << fn << endl;
#ifdef ANDROID
__android_log_print(ANDROID_LOG_ERROR, "Alien Blaster", (string( "Cannot load image " ) + fn).c_str() );
#endif
exit(1);
}
SDL_SetColorKey( newSurface, SDL_SRCCOLORKEY,
SDL_MapRGB(newSurface->format, transR, transG, transB) );
if ( alpha ) {

View File

@@ -98,16 +98,14 @@ AudioBootStrap ANDROIDAUD_bootstrap = {
static SDL_mutex * audioMutex = NULL;
static SDL_cond * audioCond = NULL;
static SDL_cond * audioCond2 = NULL;
static unsigned char * audioBuffer = NULL;
static size_t audioBufferSize = 0;
static SDL_AudioSpec *audioFormat = NULL;
static int audioInitialized = 0;
/* This function waits until it is possible to write a full sound buffer */
static void ANDROIDAUD_WaitAudio(_THIS)
{
/* We will block in PlayAudio(), do nothing here */
}
static int audioPlayed = 0;
static jbyteArray audioBufferJNI = NULL;
static JNIEnv * jniEnv = NULL;
static Uint8 *ANDROIDAUD_GetAudioBuf(_THIS)
{
@@ -117,25 +115,38 @@ static Uint8 *ANDROIDAUD_GetAudioBuf(_THIS)
static void ANDROIDAUD_CloseAudio(_THIS)
{
SDL_mutex * audioMutex1;
/*
if ( this->hidden->mixbuf != NULL ) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
}
*/
if( audioMutex != NULL )
{
audioMutex1 = audioMutex;
SDL_mutexP(audioMutex1);
audioInitialized = 0;
SDL_CondSignal(audioCond);
SDL_CondSignal(audioCond2);
audioMutex = NULL;
SDL_DestroyCond(audioCond);
SDL_DestroyCond(audioCond2);
audioCond = NULL;
audioCond2 = NULL;
audioFormat = NULL;
// TODO: this crashes JNI, so we're just memleaking it
/*
(*jniEnv)->ReleaseByteArrayElements(jniEnv, audioBufferJNI, (jbyte *)audioBuffer, 0);
(*jniEnv)->DeleteGlobalRef(jniEnv, audioBufferJNI);
*/
jniEnv = NULL;
audioBufferJNI = NULL;
audioBuffer = NULL;
audioBufferSize = 0;
SDL_mutexV(audioMutex1);
SDL_DestroyMutex(audioMutex1);
}
}
@@ -143,23 +154,15 @@ static int ANDROIDAUD_OpenAudio(_THIS, SDL_AudioSpec *spec)
{
if( ! (spec->format == AUDIO_S8 || spec->format == AUDIO_S16) )
return (-1); // TODO: enable format conversion? Don't know how to do that in SDL
/* Allocate mixing buffer */
this->hidden->mixlen = spec->size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if ( this->hidden->mixbuf == NULL ) {
return(-1);
}
SDL_memset(this->hidden->mixbuf, spec->silence, spec->size);
if( audioMutex == NULL )
{
audioInitialized = 0;
audioFormat = spec;
audioBuffer = this->hidden->mixbuf;
audioBufferSize = this->hidden->mixlen;
audioMutex = SDL_CreateMutex();
audioCond = SDL_CreateCond();
audioCond2 = SDL_CreateCond();
audioPlayed == 0;
}
SDL_mutexP(audioMutex);
@@ -175,6 +178,9 @@ static int ANDROIDAUD_OpenAudio(_THIS, SDL_AudioSpec *spec)
}
}
this->hidden->mixbuf = audioBuffer;
this->hidden->mixlen = audioBufferSize;
audioFormat = NULL;
SDL_mutexV(audioMutex);
@@ -182,16 +188,26 @@ static int ANDROIDAUD_OpenAudio(_THIS, SDL_AudioSpec *spec)
return(0);
}
/* This function waits until it is possible to write a full sound buffer */
static void ANDROIDAUD_WaitAudio(_THIS)
{
/* We will block in PlayAudio(), do nothing here */
}
static void ANDROIDAUD_PlayAudio(_THIS)
{
SDL_mutexP(audioMutex);
audioBuffer = this->hidden->mixbuf;
audioBufferSize = this->hidden->mixlen;
while( audioBuffer != NULL )
SDL_CondWait( audioCond, audioMutex );
//audioBuffer = this->hidden->mixbuf;
//audioBufferSize = this->hidden->mixlen;
audioPlayed = 1;
SDL_CondSignal(audioCond2);
SDL_CondWaitTimeout( audioCond, audioMutex, 1000 );
this->hidden->mixbuf = audioBuffer;
SDL_mutexV(audioMutex);
}
@@ -216,12 +232,12 @@ extern jintArray JAVA_EXPORT_NAME(AudioThread_nativeAudioInit) (JNIEnv * env, jo
{
initData[0] = audioFormat->freq;
initData[1] = audioFormat->channels;
initData[2] = ( audioFormat->format == AUDIO_S16 ) ? 1 : 0;
int bytesPerSample = (audioFormat->format & 0xFF) / 8;
initData[2] = ( bytesPerSample == 2 ) ? 1 : 0;
audioFormat->format = ( bytesPerSample == 2 ) ? AUDIO_S16 : AUDIO_S8;
initData[3] = audioFormat->size;
ret=(*env)->NewIntArray(env, 4);
(*env)->SetIntArrayRegion(env, ret, 0, 4, (jint *)initData);
audioInitialized = 1;
SDL_CondSignal(audioCond);
}
SDL_mutexV(audioMutex);
@@ -229,33 +245,100 @@ extern jintArray JAVA_EXPORT_NAME(AudioThread_nativeAudioInit) (JNIEnv * env, jo
return (ret);
};
extern jint JAVA_EXPORT_NAME(AudioThread_nativeAudioBuffer) ( JNIEnv * env, jobject jobj, jbyteArray data )
extern jobject JAVA_EXPORT_NAME(AudioThread_nativeAudioInit2) (JNIEnv * env, jobject jobj, jbyteArray buf)
{
jobject ret = NULL;
if( audioMutex == NULL )
return;
SDL_mutexP(audioMutex);
if( audioInitialized == 0 )
{
/* Allocate mixing buffer */
audioBufferJNI = (jbyteArray*)(*env)->NewGlobalRef(env, buf);
audioBufferSize = (*env)->GetArrayLength(env, audioBufferJNI);
jboolean isCopy = JNI_TRUE;
audioBuffer = (unsigned char *) (*env)->GetByteArrayElements(env, audioBufferJNI, &isCopy);
if( isCopy == JNI_TRUE )
__android_log_print(ANDROID_LOG_ERROR, "libSDL", "AudioThread_nativeAudioInit2() JNI returns a copy of byte array - no audio will be played");
jniEnv = env;
int bytesPerSample = (audioFormat->format & 0xFF) / 8;
audioFormat->samples = audioBufferSize / bytesPerSample / audioFormat->channels;
audioFormat->size = audioBufferSize;
SDL_memset(audioBuffer, audioFormat->silence, audioFormat->size);
char t[512];
//sprintf(t, "AudioThread_nativeAudioInit2() got byte array from JNI: size %i samples %i direct memory %i", audioBufferSize, audioFormat->samples, (isCopy == JNI_FALSE) );
__android_log_print(ANDROID_LOG_INFO, "libSDL", t);
/*
audioBuffer = (Uint8 *) SDL_AllocAudioMem(audioBufferSize);
if ( audioBuffer == NULL ) {
SDL_mutexV(audioMutex);
return NULL;
}
ret = (*env)->NewDirectByteBuffer(env, audioBuffer, audioBufferSize);
*/
audioInitialized = 1;
SDL_CondSignal(audioCond);
}
SDL_mutexV(audioMutex);
return 0;
}
extern jint JAVA_EXPORT_NAME(AudioThread_nativeAudioBufferLock) ( JNIEnv * env, jobject jobj )
{
int ret = 0;
if( audioMutex == NULL )
return;
return(-1);
SDL_mutexP(audioMutex);
if( !audioInitialized )
ret = -1;
if( audioBuffer == NULL )
{
ret = 0;
SDL_mutexV(audioMutex);
SDL_CondSignal(audioCond);
return (-1);
}
if( audioPlayed == 0 )
SDL_CondWaitTimeout(audioCond2, audioMutex, 1000);
if( audioBuffer == NULL ) // Should not happen
ret = 0;
else
{
(*env)->SetByteArrayRegion(env, data, 0, audioBufferSize, (jbyte *)audioBuffer);
(*jniEnv)->ReleaseByteArrayElements(jniEnv, audioBufferJNI, (jbyte *)audioBuffer, 0);
audioBuffer == NULL;
ret = audioBufferSize;
audioBuffer = NULL;
audioBufferSize = 0;
SDL_CondSignal(audioCond);
}
SDL_mutexV(audioMutex);
return ret;
};
extern jint JAVA_EXPORT_NAME(AudioThread_nativeAudioBufferUnlock) ( JNIEnv * env, jobject jobj )
{
if( audioMutex == NULL )
return(-1);
jboolean isCopy = JNI_TRUE;
audioBuffer = (unsigned char *) (*env)->GetByteArrayElements(env, audioBufferJNI, &isCopy);
if( isCopy == JNI_TRUE )
__android_log_print(ANDROID_LOG_INFO, "libSDL", "AudioThread_nativeAudioBufferUnlock() JNI returns a copy of byte array - that's slow");
audioPlayed = 0;
SDL_mutexV(audioMutex);
SDL_CondSignal(audioCond);
return 0;
}

View File

@@ -63,6 +63,7 @@ import org.apache.http.impl.*;
import org.apache.http.impl.client.*;
import java.util.zip.*;
import java.io.*;
import java.nio.ByteBuffer;
// TODO: export vibrator to SDL - interface is available in SDL 1.3
@@ -164,13 +165,14 @@ class AudioThread extends Thread {
private Activity mParent;
private AudioTrack mAudio;
private byte[] mAudioBuffer;
private ByteBuffer mAudioBufferNative;
public AudioThread(Activity parent)
{
android.util.Log.i("SDL Java", "AudioThread created");
mParent = parent;
mAudio = null;
mAudioBuffer = null;
this.setPriority(Thread.MAX_PRIORITY);
this.start();
}
@@ -197,10 +199,11 @@ class AudioThread extends Thread {
int encoding = initParams[2];
encoding = ( encoding == 1 ) ? AudioFormat.ENCODING_PCM_16BIT :
AudioFormat.ENCODING_PCM_8BIT;
int bufSize = AudioTrack.getMinBufferSize( rate, channels, encoding);
int bufSize = AudioTrack.getMinBufferSize( rate, channels, encoding );
if( initParams[3] > bufSize )
bufSize = initParams[3];
mAudioBuffer = new byte[bufSize];
nativeAudioInit2(mAudioBuffer);
mAudio = new AudioTrack(AudioManager.STREAM_MUSIC,
rate,
channels,
@@ -212,19 +215,26 @@ class AudioThread extends Thread {
}
else
{
int len = nativeAudioBuffer( mAudioBuffer );
int len = nativeAudioBufferLock();
if( len > 0 )
mAudio.write( mAudioBuffer, 0, len );
if( len < 0 )
break;
nativeAudioBufferUnlock();
}
}
if( mAudio != null )
{
mAudio.stop();
mAudio.release();
mAudio = null;
}
}
private static native int[] nativeAudioInit();
private static native int nativeAudioBuffer( byte[] data );
private static native int nativeAudioInit2(byte[] buf);
private static native int nativeAudioBufferLock();
private static native int nativeAudioBufferUnlock();
}
@@ -313,7 +323,7 @@ public class DemoActivity extends Activity {
class DataDownloader extends Thread
class DataDownloader extends Thread
{
class StatusWriter
{
@@ -365,9 +375,9 @@ public class DemoActivity extends Activity {
} catch( SecurityException e ) { };
if( checkFile != null )
{
Status.setText( "Already downloaded" );
Status.setText( "No need to download" );
DownloadComplete = true;
Parent.initSDL();
initParent();
return;
}
checkFile = null;
@@ -487,6 +497,11 @@ public class DemoActivity extends Activity {
Status.setText( "Finished" );
DownloadComplete = true;
initParent();
};
private void initParent()
{
class Callback implements Runnable
{
public DemoActivity Parent;
@@ -498,7 +513,7 @@ public class DemoActivity extends Activity {
Callback cb = new Callback();
cb.Parent = Parent;
Parent.runOnUiThread(cb);
};
}
private String getOutFilePath(final String filename)
{