Android: Added streaming music to AndroidAudioRenderer

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7753 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
kim..ng 14 years ago
parent 09137fef25
commit 354ff46ccf
  1. 2
      engine/src/android/com/jme3/app/android/AndroidApplication.java
  2. 1
      engine/src/android/com/jme3/asset/AndroidAssetManager.java
  3. 375
      engine/src/android/com/jme3/audio/android/AndroidAudioRenderer.java
  4. 101
      engine/src/android/com/jme3/system/android/AndroidConfigChooser.java

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

@ -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);

@ -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
}
}

@ -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;

Loading…
Cancel
Save