Sfoglia il codice sorgente

Android: Added streaming music to AndroidAudioRenderer

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7753 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
kim..ng 14 anni fa
parent
commit
354ff46ccf

+ 1 - 1
engine/src/android/com/jme3/app/android/AndroidApplication.java

@@ -296,7 +296,7 @@ public abstract class AndroidApplication extends Application implements DialogIn
     {        
         if (whichButton != -2)
         {
-            this.stop();
+            this.stop(true);
             activity.finish();
         }
     }

+ 1 - 0
engine/src/android/com/jme3/asset/AndroidAssetManager.java

@@ -70,6 +70,7 @@ public class AndroidAssetManager extends DesktopAssetManager {
         
         System.setProperty("org.xml.sax.driver","org.xmlpull.v1.sax2.Driver");
         
+        
     	// Set Default Android config        	       
         this.registerLocator("", AndroidLocator.class);	        
         this.registerLocator("", ClasspathLocator.class);

+ 251 - 124
engine/src/android/com/jme3/audio/android/AndroidAudioRenderer.java

@@ -33,31 +33,31 @@ package com.jme3.audio.android;
 
 import android.app.Activity;
 import android.content.Context;
+import android.content.res.AssetFileDescriptor;
 import android.content.res.AssetManager;
 import android.media.AudioManager;
+import android.media.MediaPlayer;
 import android.media.SoundPool;
 
+
+import com.jme3.audio.AudioKey;
 import com.jme3.audio.ListenerParam;
 import com.jme3.audio.AudioParam;
-import com.jme3.audio.AudioBuffer;
+
 import com.jme3.audio.AudioData;
 import com.jme3.audio.AudioRenderer;
 import com.jme3.audio.AudioNode;
 import com.jme3.audio.AudioNode.Status;
-import com.jme3.audio.AudioStream;
+
 import com.jme3.audio.Environment;
 import com.jme3.audio.Filter;
 import com.jme3.audio.Listener;
-import com.jme3.audio.LowPassFilter;
+
 import com.jme3.math.Vector3f;
-import com.jme3.util.BufferUtils;
+
 
 import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.FloatBuffer;
-import java.nio.IntBuffer;
-import java.util.ArrayList;
+
 import java.util.HashMap;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.logging.Level;
@@ -69,13 +69,15 @@ import java.util.logging.Logger;
  * @author larynx
  *
  */
-public class AndroidAudioRenderer implements AudioRenderer, SoundPool.OnLoadCompleteListener
+public class AndroidAudioRenderer implements AudioRenderer, SoundPool.OnLoadCompleteListener, MediaPlayer.OnCompletionListener
 {
 
     private static final Logger logger = Logger.getLogger(AndroidAudioRenderer.class.getName());
     private final static int MAX_NUM_CHANNELS = 16;
     
     private SoundPool soundPool = null;
+    private HashMap<AudioNode, MediaPlayer> musicPlaying = new HashMap<AudioNode, MediaPlayer>();   
+
     private final AudioManager manager;
     private final Context context;
     private final AssetManager am;
@@ -104,12 +106,6 @@ public class AndroidAudioRenderer implements AudioRenderer, SoundPool.OnLoadComp
         soundPool = new SoundPool(MAX_NUM_CHANNELS, AudioManager.STREAM_MUSIC, 0);  
         soundPool.setOnLoadCompleteListener(this);
     }
-    
-
-    private void updateFilter(Filter f)
-    {
-        throw new UnsupportedOperationException("Filter type unsupported: " + f.getClass().getName());
-    }
 
     @Override
     public void updateSourceParam(AudioNode src, AudioParam param)
@@ -184,7 +180,7 @@ public class AndroidAudioRenderer implements AudioRenderer, SoundPool.OnLoadComp
                     if (src.getDryFilter() != null){
                         Filter f = src.getDryFilter();
                         if (f.isUpdateNeeded()){
-                            updateFilter(f);
+                            //updateFilter(f);
 
                         }
                     }
@@ -232,6 +228,7 @@ public class AndroidAudioRenderer implements AudioRenderer, SoundPool.OnLoadComp
 
     }
 
+    /*
 
     public void update(float tpf)
     {
@@ -246,6 +243,7 @@ public class AndroidAudioRenderer implements AudioRenderer, SoundPool.OnLoadComp
             return;
 
     }
+    */
 
     public void setListener(Listener listener) 
     {
@@ -266,15 +264,13 @@ public class AndroidAudioRenderer implements AudioRenderer, SoundPool.OnLoadComp
     @Override
     public void onLoadComplete(SoundPool soundPool, int sampleId, int status)
     {
-        //lastLoadCompleted.set(true);
-        
-        if (status == 0)
+        AudioNode src = mapLoadingAudioNodes.get(sampleId);
+        if (src.getAudioData() instanceof AndroidAudioData)
         {
-            AudioNode src = mapLoadingAudioNodes.get(sampleId);
-            if (src.getAudioData() instanceof AndroidAudioData)
+            AndroidAudioData audioData = (AndroidAudioData)src.getAudioData();
+            
+            if (status == 0)    // load was successfull
             {
-                AndroidAudioData audioData = (AndroidAudioData)src.getAudioData();
-                
                 int channelIndex;
                 channelIndex = soundPool.play(audioData.getSoundId(), 1f, 1f, 1, -1, 1f);
                 src.setChannel(channelIndex);
@@ -286,14 +282,19 @@ public class AndroidAudioRenderer implements AudioRenderer, SoundPool.OnLoadComp
             }
             else
             {
-                throw new IllegalArgumentException("AudioData is not of type AndroidAudioData for AudioNode " + src.toString());
+                src.setChannel(-1);                    
             }
         }
+        else
+        {
+            throw new IllegalArgumentException("AudioData is not of type AndroidAudioData for AudioNode " + src.toString());
+        }
     }
     
     @Override
     public void cleanup()
     {
+        // Cleanup sound pool
         if (soundPool != null)
         {
             for (AudioNode src: mapLoadingAudioNodes.values())
@@ -316,41 +317,142 @@ public class AndroidAudioRenderer implements AudioRenderer, SoundPool.OnLoadComp
             soundPool.release();
             soundPool = null;
         }
+        
+        // Cleanup media player
+        for (AudioNode src : musicPlaying.keySet())
+        {
+            MediaPlayer mp = musicPlaying.get(src);
+            {                             
+                mp.stop();
+                mp.release();
+                src.setStatus(Status.Stopped);
+            }
+        }
+        musicPlaying.clear();                
     }
 
+    @Override
+    public void onCompletion(MediaPlayer mp) 
+    {
+        for (AudioNode src : musicPlaying.keySet())
+        {
+            if (musicPlaying.get(src) == mp)
+            {                     
+                mp.seekTo(0);        
+                mp.stop();
+                src.setStatus(Status.Stopped);
+            }
+        }
+                
+    }
+    
     public void playSourceInstance(AudioNode src)
     {
             if (audioDisabled)
                 return;
-            
+
             AndroidAudioData audioData;
             int soundId = 0;
             
             if (src.getAudioData() instanceof AndroidAudioData)
             {
                 audioData = (AndroidAudioData)src.getAudioData();
-                if (audioData.isUpdateNeeded() || (audioData.getSoundId() == 0))
-                {
-                    if (audioData.getSoundId() > 0)
+                
+                if (audioData.getAssetKey() instanceof AudioKey)
+                {                
+                    AudioKey assetKey = (AudioKey) audioData.getAssetKey();                     
+                    if (assetKey.isStream())
                     {
-                        if (src.getChannel() > 0)
+                        MediaPlayer mp;
+                        if (musicPlaying.containsKey(src))
                         {
-                            soundPool.stop(src.getChannel());
-                            src.setChannel(-1);
+                            mp = musicPlaying.get(src);
                         }
-                        soundPool.unload(audioData.getSoundId());
+                        else
+                        {
+                            mp = new MediaPlayer();
+                            mp.setOnCompletionListener(this);
+                            //mp = MediaPlayer.create(context, new Ur );
+                            musicPlaying.put(src, mp);                                
+                        }
+                        if (!mp.isPlaying())
+                        {
+                            try {                                                               
+                                AssetFileDescriptor afd = am.openFd(assetKey.getName());                                
+                                mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
+
+                                //mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
+                                mp.prepare();
+                                mp.setLooping(src.isLooping());
+                                mp.start();
+                                src.setStatus(Status.Playing);
+                                src.setChannel(1);
+                            } catch (IllegalArgumentException e) {
+                                // TODO Auto-generated catch block
+                                e.printStackTrace();
+                            } catch (IllegalStateException e) {
+                                // TODO Auto-generated catch block
+                                e.printStackTrace();
+                            } catch (IOException e) {
+                                // TODO Auto-generated catch block
+                                e.printStackTrace();
+                            }
+                            
+                        }
+                        
                     }
-                                                          
-                    try 
-                    {                                           
-                        soundId = soundPool.load(am.openFd(audioData.getAssetKey().getName()), 1);   
-                    } 
-                    catch (IOException e) 
+                    else
                     {
-                        logger.log(Level.SEVERE, "Failed to load sound " + audioData.getAssetKey().getName(), e);
-                        soundId = -1;
+                        // Low latency Sound effect using SoundPool
+                        if (audioData.isUpdateNeeded() || (audioData.getSoundId() <= 0))
+                        {
+                            if (audioData.getSoundId() > 0)
+                            {
+                                if (src.getChannel() > 0)
+                                {
+                                    soundPool.stop(src.getChannel());
+                                    src.setChannel(-1);
+                                }
+                                soundPool.unload(audioData.getSoundId());
+                            }
+                                                              
+                            try 
+                            {                                           
+                                soundId = soundPool.load(am.openFd(audioData.getAssetKey().getName()), 1);   
+                            } 
+                            catch (IOException e) 
+                            {
+                                logger.log(Level.SEVERE, "Failed to load sound " + audioData.getAssetKey().getName(), e);
+                                soundId = -1;
+                            }
+                            audioData.setSoundId(soundId);                                                           
+                        }
+                        
+                        // Sound failed to load ?
+                        if (audioData.getSoundId() <= 0)
+                        {
+                            throw new IllegalArgumentException("Failed to load: " + audioData.getAssetKey().getName());
+                        }
+                        else
+                        {
+                            int channelIndex;
+                            channelIndex = soundPool.play(audioData.getSoundId(), 1f, 1f, 1, -1, 1f);
+                            if (channelIndex == 0)
+                            {
+                                // Loading is not finished
+                                // Store the soundId and the AudioNode for async loading and later play start
+                                mapLoadingAudioNodes.put(audioData.getSoundId(), src);
+                            }                
+                            src.setChannel(channelIndex);
+                        }
+                        
+                        // Playing started ?
+                        if (src.getChannel() > 0)
+                        {
+                            src.setStatus(Status.Playing);
+                        }
                     }
-                    audioData.setSoundId(soundId);                    
+                
                 }
             }
             else
@@ -358,29 +460,7 @@ public class AndroidAudioRenderer implements AudioRenderer, SoundPool.OnLoadComp
                 throw new IllegalArgumentException("AudioData is not of type AndroidAudioData for AudioNode " + src.toString());
             }
             
-            // Sound failed to load ?
-            if (audioData.getSoundId() <= 0)
-            {
-                throw new IllegalArgumentException("Failed to load: " + audioData.getAssetKey().getName());
-            }
-            else
-            {
-                int channelIndex;
-                channelIndex = soundPool.play(audioData.getSoundId(), 1f, 1f, 1, -1, 1f);
-                if (channelIndex == 0)
-                {
-                    // Loading is not finished
-                    // Store the soundId and the AudioNode for async loading and later play start
-                    mapLoadingAudioNodes.put(audioData.getSoundId(), src);
-                }                
-                src.setChannel(channelIndex);
-            }
-            
-            // Playing started ?
-            if (src.getChannel() > 0)
-            {
-                src.setStatus(Status.Playing);
-            }
+
  
     }
 
@@ -411,14 +491,37 @@ public class AndroidAudioRenderer implements AudioRenderer, SoundPool.OnLoadComp
                 return;
             
             if (src.getStatus() == Status.Playing)
-            {
-                assert src.getChannel() != -1;
-
-                if (src.getChannel() > 0)
+            {                
+                if (src.getAudioData() instanceof AndroidAudioData)
                 {
-                    soundPool.pause(src.getChannel());
+                    AndroidAudioData audioData = (AndroidAudioData)src.getAudioData();                    
+                    if (audioData.getAssetKey() instanceof AudioKey)
+                    {                
+                        AudioKey assetKey = (AudioKey) audioData.getAssetKey();    
+                        
+                        if (assetKey.isStream())
+                        {
+                            MediaPlayer mp;
+                            if (musicPlaying.containsKey(src))
+                            {
+                                mp = musicPlaying.get(src);
+                                mp.pause();
+                                src.setStatus(Status.Paused);
+                            }
+                        }
+                        else
+                        {                                                       
+                            assert src.getChannel() != -1;
+            
+                            if (src.getChannel() > 0)
+                            {
+                                soundPool.pause(src.getChannel());
+                                src.setStatus(Status.Paused);
+                            }
+                        }
+                    }
                 }
-                src.setStatus(Status.Paused);
+                
             }
 
     }
@@ -429,59 +532,55 @@ public class AndroidAudioRenderer implements AudioRenderer, SoundPool.OnLoadComp
             if (audioDisabled)
                 return;
             
-            if (src.getStatus() != Status.Stopped){
-                int chan = src.getChannel();
-                assert chan != -1; // if it's not stopped, must have id
-                
-                if (src.getChannel() > 0)
-                {
-                    soundPool.stop(src.getChannel());
-                    src.setChannel(-1);
-                }
-
-                src.setStatus(Status.Stopped);                                
-            }
             
-            AndroidAudioData audioData;                       
-            if (src.getAudioData() instanceof AndroidAudioData)
-            {
-                audioData = (AndroidAudioData)src.getAudioData();
-                if (audioData.getSoundId() > 0)
+            if (src.getStatus() != Status.Stopped)
+            {                
+                if (src.getAudioData() instanceof AndroidAudioData)
                 {
-                    soundPool.unload(audioData.getSoundId());
+                    AndroidAudioData audioData = (AndroidAudioData)src.getAudioData();                    
+                    if (audioData.getAssetKey() instanceof AudioKey)
+                    {                
+                        AudioKey assetKey = (AudioKey) audioData.getAssetKey();                     
+                        if (assetKey.isStream())
+                        {
+                            MediaPlayer mp;
+                            if (musicPlaying.containsKey(src))
+                            {
+                                mp = musicPlaying.get(src);
+                                mp.stop();
+                                src.setStatus(Status.Stopped);
+                                src.setChannel(-1);
+                            }
+                        }
+                        else
+                        {                                                       
+                            int chan = src.getChannel();
+                            assert chan != -1; // if it's not stopped, must have id
+                            
+                            if (src.getChannel() > 0)
+                            {
+                                soundPool.stop(src.getChannel());
+                                src.setChannel(-1);
+                            }
+                            
+                            src.setStatus(Status.Stopped);
+                            
+                            if (audioData.getSoundId() > 0)
+                            {
+                                soundPool.unload(audioData.getSoundId());
+                            }
+                            audioData.setSoundId(-1);
+                            
+                            
+                            
+                        }
+                    }
                 }
-                audioData.setSoundId(0);
                 
-            }
-            else
-            {
-                throw new IllegalArgumentException("AudioData is not of type AndroidAudioData for AudioNode " + src.toString());
-            }
+            } 
             
-
     }
 
-    private int convertFormat(AudioData ad)
-    {
-        /*
-        switch (ad.getBitsPerSample()){
-            case 8:
-                if (ad.getChannels() == 1)
-                    return AL_FORMAT_MONO8;
-                else if (ad.getChannels() == 2)
-                    return AL_FORMAT_STEREO8;
-
-                break;
-            case 16:
-                if (ad.getChannels() == 1)
-                    return AL_FORMAT_MONO16;
-                else
-                    return AL_FORMAT_STEREO16;
-        }
-        */
-        throw new UnsupportedOperationException("Unsupported channels/bits combination: "+
-                                                "bits="+ad.getBitsPerSample()+", channels="+ad.getChannels());
-    }
 
     public void updateAudioData(AndroidAudioData data)
     {
@@ -490,15 +589,39 @@ public class AndroidAudioRenderer implements AudioRenderer, SoundPool.OnLoadComp
 
     @Override
     public void deleteAudioData(AudioData ad) 
-    {                     
+    {                                
         if (ad instanceof AndroidAudioData)
         {
-            if (((AndroidAudioData)ad).getSoundId() > 0)
-            {
-                soundPool.unload(((AndroidAudioData)ad).getSoundId());
+            AndroidAudioData audioData = (AndroidAudioData)ad;                  
+            if (audioData.getAssetKey() instanceof AudioKey)
+            {                
+                AudioKey assetKey = (AudioKey) audioData.getAssetKey();                     
+                if (assetKey.isStream())
+                {                    
+                    for (AudioNode src : musicPlaying.keySet())
+                    {                        
+                        if (src.getAudioData() == ad)
+                        {
+                            MediaPlayer mp = musicPlaying.get(src);
+                            mp.stop();
+                            mp.release();
+                            musicPlaying.remove(src);
+                            src.setStatus(Status.Stopped);
+                            src.setChannel(-1);
+                            break;                           
+                        }
+                    }
+                }
+                else
+                {
+                    if (audioData.getSoundId() > 0)
+                    {
+                        soundPool.unload(audioData.getSoundId());
+                    }
+                    audioData.setSoundId(0);   
+                }
+                
             }
-            ((AndroidAudioData)ad).setSoundId(0);
-            
         }
         else
         {
@@ -512,7 +635,11 @@ public class AndroidAudioRenderer implements AudioRenderer, SoundPool.OnLoadComp
         
     }
 
-
+    @Override
+    public void update(float tpf) {
+        // TODO Auto-generated method stub
+        
+    }
 
 
 }

+ 65 - 36
engine/src/android/com/jme3/system/android/AndroidConfigChooser.java

@@ -91,8 +91,8 @@ public class AndroidConfigChooser implements EGLConfigChooser
                 if ((value[0] & EGL10.EGL_WINDOW_BIT) != 0)
                 {                    
                     egl.eglGetConfigAttrib(display, conf[i], EGL10.EGL_DEPTH_SIZE, value);
-                    // check if conf has a depth of 16
-                    if (value[0] == 16)
+                    // check if conf has a minimum depth of 16
+                    if (value[0] >= 16)
                     {
                         egl.eglGetConfigAttrib(display, conf[i], EGL10.EGL_RENDERABLE_TYPE, value);
                         // Check if conf is OpenGL ES 2.0
@@ -121,7 +121,7 @@ public class AndroidConfigChooser implements EGLConfigChooser
                     {
                         if (verbose)
                         {
-                            logger.info("NOT Supported EGL Configuration #" + i + " EGL_DEPTH_SIZE != 16");                            
+                            logger.info("NOT Supported EGL Configuration #" + i + " EGL_DEPTH_SIZE < 16");                            
                             logEGLConfig(conf[i], display, egl);
                         }
                     }
@@ -199,30 +199,45 @@ public class AndroidConfigChooser implements EGLConfigChooser
             result = b;
         else // red size is equal
         {
-            // Choose lowest alpha size
-            egl.eglGetConfigAttrib(display, a, EGL10.EGL_ALPHA_SIZE, value);
-            int alphaA = value[0];
+            // Choose highest depth size
+            egl.eglGetConfigAttrib(display, a, EGL10.EGL_DEPTH_SIZE, value);
+            int depthA = value[0];
     
-            egl.eglGetConfigAttrib(display, b, EGL10.EGL_ALPHA_SIZE, value);
-            int alphaB = value[0];
+            egl.eglGetConfigAttrib(display, b, EGL10.EGL_DEPTH_SIZE, value);
+            int depthB = value[0];
     
-            if (alphaA < alphaB)
+            if (depthA > depthB)
                 result = a;
-            else if (alphaA > alphaB)
+            else if (depthA < depthB)
                 result = b;
-            else // alpha is equal
-            {
-                // Choose lowest stencil size
-                egl.eglGetConfigAttrib(display, a, EGL10.EGL_STENCIL_SIZE, value);
-                int stencilA = value[0];
+            else // depth is equal
+            {       
+                
+                // Choose lowest alpha size
+                egl.eglGetConfigAttrib(display, a, EGL10.EGL_ALPHA_SIZE, value);
+                int alphaA = value[0];
         
-                egl.eglGetConfigAttrib(display, b, EGL10.EGL_STENCIL_SIZE, value);
-                int stencilB = value[0];
+                egl.eglGetConfigAttrib(display, b, EGL10.EGL_ALPHA_SIZE, value);
+                int alphaB = value[0];
         
-                if (stencilA < stencilB)
+                if (alphaA < alphaB)
                     result = a;
-                else
+                else if (alphaA > alphaB)
                     result = b;
+                else // alpha is equal
+                {
+                    // Choose lowest stencil size
+                    egl.eglGetConfigAttrib(display, a, EGL10.EGL_STENCIL_SIZE, value);
+                    int stencilA = value[0];
+            
+                    egl.eglGetConfigAttrib(display, b, EGL10.EGL_STENCIL_SIZE, value);
+                    int stencilB = value[0];
+            
+                    if (stencilA < stencilB)
+                        result = a;
+                    else
+                        result = b;
+                }
             }
         }
         return result;
@@ -242,7 +257,7 @@ public class AndroidConfigChooser implements EGLConfigChooser
     
         int[] value = new int[1];
     
-        // Choose highest color size
+        // Choose 565 color size
         egl.eglGetConfigAttrib(display, a, EGL10.EGL_RED_SIZE, value);
         int redA = value[0];
     
@@ -255,30 +270,44 @@ public class AndroidConfigChooser implements EGLConfigChooser
             result = b;
         else // red size is equal
         {
-            // Choose lowest alpha size
-            egl.eglGetConfigAttrib(display, a, EGL10.EGL_ALPHA_SIZE, value);
-            int alphaA = value[0];
+            // Choose lowest depth size
+            egl.eglGetConfigAttrib(display, a, EGL10.EGL_DEPTH_SIZE, value);
+            int depthA = value[0];
     
-            egl.eglGetConfigAttrib(display, b, EGL10.EGL_ALPHA_SIZE, value);
-            int alphaB = value[0];
+            egl.eglGetConfigAttrib(display, b, EGL10.EGL_DEPTH_SIZE, value);
+            int depthB = value[0];
     
-            if (alphaA < alphaB)
+            if (depthA < depthB)
                 result = a;
-            else if (alphaA > alphaB)
+            else if (depthA > depthB)
                 result = b;
-            else // alpha is equal
-            {
-                // Choose lowest stencil size
-                egl.eglGetConfigAttrib(display, a, EGL10.EGL_STENCIL_SIZE, value);
-                int stencilA = value[0];
+            else // depth is equal
+            {                              
+                // Choose lowest alpha size
+                egl.eglGetConfigAttrib(display, a, EGL10.EGL_ALPHA_SIZE, value);
+                int alphaA = value[0];
         
-                egl.eglGetConfigAttrib(display, b, EGL10.EGL_STENCIL_SIZE, value);
-                int stencilB = value[0];
+                egl.eglGetConfigAttrib(display, b, EGL10.EGL_ALPHA_SIZE, value);
+                int alphaB = value[0];
         
-                if (stencilA < stencilB)
+                if (alphaA < alphaB)
                     result = a;
-                else
+                else if (alphaA > alphaB)
                     result = b;
+                else // alpha is equal
+                {
+                    // Choose lowest stencil size
+                    egl.eglGetConfigAttrib(display, a, EGL10.EGL_STENCIL_SIZE, value);
+                    int stencilA = value[0];
+            
+                    egl.eglGetConfigAttrib(display, b, EGL10.EGL_STENCIL_SIZE, value);
+                    int stencilB = value[0];
+            
+                    if (stencilA < stencilB)
+                        result = a;
+                    else
+                        result = b;
+                }
             }
         }
         return result;