Working audio implementation contributed by Joseph Lunderville
authorSam Lantinga <slouken@libsdl.org>
Thu, 13 Jan 2011 11:14:20 -0800
changeset 49959f9bea41e88f
parent 4994 e4ed74189d63
child 4996 8d7315668e35
Working audio implementation contributed by Joseph Lunderville
android-project/src/org/libsdl/app/SDLActivity.java
src/SDL_android.cpp
src/SDL_android.h
src/audio/android/SDL_androidaudio.c
src/audio/android/SDL_androidaudio.h
     1.1 --- a/android-project/src/org/libsdl/app/SDLActivity.java	Thu Jan 13 09:15:51 2011 -0800
     1.2 +++ b/android-project/src/org/libsdl/app/SDLActivity.java	Thu Jan 13 11:14:20 2011 -0800
     1.3 @@ -29,11 +29,15 @@
     1.4      private static SDLSurface mSurface;
     1.5  
     1.6      // Audio
     1.7 +    private static Thread mAudioThread;
     1.8      private static AudioTrack mAudioTrack;
     1.9  
    1.10      // Load the .so
    1.11      static {
    1.12          System.loadLibrary("SDL");
    1.13 +        //System.loadLibrary("SDL_image");
    1.14 +        //System.loadLibrary("SDL_mixer");
    1.15 +        //System.loadLibrary("SDL_ttf");
    1.16          System.loadLibrary("main");
    1.17      }
    1.18  
    1.19 @@ -67,12 +71,13 @@
    1.20      // C functions we call
    1.21      public static native void nativeInit();
    1.22      public static native void nativeQuit();
    1.23 +    public static native void onNativeResize(int x, int y, int format);
    1.24      public static native void onNativeKeyDown(int keycode);
    1.25      public static native void onNativeKeyUp(int keycode);
    1.26      public static native void onNativeTouch(int action, float x, 
    1.27                                              float y, float p);
    1.28 -    public static native void onNativeResize(int x, int y, int format);
    1.29      public static native void onNativeAccel(float x, float y, float z);
    1.30 +    public static native void nativeRunAudioThread();
    1.31  
    1.32  
    1.33      // Java functions called from C
    1.34 @@ -84,23 +89,83 @@
    1.35          mSurface.flipEGL();
    1.36      }
    1.37  
    1.38 -    public static void updateAudio(byte [] buf) {
    1.39 +    // Audio
    1.40 +    private static Object buf;
    1.41 +    
    1.42 +    public static Object audioInit(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) {
    1.43 +        int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO;
    1.44 +        int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT;
    1.45 +        int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1);
    1.46 +        
    1.47 +        Log.v("SDL", "SDL audio: wanted " + (isStereo ? "stereo" : "mono") + " " + (is16Bit ? "16-bit" : "8-bit") + " " + ((float)sampleRate / 1000f) + "kHz, " + desiredFrames + " frames buffer");
    1.48 +        
    1.49 +        // Let the user pick a larger buffer if they really want -- but ye
    1.50 +        // gods they probably shouldn't, the minimums are horrifyingly high
    1.51 +        // latency already
    1.52 +        desiredFrames = Math.max(desiredFrames, (AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize);
    1.53 +        
    1.54 +        mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
    1.55 +                channelConfig, audioFormat, desiredFrames * frameSize, AudioTrack.MODE_STREAM);
    1.56 +        
    1.57 +        audioStartThread();
    1.58 +        
    1.59 +        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");
    1.60 +        
    1.61 +        if (is16Bit) {
    1.62 +            buf = new short[desiredFrames * (isStereo ? 2 : 1)];
    1.63 +        } else {
    1.64 +            buf = new byte[desiredFrames * (isStereo ? 2 : 1)]; 
    1.65 +        }
    1.66 +        return buf;
    1.67 +    }
    1.68      
    1.69 -        if(mAudioTrack == null) {
    1.70 -            // Hardcoded things are bad. FIXME when we have more sound stuff
    1.71 -            // working properly. 
    1.72 -            mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
    1.73 -                        11025,
    1.74 -                        AudioFormat.CHANNEL_CONFIGURATION_MONO,
    1.75 -                        AudioFormat.ENCODING_PCM_8BIT,
    1.76 -                        2048,
    1.77 -                        AudioTrack.MODE_STREAM);   
    1.78 +    public static void audioStartThread() {
    1.79 +        mAudioThread = new Thread(new Runnable() {
    1.80 +            public void run() {
    1.81 +                mAudioTrack.play();
    1.82 +                nativeRunAudioThread();
    1.83 +            }
    1.84 +        });
    1.85 +        
    1.86 +        // I'd take REALTIME if I could get it!
    1.87 +        mAudioThread.setPriority(Thread.MAX_PRIORITY);
    1.88 +        mAudioThread.start();
    1.89 +    }
    1.90 +    
    1.91 +    public static void audioWriteShortBuffer(short[] buffer) {
    1.92 +        for (int i = 0; i < buffer.length; ) {
    1.93 +            int result = mAudioTrack.write(buffer, i, buffer.length - i);
    1.94 +            if (result > 0) {
    1.95 +                i += result;
    1.96 +            } else if (result == 0) {
    1.97 +                try {
    1.98 +                    Thread.sleep(10);
    1.99 +                } catch(InterruptedException e) {
   1.100 +                    // Nom nom
   1.101 +                }
   1.102 +            } else {
   1.103 +                Log.w("SDL", "SDL audio: error return from write(short)");
   1.104 +                return;
   1.105 +            }
   1.106          }
   1.107 -
   1.108 -        mAudioTrack.write(buf, 0, buf.length);
   1.109 -        mAudioTrack.play();
   1.110 -        
   1.111 -        Log.v("SDL", "Played some audio");
   1.112 +    }
   1.113 +    
   1.114 +    public static void audioWriteByteBuffer(byte[] buffer) {
   1.115 +        for (int i = 0; i < buffer.length; ) {
   1.116 +            int result = mAudioTrack.write(buffer, i, buffer.length - i);
   1.117 +            if (result > 0) {
   1.118 +                i += result;
   1.119 +            } else if (result == 0) {
   1.120 +                try {
   1.121 +                    Thread.sleep(10);
   1.122 +                } catch(InterruptedException e) {
   1.123 +                    // Nom nom
   1.124 +                }
   1.125 +            } else {
   1.126 +                Log.w("SDL", "SDL audio: error return from write(short)");
   1.127 +                return;
   1.128 +            }
   1.129 +        }
   1.130      }
   1.131  
   1.132  }
   1.133 @@ -279,7 +344,7 @@
   1.134  
   1.135          } catch(Exception e) {
   1.136              Log.v("SDL", e + "");
   1.137 -            for(StackTraceElement s : e.getStackTrace()) {
   1.138 +            for (StackTraceElement s : e.getStackTrace()) {
   1.139                  Log.v("SDL", s.toString());
   1.140              }
   1.141          }
   1.142 @@ -303,7 +368,7 @@
   1.143              
   1.144          } catch(Exception e) {
   1.145              Log.v("SDL", "flipEGL(): " + e);
   1.146 -            for(StackTraceElement s : e.getStackTrace()) {
   1.147 +            for (StackTraceElement s : e.getStackTrace()) {
   1.148                  Log.v("SDL", s.toString());
   1.149              }
   1.150          }
     2.1 --- a/src/SDL_android.cpp	Thu Jan 13 09:15:51 2011 -0800
     2.2 +++ b/src/SDL_android.cpp	Thu Jan 13 11:14:20 2011 -0800
     2.3 @@ -27,7 +27,10 @@
     2.4  #include "events/SDL_events_c.h"
     2.5  #include "video/android/SDL_androidkeyboard.h"
     2.6  #include "video/android/SDL_androidvideo.h"
     2.7 -}
     2.8 +
     2.9 +/* Impelemented in audio/android/SDL_androidaudio.c */
    2.10 +extern void Android_RunAudioThread();
    2.11 +} // C
    2.12  
    2.13  /*******************************************************************************
    2.14   This file links the Java side of Android with libsdl
    2.15 @@ -39,23 +42,21 @@
    2.16  /*******************************************************************************
    2.17                                 Globals
    2.18  *******************************************************************************/
    2.19 -JavaVM* mVM = NULL;
    2.20 -JNIEnv* mEnv = NULL;
    2.21 -JNIEnv* mAudioThreadEnv = NULL; //See the note below for why this is necessary
    2.22 +static JavaVM* mVM = NULL;
    2.23 +static JNIEnv* mEnv = NULL;
    2.24 +static JNIEnv* mAudioEnv = NULL;
    2.25  
    2.26 -//Main activity
    2.27 -jclass mActivityInstance;
    2.28 +// Main activity
    2.29 +static jclass mActivityInstance;
    2.30  
    2.31 -//method signatures
    2.32 -jmethodID midCreateGLContext;
    2.33 -jmethodID midFlipBuffers;
    2.34 -jmethodID midUpdateAudio;
    2.35 +// method signatures
    2.36 +static jmethodID midCreateGLContext;
    2.37 +static jmethodID midFlipBuffers;
    2.38 +static jmethodID midAudioInit;
    2.39 +static jmethodID midAudioWriteShortBuffer;
    2.40 +static jmethodID midAudioWriteByteBuffer;
    2.41  
    2.42 -//Feature IDs
    2.43 -static const int FEATURE_AUDIO = 1;
    2.44 -static const int FEATURE_ACCEL = 2;
    2.45 -
    2.46 -//Accelerometer data storage
    2.47 +// Accelerometer data storage
    2.48  float fLastAccelerometer[3];
    2.49  
    2.50  
    2.51 @@ -82,42 +83,42 @@
    2.52      mActivityInstance = cls;
    2.53      midCreateGLContext = mEnv->GetStaticMethodID(cls,"createGLContext","()V");
    2.54      midFlipBuffers = mEnv->GetStaticMethodID(cls,"flipBuffers","()V");
    2.55 -    midUpdateAudio = mEnv->GetStaticMethodID(cls,"updateAudio","([B)V");
    2.56 +	midAudioInit = mEnv->GetStaticMethodID(cls, "audioInit", "(IZZI)Ljava/lang/Object;");
    2.57 +	midAudioWriteShortBuffer = mEnv->GetStaticMethodID(cls, "audioWriteShortBuffer", "([S)V");
    2.58 +	midAudioWriteByteBuffer = mEnv->GetStaticMethodID(cls, "audioWriteByteBuffer", "([B)V");
    2.59  
    2.60 -    if(!midCreateGLContext || !midFlipBuffers || !midUpdateAudio) {
    2.61 -        __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: Bad mids\n");
    2.62 -    } else {
    2.63 -#ifdef DEBUG
    2.64 -        __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: Good mids\n");
    2.65 -#endif
    2.66 +    if(!midCreateGLContext || !midFlipBuffers || !midAudioInit ||
    2.67 +       !midAudioWriteShortBuffer || !midAudioWriteByteBuffer) {
    2.68 +		__android_log_print(ANDROID_LOG_WARN, "SDL", "SDL: Couldn't locate Java callbacks, check that they're named and typed correctly");
    2.69      }
    2.70  }
    2.71  
    2.72 -// Keydown
    2.73 -extern "C" void Java_org_libsdl_app_SDLActivity_onNativeKeyDown(JNIEnv* env, 
    2.74 -               jobject obj, jint keycode)
    2.75 +// Resize
    2.76 +extern "C" void Java_org_libsdl_app_SDLActivity_onNativeResize(
    2.77 +                                    JNIEnv* env, jobject obj,
    2.78 +                                    jint width, jint height, jint format)
    2.79  {
    2.80 -#ifdef DEBUG
    2.81 -    __android_log_print(ANDROID_LOG_INFO, "SDL", 
    2.82 -                        "SDL: native key down %d\n", keycode);
    2.83 -#endif
    2.84 +    Android_SetScreenResolution(width, height, format);
    2.85 +}
    2.86 +
    2.87 +// Keydown
    2.88 +extern "C" void Java_org_libsdl_app_SDLActivity_onNativeKeyDown(
    2.89 +                                    JNIEnv* env, jobject obj, jint keycode)
    2.90 +{
    2.91      Android_OnKeyDown(keycode);
    2.92  }
    2.93  
    2.94  // Keyup
    2.95 -extern "C" void Java_org_libsdl_app_SDLActivity_onNativeKeyUp(JNIEnv* env, 
    2.96 -               jobject obj, jint keycode)
    2.97 +extern "C" void Java_org_libsdl_app_SDLActivity_onNativeKeyUp(
    2.98 +                                    JNIEnv* env, jobject obj, jint keycode)
    2.99  {
   2.100 -#ifdef DEBUG
   2.101 -    __android_log_print(ANDROID_LOG_INFO, "SDL", 
   2.102 -                        "SDL: native key up %d\n", keycode);
   2.103 -#endif
   2.104      Android_OnKeyUp(keycode);
   2.105  }
   2.106  
   2.107  // Touch
   2.108 -extern "C" void Java_org_libsdl_app_SDLActivity_onNativeTouch(JNIEnv* env, 
   2.109 -               jobject obj, jint action, jfloat x, jfloat y, jfloat p)
   2.110 +extern "C" void Java_org_libsdl_app_SDLActivity_onNativeTouch(
   2.111 +                                    JNIEnv* env, jobject obj,
   2.112 +                                    jint action, jfloat x, jfloat y, jfloat p)
   2.113  {
   2.114  #ifdef DEBUG
   2.115      __android_log_print(ANDROID_LOG_INFO, "SDL", 
   2.116 @@ -128,31 +129,30 @@
   2.117      //TODO: Pass this off to the SDL multitouch stuff
   2.118  }
   2.119  
   2.120 -// Quit
   2.121 -extern "C" void Java_org_libsdl_app_SDLActivity_nativeQuit( JNIEnv*  env, 
   2.122 -                                                                jobject obj )
   2.123 -{    
   2.124 -    // Inject a SDL_QUIT event
   2.125 -    SDL_SendQuit();
   2.126 -}
   2.127 -
   2.128 -// Resize
   2.129 -extern "C" void Java_org_libsdl_app_SDLActivity_onNativeResize(
   2.130 -                                        JNIEnv*  env, jobject obj, jint width, 
   2.131 -                                        jint height, jint format)
   2.132 -{
   2.133 -    Android_SetScreenResolution(width, height, format);
   2.134 -}
   2.135 -
   2.136 +// Accelerometer
   2.137  extern "C" void Java_org_libsdl_app_SDLActivity_onNativeAccel(
   2.138 -                                        JNIEnv*  env, jobject obj,
   2.139 -                                        jfloat x, jfloat y, jfloat z)
   2.140 +                                    JNIEnv* env, jobject obj,
   2.141 +                                    jfloat x, jfloat y, jfloat z)
   2.142  {
   2.143      fLastAccelerometer[0] = x;
   2.144      fLastAccelerometer[1] = y;
   2.145      fLastAccelerometer[2] = z;   
   2.146  }
   2.147  
   2.148 +// Quit
   2.149 +extern "C" void Java_org_libsdl_app_SDLActivity_nativeQuit(
   2.150 +                                    JNIEnv* env, jobject obj)
   2.151 +{    
   2.152 +    // Inject a SDL_QUIT event
   2.153 +    SDL_SendQuit();
   2.154 +}
   2.155 +
   2.156 +extern "C" void Java_org_libsdl_app_SDLActivity_nativeRunAudioThread(
   2.157 +                                    JNIEnv* env)
   2.158 +{
   2.159 +	mVM->AttachCurrentThread(&mAudioEnv, NULL);
   2.160 +	Android_RunAudioThread();
   2.161 +}
   2.162  
   2.163  
   2.164  /*******************************************************************************
   2.165 @@ -168,33 +168,81 @@
   2.166      mEnv->CallStaticVoidMethod(mActivityInstance, midFlipBuffers); 
   2.167  }
   2.168  
   2.169 -extern "C" void Android_JNI_UpdateAudioBuffer(unsigned char *buf, int len)
   2.170 +//
   2.171 +// Audio support
   2.172 +//
   2.173 +static jint audioBufferFrames = 0;
   2.174 +static bool audioBuffer16Bit = false;
   2.175 +static bool audioBufferStereo = false;
   2.176 +
   2.177 +static jobject audioBuffer;
   2.178 +static void * audioPinnedBuffer;
   2.179 +
   2.180 +extern "C" int Android_JNI_OpenAudioDevice(int sampleRate, int is16Bit, int channelCount, int desiredBufferFrames)
   2.181 +{
   2.182 +	__android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device");
   2.183 +	audioBuffer16Bit = is16Bit;
   2.184 +	audioBufferStereo = channelCount > 1;
   2.185 +
   2.186 +	audioBuffer = mEnv->CallStaticObjectMethod(mActivityInstance, midAudioInit, sampleRate, audioBuffer16Bit, audioBufferStereo, desiredBufferFrames);
   2.187 +	audioBuffer = mEnv->NewGlobalRef(audioBuffer);
   2.188 +
   2.189 +	if (audioBuffer == NULL) {
   2.190 +		__android_log_print(ANDROID_LOG_WARN, "SDL", "SDL audio: didn't get back a good audio buffer!");
   2.191 +		return 0;
   2.192 +	}
   2.193 +
   2.194 +	if (audioBufferStereo) {
   2.195 +		audioBufferFrames = mEnv->GetArrayLength((jshortArray)audioBuffer) / 2;
   2.196 +	} else {
   2.197 +		audioBufferFrames = mEnv->GetArrayLength((jbyteArray)audioBuffer);
   2.198 +	}
   2.199 +
   2.200 +	return audioBufferFrames;
   2.201 +}
   2.202 +
   2.203 +extern "C" void * Android_JNI_PinAudioBuffer()
   2.204  {
   2.205 -    //Annoyingly we can't just call into Java from any thread. Because the audio
   2.206 -    //callback is dispatched from the SDL audio thread (that wasn't made from
   2.207 -    //java, we have to do some magic here to let the JVM know about the thread.
   2.208 -    //Because everything it touches on the Java side is static anyway, it's 
   2.209 -    //not a big deal, just annoying.
   2.210 -    if(!mAudioThreadEnv) {
   2.211 -        __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: Need to set up audio thread env\n");
   2.212 +	jboolean isCopy = JNI_FALSE;
   2.213 +
   2.214 +	if (audioPinnedBuffer != NULL) {
   2.215 +		return audioPinnedBuffer;
   2.216 +	}
   2.217 +
   2.218 +	if (audioBuffer16Bit) {
   2.219 +		audioPinnedBuffer = mAudioEnv->GetShortArrayElements((jshortArray)audioBuffer, &isCopy);
   2.220 +	} else {
   2.221 +		audioPinnedBuffer = mAudioEnv->GetByteArrayElements((jbyteArray)audioBuffer, &isCopy);
   2.222 +	}
   2.223 +
   2.224 +	return audioPinnedBuffer;
   2.225 +}
   2.226  
   2.227 -        mVM->AttachCurrentThread(&mAudioThreadEnv, NULL);
   2.228 +extern "C" void Android_JNI_WriteAudioBufferAndUnpin()
   2.229 +{
   2.230 +	if (audioPinnedBuffer == NULL) {
   2.231 +		return;
   2.232 +	}
   2.233  
   2.234 -        __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: ok\n");
   2.235 +	if (audioBuffer16Bit) {
   2.236 +		mAudioEnv->ReleaseShortArrayElements((jshortArray)audioBuffer, (jshort *)audioPinnedBuffer, JNI_COMMIT);
   2.237 +		mAudioEnv->CallStaticVoidMethod(mActivityInstance, midAudioWriteShortBuffer, (jshortArray)audioBuffer);
   2.238 +	} else {
   2.239 +		mAudioEnv->ReleaseByteArrayElements((jbyteArray)audioBuffer, (jbyte *)audioPinnedBuffer, JNI_COMMIT);
   2.240 +		mAudioEnv->CallStaticVoidMethod(mActivityInstance, midAudioWriteByteBuffer, (jbyteArray)audioBuffer);
   2.241 +	}
   2.242 +
   2.243 +	audioPinnedBuffer = NULL;
   2.244 +}
   2.245 +
   2.246 +extern "C" void Android_JNI_CloseAudioDevice()
   2.247 +{
   2.248 +    if (audioBuffer) {
   2.249 +        mEnv->DeleteGlobalRef(audioBuffer);
   2.250 +        audioBuffer = NULL;
   2.251      }
   2.252 -    
   2.253 -    jbyteArray arr = mAudioThreadEnv->NewByteArray(len);
   2.254  
   2.255 -    //blah. We probably should rework this so we avoid the copy. 
   2.256 -    mAudioThreadEnv->SetByteArrayRegion(arr, 0, len, (jbyte *)buf);
   2.257 -    
   2.258 -    __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: copied\n");
   2.259 -
   2.260 -    mAudioThreadEnv->CallStaticVoidMethod(  mActivityInstance, 
   2.261 -                                            midUpdateAudio, arr );
   2.262 -
   2.263 -    __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL: invoked\n");
   2.264 -    
   2.265 +	// TODO: Implement
   2.266  }
   2.267  
   2.268  /* vi: set ts=4 sw=4 expandtab: */
     3.1 --- a/src/SDL_android.h	Thu Jan 13 09:15:51 2011 -0800
     3.2 +++ b/src/SDL_android.h	Thu Jan 13 11:14:20 2011 -0800
     3.3 @@ -31,7 +31,12 @@
     3.4  /* Interface from the SDL library into the Android Java activity */
     3.5  void Android_JNI_CreateContext();
     3.6  void Android_JNI_SwapWindow();
     3.7 -void Android_JNI_UpdateAudioBuffer(unsigned char *buf, int len);
     3.8 +
     3.9 +// Audio support
    3.10 +int Android_JNI_OpenAudioDevice(int sampleRate, int is16Bit, int channelCount, int desiredBufferFrames);
    3.11 +void* Android_JNI_PinAudioBuffer();
    3.12 +void Android_JNI_WriteAudioBufferAndUnpin();
    3.13 +void Android_JNI_CloseAudioDevice();
    3.14  
    3.15  /* Ends C function definitions when using C++ */
    3.16  #ifdef __cplusplus
     4.1 --- a/src/audio/android/SDL_androidaudio.c	Thu Jan 13 09:15:51 2011 -0800
     4.2 +++ b/src/audio/android/SDL_androidaudio.c	Thu Jan 13 11:14:20 2011 -0800
     4.3 @@ -18,8 +18,6 @@
     4.4  
     4.5      Sam Lantinga
     4.6      slouken@libsdl.org
     4.7 -
     4.8 -    This file written by Ryan C. Gordon (icculus@icculus.org)
     4.9  */
    4.10  #include "SDL_config.h"
    4.11  
    4.12 @@ -28,18 +26,31 @@
    4.13  #include "SDL_audio.h"
    4.14  #include "../SDL_audio_c.h"
    4.15  #include "SDL_androidaudio.h"
    4.16 +
    4.17  #include "../../SDL_android.h"
    4.18  
    4.19  #include <android/log.h>
    4.20  
    4.21 +static void * audioDevice;
    4.22 +
    4.23  static int
    4.24  AndroidAUD_OpenDevice(_THIS, const char *devname, int iscapture)
    4.25  {
    4.26 -    SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
    4.27 +    SDL_AudioFormat test_format;
    4.28      int valid_datatype = 0;
    4.29      
    4.30 -    //TODO: Sample rates etc
    4.31 -    __android_log_print(ANDROID_LOG_INFO, "SDL", "AndroidAudio Open\n");
    4.32 +    if (iscapture) {
    4.33 +    	//TODO: implement capture
    4.34 +    	SDL_SetError("Capture not supported on Android");
    4.35 +    	return 0;
    4.36 +    }
    4.37 +
    4.38 +    if (audioDevice != NULL) {
    4.39 +    	SDL_SetError("Only one audio device at a time please!");
    4.40 +    	return 0;
    4.41 +    }
    4.42 +
    4.43 +    audioDevice = this;
    4.44  
    4.45      this->hidden = SDL_malloc(sizeof(*(this->hidden)));
    4.46      if (!this->hidden) {
    4.47 @@ -48,68 +59,78 @@
    4.48      }
    4.49      SDL_memset(this->hidden, 0, (sizeof *this->hidden));
    4.50  
    4.51 -    while ((!valid_datatype) && (test_format)) {
    4.52 -        this->spec.format = test_format;
    4.53 -        switch (test_format) {
    4.54 -        case AUDIO_S8:
    4.55 -            /*case AUDIO_S16LSB: */
    4.56 -            valid_datatype = 1;
    4.57 -            break;
    4.58 -        default:
    4.59 -            test_format = SDL_NextAudioFormat();
    4.60 +    test_format = SDL_FirstAudioFormat(this->spec.format);
    4.61 +    while (test_format != 0) { // no "UNKNOWN" constant
    4.62 +        if ((test_format == AUDIO_U8) || (test_format == AUDIO_S16LSB)) {
    4.63 +            this->spec.format = test_format;
    4.64              break;
    4.65          }
    4.66 +        test_format = SDL_NextAudioFormat();
    4.67      }
    4.68      
    4.69 +    if (test_format == 0) {
    4.70 +    	// Didn't find a compatible format :(
    4.71 +    	SDL_SetError("No compatible audio format!");
    4.72 +    	return 0;
    4.73 +    }
    4.74 +
    4.75 +    if (this->spec.channels > 1) {
    4.76 +    	this->spec.channels = 2;
    4.77 +    } else {
    4.78 +    	this->spec.channels = 1;
    4.79 +    }
    4.80 +
    4.81 +    if (this->spec.freq < 8000) {
    4.82 +    	this->spec.freq = 8000;
    4.83 +    }
    4.84 +    if (this->spec.freq > 48000) {
    4.85 +    	this->spec.freq = 48000;
    4.86 +    }
    4.87 +
    4.88 +    // TODO: pass in/return a (Java) device ID, also whether we're opening for input or output
    4.89 +    this->spec.samples = Android_JNI_OpenAudioDevice(this->spec.freq, this->spec.format == AUDIO_U8 ? 0 : 1, this->spec.channels, this->spec.samples);
    4.90 +    SDL_CalculateAudioSpec(&this->spec);
    4.91 +
    4.92 +    if (this->spec.samples == 0) {
    4.93 +    	// Init failed?
    4.94 +    	SDL_SetError("Java-side initialization failed!");
    4.95 +    	return 0;
    4.96 +    }
    4.97 +
    4.98      return 1;
    4.99  }
   4.100  
   4.101  static void
   4.102  AndroidAUD_PlayDevice(_THIS)
   4.103  {
   4.104 -    __android_log_print(ANDROID_LOG_INFO, "SDL", "AndroidAudio Play\n");
   4.105 -    
   4.106 -
   4.107 -    //playGenericSound(this->hidden->mixbuf, this->hidden->mixlen);
   4.108 -    
   4.109 -#if 0
   4.110 -
   4.111 -//    sound->rate = 22050; /* sample rate = 22050Hz */
   4.112 -//    sound->vol = 127;    /* volume [0..127] for [min..max] */
   4.113 -//    sound->pan = 64;     /* balance [0..127] for [left..right] */
   4.114 -//    sound->format = 0;   /* 0 for 16-bit, 1 for 8-bit */
   4.115 -//    playSound(sound);
   4.116 -#endif
   4.117 +    Android_JNI_WriteAudioBufferAndUnpin();
   4.118 +    this->hidden->mixbuf = NULL;
   4.119  }
   4.120  
   4.121 -
   4.122  static Uint8 *
   4.123  AndroidAUD_GetDeviceBuf(_THIS)
   4.124  {
   4.125 -     //__android_log_print(ANDROID_LOG_INFO, "SDL", "****** get device buf\n");
   4.126 -
   4.127 -     
   4.128 -    //    sound->data = this->hidden->mixbuf;/* pointer to raw audio data */
   4.129 -//    sound->len = this->hidden->mixlen; /* size of raw data pointed to above */
   4.130 -
   4.131 -
   4.132 -    Android_JNI_UpdateAudioBuffer(this->hidden->mixbuf, this->hidden->mixlen);
   4.133 -    
   4.134 -    return this->hidden->mixbuf;        /* is this right? */
   4.135 -}
   4.136 -
   4.137 -static void
   4.138 -AndroidAUD_WaitDevice(_THIS)
   4.139 -{
   4.140 -    /* stub */
   4.141 -     __android_log_print(ANDROID_LOG_INFO, "SDL", "****** wait device buf\n");
   4.142 +	if (this->hidden->mixbuf == NULL) {
   4.143 +		this->hidden->mixbuf = Android_JNI_PinAudioBuffer();
   4.144 +	}
   4.145 +    return this->hidden->mixbuf;
   4.146  }
   4.147  
   4.148  static void
   4.149  AndroidAUD_CloseDevice(_THIS)
   4.150  {
   4.151 -    /* stub */
   4.152 -     __android_log_print(ANDROID_LOG_INFO, "SDL", "****** close device buf\n");
   4.153 +    if (this->hidden != NULL) {
   4.154 +    	if (this->hidden->mixbuf != NULL) {
   4.155 +    		Android_JNI_WriteAudioBufferAndUnpin();
   4.156 +    	}
   4.157 +    	SDL_free(this->hidden);
   4.158 +    	this->hidden = NULL;
   4.159 +    }
   4.160 +	Android_JNI_CloseAudioDevice();
   4.161 +
   4.162 +    if (audioDevice == this) {
   4.163 +    	audioDevice = NULL;
   4.164 +    }
   4.165  }
   4.166  
   4.167  static int
   4.168 @@ -118,17 +139,15 @@
   4.169      /* Set the function pointers */
   4.170      impl->OpenDevice = AndroidAUD_OpenDevice;
   4.171      impl->PlayDevice = AndroidAUD_PlayDevice;
   4.172 -    impl->WaitDevice = AndroidAUD_WaitDevice;
   4.173      impl->GetDeviceBuf = AndroidAUD_GetDeviceBuf;
   4.174      impl->CloseDevice = AndroidAUD_CloseDevice;
   4.175  
   4.176      /* and the capabilities */
   4.177 +    impl->ProvidesOwnCallbackThread = 1;
   4.178      impl->HasCaptureSupport = 0; //TODO
   4.179      impl->OnlyHasDefaultOutputDevice = 1;
   4.180      impl->OnlyHasDefaultInputDevice = 1;
   4.181  
   4.182 -    __android_log_print(ANDROID_LOG_INFO, "SDL","Audio init\n");
   4.183 -
   4.184      return 1;   /* this audio target is available. */
   4.185  }
   4.186  
   4.187 @@ -136,4 +155,11 @@
   4.188      "android", "SDL Android audio driver", AndroidAUD_Init, 0       /*1? */
   4.189  };
   4.190  
   4.191 +/* Called by the Java code to start the audio processing on a thread */
   4.192 +void
   4.193 +Android_RunAudioThread()
   4.194 +{
   4.195 +	SDL_RunAudio(audioDevice);
   4.196 +}
   4.197 +
   4.198  /* vi: set ts=4 sw=4 expandtab: */
     5.1 --- a/src/audio/android/SDL_androidaudio.h	Thu Jan 13 09:15:51 2011 -0800
     5.2 +++ b/src/audio/android/SDL_androidaudio.h	Thu Jan 13 11:14:20 2011 -0800
     5.3 @@ -34,9 +34,8 @@
     5.4      /* The file descriptor for the audio device */
     5.5      Uint8 *mixbuf;
     5.6      Uint32 mixlen;
     5.7 -    Uint32 write_delay;
     5.8 -    Uint32 initial_calls;
     5.9  };
    5.10  
    5.11  #endif /* _SDL_androidaudio_h */
    5.12 +
    5.13  /* vi: set ts=4 sw=4 expandtab: */