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 "surfaceDB.h"
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#ifdef ANDROID
#include <android/log.h>
#endif
SurfaceDB surfaceDB; SurfaceDB surfaceDB;
@@ -56,6 +59,14 @@ SDL_Surface *SurfaceDB::loadSurface( string fn, bool alpha ) {
} }
SDL_Surface *newSurface = SDL_LoadBMP( fn.c_str() ); 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_SetColorKey( newSurface, SDL_SRCCOLORKEY,
SDL_MapRGB(newSurface->format, transR, transG, transB) ); SDL_MapRGB(newSurface->format, transR, transG, transB) );
if ( alpha ) { if ( alpha ) {

View File

@@ -98,16 +98,14 @@ AudioBootStrap ANDROIDAUD_bootstrap = {
static SDL_mutex * audioMutex = NULL; static SDL_mutex * audioMutex = NULL;
static SDL_cond * audioCond = NULL; static SDL_cond * audioCond = NULL;
static SDL_cond * audioCond2 = NULL;
static unsigned char * audioBuffer = NULL; static unsigned char * audioBuffer = NULL;
static size_t audioBufferSize = 0; static size_t audioBufferSize = 0;
static SDL_AudioSpec *audioFormat = NULL; static SDL_AudioSpec *audioFormat = NULL;
static int audioInitialized = 0; static int audioInitialized = 0;
static int audioPlayed = 0;
/* This function waits until it is possible to write a full sound buffer */ static jbyteArray audioBufferJNI = NULL;
static void ANDROIDAUD_WaitAudio(_THIS) static JNIEnv * jniEnv = NULL;
{
/* We will block in PlayAudio(), do nothing here */
}
static Uint8 *ANDROIDAUD_GetAudioBuf(_THIS) static Uint8 *ANDROIDAUD_GetAudioBuf(_THIS)
{ {
@@ -117,25 +115,38 @@ static Uint8 *ANDROIDAUD_GetAudioBuf(_THIS)
static void ANDROIDAUD_CloseAudio(_THIS) static void ANDROIDAUD_CloseAudio(_THIS)
{ {
SDL_mutex * audioMutex1; SDL_mutex * audioMutex1;
/*
if ( this->hidden->mixbuf != NULL ) { if ( this->hidden->mixbuf != NULL ) {
SDL_FreeAudioMem(this->hidden->mixbuf); SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL; this->hidden->mixbuf = NULL;
} }
*/
if( audioMutex != NULL ) if( audioMutex != NULL )
{ {
audioMutex1 = audioMutex; audioMutex1 = audioMutex;
SDL_mutexP(audioMutex1); SDL_mutexP(audioMutex1);
audioInitialized = 0; audioInitialized = 0;
SDL_CondSignal(audioCond); SDL_CondSignal(audioCond);
SDL_CondSignal(audioCond2);
audioMutex = NULL; audioMutex = NULL;
SDL_DestroyCond(audioCond); SDL_DestroyCond(audioCond);
SDL_DestroyCond(audioCond2);
audioCond = NULL; audioCond = NULL;
audioCond2 = NULL;
audioFormat = 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; audioBuffer = NULL;
audioBufferSize = 0; audioBufferSize = 0;
SDL_mutexV(audioMutex1); SDL_mutexV(audioMutex1);
SDL_DestroyMutex(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) ) if( ! (spec->format == AUDIO_S8 || spec->format == AUDIO_S16) )
return (-1); // TODO: enable format conversion? Don't know how to do that in SDL 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 ) if( audioMutex == NULL )
{ {
audioInitialized = 0; audioInitialized = 0;
audioFormat = spec; audioFormat = spec;
audioBuffer = this->hidden->mixbuf;
audioBufferSize = this->hidden->mixlen;
audioMutex = SDL_CreateMutex(); audioMutex = SDL_CreateMutex();
audioCond = SDL_CreateCond(); audioCond = SDL_CreateCond();
audioCond2 = SDL_CreateCond();
audioPlayed == 0;
} }
SDL_mutexP(audioMutex); 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; audioFormat = NULL;
SDL_mutexV(audioMutex); SDL_mutexV(audioMutex);
@@ -182,16 +188,26 @@ static int ANDROIDAUD_OpenAudio(_THIS, SDL_AudioSpec *spec)
return(0); 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) static void ANDROIDAUD_PlayAudio(_THIS)
{ {
SDL_mutexP(audioMutex); SDL_mutexP(audioMutex);
audioBuffer = this->hidden->mixbuf; //audioBuffer = this->hidden->mixbuf;
audioBufferSize = this->hidden->mixlen; //audioBufferSize = this->hidden->mixlen;
while( audioBuffer != NULL )
SDL_CondWait( audioCond, audioMutex );
audioPlayed = 1;
SDL_CondSignal(audioCond2);
SDL_CondWaitTimeout( audioCond, audioMutex, 1000 );
this->hidden->mixbuf = audioBuffer;
SDL_mutexV(audioMutex); SDL_mutexV(audioMutex);
} }
@@ -216,12 +232,12 @@ extern jintArray JAVA_EXPORT_NAME(AudioThread_nativeAudioInit) (JNIEnv * env, jo
{ {
initData[0] = audioFormat->freq; initData[0] = audioFormat->freq;
initData[1] = audioFormat->channels; 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; initData[3] = audioFormat->size;
ret=(*env)->NewIntArray(env, 4); ret=(*env)->NewIntArray(env, 4);
(*env)->SetIntArrayRegion(env, ret, 0, 4, (jint *)initData); (*env)->SetIntArrayRegion(env, ret, 0, 4, (jint *)initData);
audioInitialized = 1;
SDL_CondSignal(audioCond);
} }
SDL_mutexV(audioMutex); SDL_mutexV(audioMutex);
@@ -229,33 +245,100 @@ extern jintArray JAVA_EXPORT_NAME(AudioThread_nativeAudioInit) (JNIEnv * env, jo
return (ret); 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; int ret = 0;
if( audioMutex == NULL ) if( audioMutex == NULL )
return; return(-1);
SDL_mutexP(audioMutex); SDL_mutexP(audioMutex);
if( !audioInitialized ) 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 else
{ {
(*env)->SetByteArrayRegion(env, data, 0, audioBufferSize, (jbyte *)audioBuffer); (*jniEnv)->ReleaseByteArrayElements(jniEnv, audioBufferJNI, (jbyte *)audioBuffer, 0);
audioBuffer == NULL;
ret = audioBufferSize; ret = audioBufferSize;
audioBuffer = NULL;
audioBufferSize = 0;
SDL_CondSignal(audioCond);
} }
SDL_mutexV(audioMutex);
return ret; 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 org.apache.http.impl.client.*;
import java.util.zip.*; import java.util.zip.*;
import java.io.*; import java.io.*;
import java.nio.ByteBuffer;
// TODO: export vibrator to SDL - interface is available in SDL 1.3 // TODO: export vibrator to SDL - interface is available in SDL 1.3
@@ -164,13 +165,14 @@ class AudioThread extends Thread {
private Activity mParent; private Activity mParent;
private AudioTrack mAudio; private AudioTrack mAudio;
private byte[] mAudioBuffer; private byte[] mAudioBuffer;
private ByteBuffer mAudioBufferNative;
public AudioThread(Activity parent) public AudioThread(Activity parent)
{ {
android.util.Log.i("SDL Java", "AudioThread created");
mParent = parent; mParent = parent;
mAudio = null; mAudio = null;
mAudioBuffer = null; mAudioBuffer = null;
this.setPriority(Thread.MAX_PRIORITY);
this.start(); this.start();
} }
@@ -197,10 +199,11 @@ class AudioThread extends Thread {
int encoding = initParams[2]; int encoding = initParams[2];
encoding = ( encoding == 1 ) ? AudioFormat.ENCODING_PCM_16BIT : encoding = ( encoding == 1 ) ? AudioFormat.ENCODING_PCM_16BIT :
AudioFormat.ENCODING_PCM_8BIT; AudioFormat.ENCODING_PCM_8BIT;
int bufSize = AudioTrack.getMinBufferSize( rate, channels, encoding); int bufSize = AudioTrack.getMinBufferSize( rate, channels, encoding );
if( initParams[3] > bufSize ) if( initParams[3] > bufSize )
bufSize = initParams[3]; bufSize = initParams[3];
mAudioBuffer = new byte[bufSize]; mAudioBuffer = new byte[bufSize];
nativeAudioInit2(mAudioBuffer);
mAudio = new AudioTrack(AudioManager.STREAM_MUSIC, mAudio = new AudioTrack(AudioManager.STREAM_MUSIC,
rate, rate,
channels, channels,
@@ -212,19 +215,26 @@ class AudioThread extends Thread {
} }
else else
{ {
int len = nativeAudioBuffer( mAudioBuffer ); int len = nativeAudioBufferLock();
if( len > 0 ) if( len > 0 )
mAudio.write( mAudioBuffer, 0, len ); mAudio.write( mAudioBuffer, 0, len );
if( len < 0 ) if( len < 0 )
break; break;
nativeAudioBufferUnlock();
} }
} }
if( mAudio != null ) if( mAudio != null )
{
mAudio.stop(); mAudio.stop();
mAudio.release();
mAudio = null;
}
} }
private static native int[] nativeAudioInit(); 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 class StatusWriter
{ {
@@ -365,9 +375,9 @@ public class DemoActivity extends Activity {
} catch( SecurityException e ) { }; } catch( SecurityException e ) { };
if( checkFile != null ) if( checkFile != null )
{ {
Status.setText( "Already downloaded" ); Status.setText( "No need to download" );
DownloadComplete = true; DownloadComplete = true;
Parent.initSDL(); initParent();
return; return;
} }
checkFile = null; checkFile = null;
@@ -487,6 +497,11 @@ public class DemoActivity extends Activity {
Status.setText( "Finished" ); Status.setText( "Finished" );
DownloadComplete = true; DownloadComplete = true;
initParent();
};
private void initParent()
{
class Callback implements Runnable class Callback implements Runnable
{ {
public DemoActivity Parent; public DemoActivity Parent;
@@ -498,7 +513,7 @@ public class DemoActivity extends Activity {
Callback cb = new Callback(); Callback cb = new Callback();
cb.Parent = Parent; cb.Parent = Parent;
Parent.runOnUiThread(cb); Parent.runOnUiThread(cb);
}; }
private String getOutFilePath(final String filename) private String getOutFilePath(final String filename)
{ {