diff android-project/src/org/libsdl/app/SDLActivity.java @ 4995:9f9bea41e88f

Working audio implementation contributed by Joseph Lunderville
author Sam Lantinga <slouken@libsdl.org>
date Thu, 13 Jan 2011 11:14:20 -0800
parents 3c9058f3ffe7
children 8d7315668e35
line wrap: on
line diff
--- a/android-project/src/org/libsdl/app/SDLActivity.java	Thu Jan 13 09:15:51 2011 -0800
+++ b/android-project/src/org/libsdl/app/SDLActivity.java	Thu Jan 13 11:14:20 2011 -0800
@@ -29,11 +29,15 @@
     private static SDLSurface mSurface;
 
     // Audio
+    private static Thread mAudioThread;
     private static AudioTrack mAudioTrack;
 
     // Load the .so
     static {
         System.loadLibrary("SDL");
+        //System.loadLibrary("SDL_image");
+        //System.loadLibrary("SDL_mixer");
+        //System.loadLibrary("SDL_ttf");
         System.loadLibrary("main");
     }
 
@@ -67,12 +71,13 @@
     // C functions we call
     public static native void nativeInit();
     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 onNativeKeyUp(int keycode);
     public static native void onNativeTouch(int action, float x, 
                                             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 nativeRunAudioThread();
 
 
     // Java functions called from C
@@ -84,23 +89,83 @@
         mSurface.flipEGL();
     }
 
-    public static void updateAudio(byte [] buf) {
+    // Audio
+    private static Object buf;
+    
+    public static Object audioInit(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("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;
+    }
     
-        if(mAudioTrack == null) {
-            // Hardcoded things are bad. FIXME when we have more sound stuff
-            // working properly. 
-            mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
-                        11025,
-                        AudioFormat.CHANNEL_CONFIGURATION_MONO,
-                        AudioFormat.ENCODING_PCM_8BIT,
-                        2048,
-                        AudioTrack.MODE_STREAM);   
+    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;
+            }
         }
-
-        mAudioTrack.write(buf, 0, buf.length);
-        mAudioTrack.play();
-        
-        Log.v("SDL", "Played some audio");
+    }
+    
+    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 @@
 
         } catch(Exception e) {
             Log.v("SDL", e + "");
-            for(StackTraceElement s : e.getStackTrace()) {
+            for (StackTraceElement s : e.getStackTrace()) {
                 Log.v("SDL", s.toString());
             }
         }
@@ -303,7 +368,7 @@
             
         } catch(Exception e) {
             Log.v("SDL", "flipEGL(): " + e);
-            for(StackTraceElement s : e.getStackTrace()) {
+            for (StackTraceElement s : e.getStackTrace()) {
                 Log.v("SDL", s.toString());
             }
         }