Working audio implementation contributed by Joseph Lunderville
This commit is contained in:
parent
a409f9858f
commit
4f9db82a4c
5 changed files with 291 additions and 148 deletions
|
@ -29,11 +29,15 @@ public class SDLActivity extends Activity {
|
||||||
private static SDLSurface mSurface;
|
private static SDLSurface mSurface;
|
||||||
|
|
||||||
// Audio
|
// Audio
|
||||||
|
private static Thread mAudioThread;
|
||||||
private static AudioTrack mAudioTrack;
|
private static AudioTrack mAudioTrack;
|
||||||
|
|
||||||
// Load the .so
|
// Load the .so
|
||||||
static {
|
static {
|
||||||
System.loadLibrary("SDL");
|
System.loadLibrary("SDL");
|
||||||
|
//System.loadLibrary("SDL_image");
|
||||||
|
//System.loadLibrary("SDL_mixer");
|
||||||
|
//System.loadLibrary("SDL_ttf");
|
||||||
System.loadLibrary("main");
|
System.loadLibrary("main");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,12 +71,13 @@ public class SDLActivity extends Activity {
|
||||||
// C functions we call
|
// C functions we call
|
||||||
public static native void nativeInit();
|
public static native void nativeInit();
|
||||||
public static native void nativeQuit();
|
public static native void nativeQuit();
|
||||||
|
public static native void onNativeResize(int x, int y, int format);
|
||||||
public static native void onNativeKeyDown(int keycode);
|
public static native void onNativeKeyDown(int keycode);
|
||||||
public static native void onNativeKeyUp(int keycode);
|
public static native void onNativeKeyUp(int keycode);
|
||||||
public static native void onNativeTouch(int action, float x,
|
public static native void onNativeTouch(int action, float x,
|
||||||
float y, float p);
|
float y, float p);
|
||||||
public static native void onNativeResize(int x, int y, int format);
|
|
||||||
public static native void onNativeAccel(float x, float y, float z);
|
public static native void onNativeAccel(float x, float y, float z);
|
||||||
|
public static native void nativeRunAudioThread();
|
||||||
|
|
||||||
|
|
||||||
// Java functions called from C
|
// Java functions called from C
|
||||||
|
@ -84,23 +89,83 @@ public class SDLActivity extends Activity {
|
||||||
mSurface.flipEGL();
|
mSurface.flipEGL();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void updateAudio(byte [] buf) {
|
// Audio
|
||||||
|
private static Object buf;
|
||||||
|
|
||||||
if(mAudioTrack == null) {
|
public static Object audioInit(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) {
|
||||||
// Hardcoded things are bad. FIXME when we have more sound stuff
|
int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO;
|
||||||
// working properly.
|
int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT;
|
||||||
mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
|
int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1);
|
||||||
11025,
|
|
||||||
AudioFormat.CHANNEL_CONFIGURATION_MONO,
|
|
||||||
AudioFormat.ENCODING_PCM_8BIT,
|
|
||||||
2048,
|
|
||||||
AudioTrack.MODE_STREAM);
|
|
||||||
}
|
|
||||||
|
|
||||||
mAudioTrack.write(buf, 0, buf.length);
|
|
||||||
mAudioTrack.play();
|
|
||||||
|
|
||||||
Log.v("SDL", "Played some audio");
|
Log.v("SDL", "SDL audio: wanted " + (isStereo ? "stereo" : "mono") + " " + (is16Bit ? "16-bit" : "8-bit") + " " + ((float)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, (AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize);
|
||||||
|
|
||||||
|
mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
|
||||||
|
channelConfig, audioFormat, desiredFrames * frameSize, AudioTrack.MODE_STREAM);
|
||||||
|
|
||||||
|
audioStartThread();
|
||||||
|
|
||||||
|
Log.v("SDL", "SDL audio: got " + ((mAudioTrack.getChannelCount() >= 2) ? "stereo" : "mono") + " " + ((mAudioTrack.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit" : "8-bit") + " " + ((float)mAudioTrack.getSampleRate() / 1000f) + "kHz, " + desiredFrames + " frames buffer");
|
||||||
|
|
||||||
|
if (is16Bit) {
|
||||||
|
buf = new short[desiredFrames * (isStereo ? 2 : 1)];
|
||||||
|
} else {
|
||||||
|
buf = new byte[desiredFrames * (isStereo ? 2 : 1)];
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void audioStartThread() {
|
||||||
|
mAudioThread = new Thread(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
mAudioTrack.play();
|
||||||
|
nativeRunAudioThread();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// I'd take REALTIME if I could get it!
|
||||||
|
mAudioThread.setPriority(Thread.MAX_PRIORITY);
|
||||||
|
mAudioThread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void audioWriteShortBuffer(short[] buffer) {
|
||||||
|
for (int i = 0; i < buffer.length; ) {
|
||||||
|
int result = mAudioTrack.write(buffer, i, buffer.length - i);
|
||||||
|
if (result > 0) {
|
||||||
|
i += result;
|
||||||
|
} else if (result == 0) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(10);
|
||||||
|
} catch(InterruptedException e) {
|
||||||
|
// Nom nom
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.w("SDL", "SDL audio: error return from write(short)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void audioWriteByteBuffer(byte[] buffer) {
|
||||||
|
for (int i = 0; i < buffer.length; ) {
|
||||||
|
int result = mAudioTrack.write(buffer, i, buffer.length - i);
|
||||||
|
if (result > 0) {
|
||||||
|
i += result;
|
||||||
|
} else if (result == 0) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(10);
|
||||||
|
} catch(InterruptedException e) {
|
||||||
|
// Nom nom
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.w("SDL", "SDL audio: error return from write(short)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -279,7 +344,7 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
|
||||||
|
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
Log.v("SDL", e + "");
|
Log.v("SDL", e + "");
|
||||||
for(StackTraceElement s : e.getStackTrace()) {
|
for (StackTraceElement s : e.getStackTrace()) {
|
||||||
Log.v("SDL", s.toString());
|
Log.v("SDL", s.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -303,7 +368,7 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
|
||||||
|
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
Log.v("SDL", "flipEGL(): " + e);
|
Log.v("SDL", "flipEGL(): " + e);
|
||||||
for(StackTraceElement s : e.getStackTrace()) {
|
for (StackTraceElement s : e.getStackTrace()) {
|
||||||
Log.v("SDL", s.toString());
|
Log.v("SDL", s.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,10 @@ extern "C" {
|
||||||
#include "events/SDL_events_c.h"
|
#include "events/SDL_events_c.h"
|
||||||
#include "video/android/SDL_androidkeyboard.h"
|
#include "video/android/SDL_androidkeyboard.h"
|
||||||
#include "video/android/SDL_androidvideo.h"
|
#include "video/android/SDL_androidvideo.h"
|
||||||
}
|
|
||||||
|
/* Impelemented in audio/android/SDL_androidaudio.c */
|
||||||
|
extern void Android_RunAudioThread();
|
||||||
|
} // C
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
This file links the Java side of Android with libsdl
|
This file links the Java side of Android with libsdl
|
||||||
|
@ -39,23 +42,21 @@ extern "C" {
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
Globals
|
Globals
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
JavaVM* mVM = NULL;
|
static JavaVM* mVM = NULL;
|
||||||
JNIEnv* mEnv = NULL;
|
static JNIEnv* mEnv = NULL;
|
||||||
JNIEnv* mAudioThreadEnv = NULL; //See the note below for why this is necessary
|
static JNIEnv* mAudioEnv = NULL;
|
||||||
|
|
||||||
//Main activity
|
// Main activity
|
||||||
jclass mActivityInstance;
|
static jclass mActivityInstance;
|
||||||
|
|
||||||
//method signatures
|
// method signatures
|
||||||
jmethodID midCreateGLContext;
|
static jmethodID midCreateGLContext;
|
||||||
jmethodID midFlipBuffers;
|
static jmethodID midFlipBuffers;
|
||||||
jmethodID midUpdateAudio;
|
static jmethodID midAudioInit;
|
||||||
|
static jmethodID midAudioWriteShortBuffer;
|
||||||
|
static jmethodID midAudioWriteByteBuffer;
|
||||||
|
|
||||||
//Feature IDs
|
// Accelerometer data storage
|
||||||
static const int FEATURE_AUDIO = 1;
|
|
||||||
static const int FEATURE_ACCEL = 2;
|
|
||||||
|
|
||||||
//Accelerometer data storage
|
|
||||||
float fLastAccelerometer[3];
|
float fLastAccelerometer[3];
|
||||||
|
|
||||||
|
|
||||||
|
@ -82,42 +83,42 @@ extern "C" void SDL_Android_Init(JNIEnv* env)
|
||||||
mActivityInstance = cls;
|
mActivityInstance = cls;
|
||||||
midCreateGLContext = mEnv->GetStaticMethodID(cls,"createGLContext","()V");
|
midCreateGLContext = mEnv->GetStaticMethodID(cls,"createGLContext","()V");
|
||||||
midFlipBuffers = mEnv->GetStaticMethodID(cls,"flipBuffers","()V");
|
midFlipBuffers = mEnv->GetStaticMethodID(cls,"flipBuffers","()V");
|
||||||
midUpdateAudio = mEnv->GetStaticMethodID(cls,"updateAudio","([B)V");
|
midAudioInit = mEnv->GetStaticMethodID(cls, "audioInit", "(IZZI)Ljava/lang/Object;");
|
||||||
|
midAudioWriteShortBuffer = mEnv->GetStaticMethodID(cls, "audioWriteShortBuffer", "([S)V");
|
||||||
|
midAudioWriteByteBuffer = mEnv->GetStaticMethodID(cls, "audioWriteByteBuffer", "([B)V");
|
||||||
|
|
||||||
if(!midCreateGLContext || !midFlipBuffers || !midUpdateAudio) {
|
if(!midCreateGLContext || !midFlipBuffers || !midAudioInit ||
|
||||||
__android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: Bad mids\n");
|
!midAudioWriteShortBuffer || !midAudioWriteByteBuffer) {
|
||||||
} else {
|
__android_log_print(ANDROID_LOG_WARN, "SDL", "SDL: Couldn't locate Java callbacks, check that they're named and typed correctly");
|
||||||
#ifdef DEBUG
|
|
||||||
__android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: Good mids\n");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keydown
|
// Resize
|
||||||
extern "C" void Java_org_libsdl_app_SDLActivity_onNativeKeyDown(JNIEnv* env,
|
extern "C" void Java_org_libsdl_app_SDLActivity_onNativeResize(
|
||||||
jobject obj, jint keycode)
|
JNIEnv* env, jobject obj,
|
||||||
|
jint width, jint height, jint format)
|
||||||
|
{
|
||||||
|
Android_SetScreenResolution(width, height, format);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keydown
|
||||||
|
extern "C" void Java_org_libsdl_app_SDLActivity_onNativeKeyDown(
|
||||||
|
JNIEnv* env, jobject obj, jint keycode)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG
|
|
||||||
__android_log_print(ANDROID_LOG_INFO, "SDL",
|
|
||||||
"SDL: native key down %d\n", keycode);
|
|
||||||
#endif
|
|
||||||
Android_OnKeyDown(keycode);
|
Android_OnKeyDown(keycode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keyup
|
// Keyup
|
||||||
extern "C" void Java_org_libsdl_app_SDLActivity_onNativeKeyUp(JNIEnv* env,
|
extern "C" void Java_org_libsdl_app_SDLActivity_onNativeKeyUp(
|
||||||
jobject obj, jint keycode)
|
JNIEnv* env, jobject obj, jint keycode)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG
|
|
||||||
__android_log_print(ANDROID_LOG_INFO, "SDL",
|
|
||||||
"SDL: native key up %d\n", keycode);
|
|
||||||
#endif
|
|
||||||
Android_OnKeyUp(keycode);
|
Android_OnKeyUp(keycode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Touch
|
// Touch
|
||||||
extern "C" void Java_org_libsdl_app_SDLActivity_onNativeTouch(JNIEnv* env,
|
extern "C" void Java_org_libsdl_app_SDLActivity_onNativeTouch(
|
||||||
jobject obj, jint action, jfloat x, jfloat y, jfloat p)
|
JNIEnv* env, jobject obj,
|
||||||
|
jint action, jfloat x, jfloat y, jfloat p)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
__android_log_print(ANDROID_LOG_INFO, "SDL",
|
__android_log_print(ANDROID_LOG_INFO, "SDL",
|
||||||
|
@ -128,31 +129,30 @@ extern "C" void Java_org_libsdl_app_SDLActivity_onNativeTouch(JNIEnv* env,
|
||||||
//TODO: Pass this off to the SDL multitouch stuff
|
//TODO: Pass this off to the SDL multitouch stuff
|
||||||
}
|
}
|
||||||
|
|
||||||
// Quit
|
// Accelerometer
|
||||||
extern "C" void Java_org_libsdl_app_SDLActivity_nativeQuit( JNIEnv* env,
|
|
||||||
jobject obj )
|
|
||||||
{
|
|
||||||
// Inject a SDL_QUIT event
|
|
||||||
SDL_SendQuit();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resize
|
|
||||||
extern "C" void Java_org_libsdl_app_SDLActivity_onNativeResize(
|
|
||||||
JNIEnv* env, jobject obj, jint width,
|
|
||||||
jint height, jint format)
|
|
||||||
{
|
|
||||||
Android_SetScreenResolution(width, height, format);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" void Java_org_libsdl_app_SDLActivity_onNativeAccel(
|
extern "C" void Java_org_libsdl_app_SDLActivity_onNativeAccel(
|
||||||
JNIEnv* env, jobject obj,
|
JNIEnv* env, jobject obj,
|
||||||
jfloat x, jfloat y, jfloat z)
|
jfloat x, jfloat y, jfloat z)
|
||||||
{
|
{
|
||||||
fLastAccelerometer[0] = x;
|
fLastAccelerometer[0] = x;
|
||||||
fLastAccelerometer[1] = y;
|
fLastAccelerometer[1] = y;
|
||||||
fLastAccelerometer[2] = z;
|
fLastAccelerometer[2] = z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Quit
|
||||||
|
extern "C" void Java_org_libsdl_app_SDLActivity_nativeQuit(
|
||||||
|
JNIEnv* env, jobject obj)
|
||||||
|
{
|
||||||
|
// Inject a SDL_QUIT event
|
||||||
|
SDL_SendQuit();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void Java_org_libsdl_app_SDLActivity_nativeRunAudioThread(
|
||||||
|
JNIEnv* env)
|
||||||
|
{
|
||||||
|
mVM->AttachCurrentThread(&mAudioEnv, NULL);
|
||||||
|
Android_RunAudioThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
@ -168,33 +168,81 @@ extern "C" void Android_JNI_SwapWindow()
|
||||||
mEnv->CallStaticVoidMethod(mActivityInstance, midFlipBuffers);
|
mEnv->CallStaticVoidMethod(mActivityInstance, midFlipBuffers);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void Android_JNI_UpdateAudioBuffer(unsigned char *buf, int len)
|
//
|
||||||
|
// Audio support
|
||||||
|
//
|
||||||
|
static jint audioBufferFrames = 0;
|
||||||
|
static bool audioBuffer16Bit = false;
|
||||||
|
static bool audioBufferStereo = false;
|
||||||
|
|
||||||
|
static jobject audioBuffer;
|
||||||
|
static void * audioPinnedBuffer;
|
||||||
|
|
||||||
|
extern "C" int Android_JNI_OpenAudioDevice(int sampleRate, int is16Bit, int channelCount, int desiredBufferFrames)
|
||||||
{
|
{
|
||||||
//Annoyingly we can't just call into Java from any thread. Because the audio
|
__android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device");
|
||||||
//callback is dispatched from the SDL audio thread (that wasn't made from
|
audioBuffer16Bit = is16Bit;
|
||||||
//java, we have to do some magic here to let the JVM know about the thread.
|
audioBufferStereo = channelCount > 1;
|
||||||
//Because everything it touches on the Java side is static anyway, it's
|
|
||||||
//not a big deal, just annoying.
|
|
||||||
if(!mAudioThreadEnv) {
|
|
||||||
__android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: Need to set up audio thread env\n");
|
|
||||||
|
|
||||||
mVM->AttachCurrentThread(&mAudioThreadEnv, NULL);
|
audioBuffer = mEnv->CallStaticObjectMethod(mActivityInstance, midAudioInit, sampleRate, audioBuffer16Bit, audioBufferStereo, desiredBufferFrames);
|
||||||
|
audioBuffer = mEnv->NewGlobalRef(audioBuffer);
|
||||||
|
|
||||||
__android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: ok\n");
|
if (audioBuffer == NULL) {
|
||||||
|
__android_log_print(ANDROID_LOG_WARN, "SDL", "SDL audio: didn't get back a good audio buffer!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (audioBufferStereo) {
|
||||||
|
audioBufferFrames = mEnv->GetArrayLength((jshortArray)audioBuffer) / 2;
|
||||||
|
} else {
|
||||||
|
audioBufferFrames = mEnv->GetArrayLength((jbyteArray)audioBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return audioBufferFrames;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void * Android_JNI_PinAudioBuffer()
|
||||||
|
{
|
||||||
|
jboolean isCopy = JNI_FALSE;
|
||||||
|
|
||||||
|
if (audioPinnedBuffer != NULL) {
|
||||||
|
return audioPinnedBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (audioBuffer16Bit) {
|
||||||
|
audioPinnedBuffer = mAudioEnv->GetShortArrayElements((jshortArray)audioBuffer, &isCopy);
|
||||||
|
} else {
|
||||||
|
audioPinnedBuffer = mAudioEnv->GetByteArrayElements((jbyteArray)audioBuffer, &isCopy);
|
||||||
|
}
|
||||||
|
|
||||||
|
return audioPinnedBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void Android_JNI_WriteAudioBufferAndUnpin()
|
||||||
|
{
|
||||||
|
if (audioPinnedBuffer == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (audioBuffer16Bit) {
|
||||||
|
mAudioEnv->ReleaseShortArrayElements((jshortArray)audioBuffer, (jshort *)audioPinnedBuffer, JNI_COMMIT);
|
||||||
|
mAudioEnv->CallStaticVoidMethod(mActivityInstance, midAudioWriteShortBuffer, (jshortArray)audioBuffer);
|
||||||
|
} else {
|
||||||
|
mAudioEnv->ReleaseByteArrayElements((jbyteArray)audioBuffer, (jbyte *)audioPinnedBuffer, JNI_COMMIT);
|
||||||
|
mAudioEnv->CallStaticVoidMethod(mActivityInstance, midAudioWriteByteBuffer, (jbyteArray)audioBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
audioPinnedBuffer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void Android_JNI_CloseAudioDevice()
|
||||||
|
{
|
||||||
|
if (audioBuffer) {
|
||||||
|
mEnv->DeleteGlobalRef(audioBuffer);
|
||||||
|
audioBuffer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
jbyteArray arr = mAudioThreadEnv->NewByteArray(len);
|
|
||||||
|
|
||||||
//blah. We probably should rework this so we avoid the copy.
|
// TODO: Implement
|
||||||
mAudioThreadEnv->SetByteArrayRegion(arr, 0, len, (jbyte *)buf);
|
|
||||||
|
|
||||||
__android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: copied\n");
|
|
||||||
|
|
||||||
mAudioThreadEnv->CallStaticVoidMethod( mActivityInstance,
|
|
||||||
midUpdateAudio, arr );
|
|
||||||
|
|
||||||
__android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: invoked\n");
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
/* vi: set ts=4 sw=4 expandtab: */
|
||||||
|
|
|
@ -31,7 +31,12 @@ extern "C" {
|
||||||
/* Interface from the SDL library into the Android Java activity */
|
/* Interface from the SDL library into the Android Java activity */
|
||||||
void Android_JNI_CreateContext();
|
void Android_JNI_CreateContext();
|
||||||
void Android_JNI_SwapWindow();
|
void Android_JNI_SwapWindow();
|
||||||
void Android_JNI_UpdateAudioBuffer(unsigned char *buf, int len);
|
|
||||||
|
// Audio support
|
||||||
|
int Android_JNI_OpenAudioDevice(int sampleRate, int is16Bit, int channelCount, int desiredBufferFrames);
|
||||||
|
void* Android_JNI_PinAudioBuffer();
|
||||||
|
void Android_JNI_WriteAudioBufferAndUnpin();
|
||||||
|
void Android_JNI_CloseAudioDevice();
|
||||||
|
|
||||||
/* Ends C function definitions when using C++ */
|
/* Ends C function definitions when using C++ */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -18,8 +18,6 @@
|
||||||
|
|
||||||
Sam Lantinga
|
Sam Lantinga
|
||||||
slouken@libsdl.org
|
slouken@libsdl.org
|
||||||
|
|
||||||
This file written by Ryan C. Gordon (icculus@icculus.org)
|
|
||||||
*/
|
*/
|
||||||
#include "SDL_config.h"
|
#include "SDL_config.h"
|
||||||
|
|
||||||
|
@ -28,18 +26,31 @@
|
||||||
#include "SDL_audio.h"
|
#include "SDL_audio.h"
|
||||||
#include "../SDL_audio_c.h"
|
#include "../SDL_audio_c.h"
|
||||||
#include "SDL_androidaudio.h"
|
#include "SDL_androidaudio.h"
|
||||||
|
|
||||||
#include "../../SDL_android.h"
|
#include "../../SDL_android.h"
|
||||||
|
|
||||||
#include <android/log.h>
|
#include <android/log.h>
|
||||||
|
|
||||||
|
static void * audioDevice;
|
||||||
|
|
||||||
static int
|
static int
|
||||||
AndroidAUD_OpenDevice(_THIS, const char *devname, int iscapture)
|
AndroidAUD_OpenDevice(_THIS, const char *devname, int iscapture)
|
||||||
{
|
{
|
||||||
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
|
SDL_AudioFormat test_format;
|
||||||
int valid_datatype = 0;
|
int valid_datatype = 0;
|
||||||
|
|
||||||
//TODO: Sample rates etc
|
if (iscapture) {
|
||||||
__android_log_print(ANDROID_LOG_INFO, "SDL", "AndroidAudio Open\n");
|
//TODO: implement capture
|
||||||
|
SDL_SetError("Capture not supported on Android");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (audioDevice != NULL) {
|
||||||
|
SDL_SetError("Only one audio device at a time please!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
audioDevice = this;
|
||||||
|
|
||||||
this->hidden = SDL_malloc(sizeof(*(this->hidden)));
|
this->hidden = SDL_malloc(sizeof(*(this->hidden)));
|
||||||
if (!this->hidden) {
|
if (!this->hidden) {
|
||||||
|
@ -48,68 +59,78 @@ AndroidAUD_OpenDevice(_THIS, const char *devname, int iscapture)
|
||||||
}
|
}
|
||||||
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
|
||||||
|
|
||||||
while ((!valid_datatype) && (test_format)) {
|
test_format = SDL_FirstAudioFormat(this->spec.format);
|
||||||
this->spec.format = test_format;
|
while (test_format != 0) { // no "UNKNOWN" constant
|
||||||
switch (test_format) {
|
if ((test_format == AUDIO_U8) || (test_format == AUDIO_S16LSB)) {
|
||||||
case AUDIO_S8:
|
this->spec.format = test_format;
|
||||||
/*case AUDIO_S16LSB: */
|
|
||||||
valid_datatype = 1;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
test_format = SDL_NextAudioFormat();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
test_format = SDL_NextAudioFormat();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (test_format == 0) {
|
||||||
|
// Didn't find a compatible format :(
|
||||||
|
SDL_SetError("No compatible audio format!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->spec.channels > 1) {
|
||||||
|
this->spec.channels = 2;
|
||||||
|
} else {
|
||||||
|
this->spec.channels = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->spec.freq < 8000) {
|
||||||
|
this->spec.freq = 8000;
|
||||||
|
}
|
||||||
|
if (this->spec.freq > 48000) {
|
||||||
|
this->spec.freq = 48000;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: pass in/return a (Java) device ID, also whether we're opening for input or output
|
||||||
|
this->spec.samples = Android_JNI_OpenAudioDevice(this->spec.freq, this->spec.format == AUDIO_U8 ? 0 : 1, this->spec.channels, this->spec.samples);
|
||||||
|
SDL_CalculateAudioSpec(&this->spec);
|
||||||
|
|
||||||
|
if (this->spec.samples == 0) {
|
||||||
|
// Init failed?
|
||||||
|
SDL_SetError("Java-side initialization failed!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
AndroidAUD_PlayDevice(_THIS)
|
AndroidAUD_PlayDevice(_THIS)
|
||||||
{
|
{
|
||||||
__android_log_print(ANDROID_LOG_INFO, "SDL", "AndroidAudio Play\n");
|
Android_JNI_WriteAudioBufferAndUnpin();
|
||||||
|
this->hidden->mixbuf = NULL;
|
||||||
|
|
||||||
//playGenericSound(this->hidden->mixbuf, this->hidden->mixlen);
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
|
|
||||||
// sound->rate = 22050; /* sample rate = 22050Hz */
|
|
||||||
// sound->vol = 127; /* volume [0..127] for [min..max] */
|
|
||||||
// sound->pan = 64; /* balance [0..127] for [left..right] */
|
|
||||||
// sound->format = 0; /* 0 for 16-bit, 1 for 8-bit */
|
|
||||||
// playSound(sound);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static Uint8 *
|
static Uint8 *
|
||||||
AndroidAUD_GetDeviceBuf(_THIS)
|
AndroidAUD_GetDeviceBuf(_THIS)
|
||||||
{
|
{
|
||||||
//__android_log_print(ANDROID_LOG_INFO, "SDL", "****** get device buf\n");
|
if (this->hidden->mixbuf == NULL) {
|
||||||
|
this->hidden->mixbuf = Android_JNI_PinAudioBuffer();
|
||||||
|
}
|
||||||
// sound->data = this->hidden->mixbuf;/* pointer to raw audio data */
|
return this->hidden->mixbuf;
|
||||||
// sound->len = this->hidden->mixlen; /* size of raw data pointed to above */
|
|
||||||
|
|
||||||
|
|
||||||
Android_JNI_UpdateAudioBuffer(this->hidden->mixbuf, this->hidden->mixlen);
|
|
||||||
|
|
||||||
return this->hidden->mixbuf; /* is this right? */
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
AndroidAUD_WaitDevice(_THIS)
|
|
||||||
{
|
|
||||||
/* stub */
|
|
||||||
__android_log_print(ANDROID_LOG_INFO, "SDL", "****** wait device buf\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
AndroidAUD_CloseDevice(_THIS)
|
AndroidAUD_CloseDevice(_THIS)
|
||||||
{
|
{
|
||||||
/* stub */
|
if (this->hidden != NULL) {
|
||||||
__android_log_print(ANDROID_LOG_INFO, "SDL", "****** close device buf\n");
|
if (this->hidden->mixbuf != NULL) {
|
||||||
|
Android_JNI_WriteAudioBufferAndUnpin();
|
||||||
|
}
|
||||||
|
SDL_free(this->hidden);
|
||||||
|
this->hidden = NULL;
|
||||||
|
}
|
||||||
|
Android_JNI_CloseAudioDevice();
|
||||||
|
|
||||||
|
if (audioDevice == this) {
|
||||||
|
audioDevice = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -118,17 +139,15 @@ AndroidAUD_Init(SDL_AudioDriverImpl * impl)
|
||||||
/* Set the function pointers */
|
/* Set the function pointers */
|
||||||
impl->OpenDevice = AndroidAUD_OpenDevice;
|
impl->OpenDevice = AndroidAUD_OpenDevice;
|
||||||
impl->PlayDevice = AndroidAUD_PlayDevice;
|
impl->PlayDevice = AndroidAUD_PlayDevice;
|
||||||
impl->WaitDevice = AndroidAUD_WaitDevice;
|
|
||||||
impl->GetDeviceBuf = AndroidAUD_GetDeviceBuf;
|
impl->GetDeviceBuf = AndroidAUD_GetDeviceBuf;
|
||||||
impl->CloseDevice = AndroidAUD_CloseDevice;
|
impl->CloseDevice = AndroidAUD_CloseDevice;
|
||||||
|
|
||||||
/* and the capabilities */
|
/* and the capabilities */
|
||||||
|
impl->ProvidesOwnCallbackThread = 1;
|
||||||
impl->HasCaptureSupport = 0; //TODO
|
impl->HasCaptureSupport = 0; //TODO
|
||||||
impl->OnlyHasDefaultOutputDevice = 1;
|
impl->OnlyHasDefaultOutputDevice = 1;
|
||||||
impl->OnlyHasDefaultInputDevice = 1;
|
impl->OnlyHasDefaultInputDevice = 1;
|
||||||
|
|
||||||
__android_log_print(ANDROID_LOG_INFO, "SDL","Audio init\n");
|
|
||||||
|
|
||||||
return 1; /* this audio target is available. */
|
return 1; /* this audio target is available. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,4 +155,11 @@ AudioBootStrap ANDROIDAUD_bootstrap = {
|
||||||
"android", "SDL Android audio driver", AndroidAUD_Init, 0 /*1? */
|
"android", "SDL Android audio driver", AndroidAUD_Init, 0 /*1? */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Called by the Java code to start the audio processing on a thread */
|
||||||
|
void
|
||||||
|
Android_RunAudioThread()
|
||||||
|
{
|
||||||
|
SDL_RunAudio(audioDevice);
|
||||||
|
}
|
||||||
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
/* vi: set ts=4 sw=4 expandtab: */
|
||||||
|
|
|
@ -34,9 +34,8 @@ struct SDL_PrivateAudioData
|
||||||
/* The file descriptor for the audio device */
|
/* The file descriptor for the audio device */
|
||||||
Uint8 *mixbuf;
|
Uint8 *mixbuf;
|
||||||
Uint32 mixlen;
|
Uint32 mixlen;
|
||||||
Uint32 write_delay;
|
|
||||||
Uint32 initial_calls;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _SDL_androidaudio_h */
|
#endif /* _SDL_androidaudio_h */
|
||||||
|
|
||||||
/* vi: set ts=4 sw=4 expandtab: */
|
/* vi: set ts=4 sw=4 expandtab: */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue