Fixed NPE in AndroidAudioRenderer when soundPool is not initialized

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9175 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
rem..om 13 years ago
parent c4231e3200
commit 446c03935e
  1. 875
      engine/src/android/com/jme3/audio/android/AndroidAudioRenderer.java

@ -58,442 +58,441 @@ import java.util.logging.Logger;
* @author plan_rich * @author plan_rich
*/ */
public class AndroidAudioRenderer implements AudioRenderer, public class AndroidAudioRenderer implements AudioRenderer,
SoundPool.OnLoadCompleteListener, MediaPlayer.OnCompletionListener { SoundPool.OnLoadCompleteListener, MediaPlayer.OnCompletionListener {
private static final Logger logger = Logger private static final Logger logger = Logger.getLogger(AndroidAudioRenderer.class.getName());
.getLogger(AndroidAudioRenderer.class.getName()); private final static int MAX_NUM_CHANNELS = 16;
private final static int MAX_NUM_CHANNELS = 16; private final HashMap<AudioNode, MediaPlayer> musicPlaying = new HashMap<AudioNode, MediaPlayer>();
private final HashMap<AudioNode, MediaPlayer> musicPlaying = new HashMap<AudioNode, MediaPlayer>(); private SoundPool soundPool = null;
private SoundPool soundPool = null; private final Vector3f listenerPosition = new Vector3f();
// For temp use
private final Vector3f listenerPosition = new Vector3f(); private final Vector3f distanceVector = new Vector3f();
// For temp use private final Context context;
private final Vector3f distanceVector = new Vector3f(); private final AssetManager assetManager;
private final Context context; private HashMap<Integer, AudioNode> soundpoolStillLoading = new HashMap<Integer, AudioNode>();
private final AssetManager assetManager; private Listener listener;
private HashMap<Integer, AudioNode> soundpoolStillLoading = new HashMap<Integer, AudioNode>(); private boolean audioDisabled = false;
private Listener listener; private final AudioManager manager;
private boolean audioDisabled = false;
public AndroidAudioRenderer(Activity context) {
private final AudioManager manager; this.context = context;
manager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
public AndroidAudioRenderer(Activity context) { context.setVolumeControlStream(AudioManager.STREAM_MUSIC);
this.context = context; assetManager = context.getAssets();
manager = (AudioManager) context }
.getSystemService(Context.AUDIO_SERVICE);
context.setVolumeControlStream(AudioManager.STREAM_MUSIC); @Override
assetManager = context.getAssets(); public void initialize() {
} soundPool = new SoundPool(MAX_NUM_CHANNELS, AudioManager.STREAM_MUSIC,
0);
@Override soundPool.setOnLoadCompleteListener(this);
public void initialize() { }
soundPool = new SoundPool(MAX_NUM_CHANNELS, AudioManager.STREAM_MUSIC,
0); @Override
soundPool.setOnLoadCompleteListener(this); public void updateSourceParam(AudioNode src, AudioParam param) {
} // logger.log(Level.INFO, "updateSourceParam " + param);
@Override if (audioDisabled) {
public void updateSourceParam(AudioNode src, AudioParam param) { return;
// logger.log(Level.INFO, "updateSourceParam " + param); }
if (audioDisabled) { if (src.getChannel() < 0) {
return; return;
} }
if (src.getChannel() < 0) { switch (param) {
return; case Position:
} if (!src.isPositional()) {
return;
switch (param) { }
case Position:
if (!src.isPositional()) { Vector3f pos = src.getWorldTranslation();
return; break;
} case Velocity:
if (!src.isPositional()) {
Vector3f pos = src.getWorldTranslation(); return;
break; }
case Velocity:
if (!src.isPositional()) { Vector3f vel = src.getVelocity();
return; break;
} case MaxDistance:
if (!src.isPositional()) {
Vector3f vel = src.getVelocity(); return;
break; }
case MaxDistance: break;
if (!src.isPositional()) { case RefDistance:
return; if (!src.isPositional()) {
} return;
break; }
case RefDistance: break;
if (!src.isPositional()) { case ReverbFilter:
return; if (!src.isPositional() || !src.isReverbEnabled()) {
} return;
break; }
case ReverbFilter: break;
if (!src.isPositional() || !src.isReverbEnabled()) { case ReverbEnabled:
return; if (!src.isPositional()) {
} return;
break; }
case ReverbEnabled:
if (!src.isPositional()) { if (src.isReverbEnabled()) {
return; updateSourceParam(src, AudioParam.ReverbFilter);
} }
break;
if (src.isReverbEnabled()) { case IsPositional:
updateSourceParam(src, AudioParam.ReverbFilter); break;
} case Direction:
break; if (!src.isDirectional()) {
case IsPositional: return;
break; }
case Direction:
if (!src.isDirectional()) { Vector3f dir = src.getDirection();
return; break;
} case InnerAngle:
if (!src.isDirectional()) {
Vector3f dir = src.getDirection(); return;
break; }
case InnerAngle: break;
if (!src.isDirectional()) { case OuterAngle:
return; if (!src.isDirectional()) {
} return;
break; }
case OuterAngle: break;
if (!src.isDirectional()) { case IsDirectional:
return; if (src.isDirectional()) {
} updateSourceParam(src, AudioParam.Direction);
break; updateSourceParam(src, AudioParam.InnerAngle);
case IsDirectional: updateSourceParam(src, AudioParam.OuterAngle);
if (src.isDirectional()) { } else {
updateSourceParam(src, AudioParam.Direction); }
updateSourceParam(src, AudioParam.InnerAngle); break;
updateSourceParam(src, AudioParam.OuterAngle); case DryFilter:
} else { if (src.getDryFilter() != null) {
} Filter f = src.getDryFilter();
break; if (f.isUpdateNeeded()) {
case DryFilter: // updateFilter(f);
if (src.getDryFilter() != null) { }
Filter f = src.getDryFilter(); }
if (f.isUpdateNeeded()) { break;
// updateFilter(f); case Looping:
} if (src.isLooping()) {
} }
break; break;
case Looping: case Volume:
if (src.isLooping()) {
} soundPool.setVolume(src.getChannel(), src.getVolume(),
break; src.getVolume());
case Volume:
break;
soundPool.setVolume(src.getChannel(), src.getVolume(), case Pitch:
src.getVolume());
break;
break; }
case Pitch:
}
break;
} @Override
public void updateListenerParam(Listener listener, ListenerParam param) {
} // logger.log(Level.INFO, "updateListenerParam " + param);
if (audioDisabled) {
@Override return;
public void updateListenerParam(Listener listener, ListenerParam param) { }
// logger.log(Level.INFO, "updateListenerParam " + param);
if (audioDisabled) { switch (param) {
return; case Position:
} listenerPosition.set(listener.getLocation());
switch (param) { break;
case Position: case Rotation:
listenerPosition.set(listener.getLocation()); Vector3f dir = listener.getDirection();
Vector3f up = listener.getUp();
break;
case Rotation: break;
Vector3f dir = listener.getDirection(); case Velocity:
Vector3f up = listener.getUp(); Vector3f vel = listener.getVelocity();
break; break;
case Velocity: case Volume:
Vector3f vel = listener.getVelocity(); // alListenerf(AL_GAIN, listener.getVolume());
break;
break; }
case Volume:
// alListenerf(AL_GAIN, listener.getVolume()); }
break;
} @Override
public void update(float tpf) {
} float distance;
float volume;
@Override
public void update(float tpf) { // Loop over all mediaplayers
float distance; for (AudioNode src : musicPlaying.keySet()) {
float volume;
MediaPlayer mp = musicPlaying.get(src);
// Loop over all mediaplayers {
for (AudioNode src : musicPlaying.keySet()) { // Calc the distance to the listener
distanceVector.set(listenerPosition);
MediaPlayer mp = musicPlaying.get(src); distanceVector.subtractLocal(src.getLocalTranslation());
{ distance = FastMath.abs(distanceVector.length());
// Calc the distance to the listener
distanceVector.set(listenerPosition); if (distance < src.getRefDistance()) {
distanceVector.subtractLocal(src.getLocalTranslation()); distance = src.getRefDistance();
distance = FastMath.abs(distanceVector.length()); }
if (distance > src.getMaxDistance()) {
if (distance < src.getRefDistance()) { distance = src.getMaxDistance();
distance = src.getRefDistance(); }
} volume = src.getRefDistance() / distance;
if (distance > src.getMaxDistance()) {
distance = src.getMaxDistance(); AndroidAudioData audioData = (AndroidAudioData) src.getAudioData();
}
volume = src.getRefDistance() / distance; if (FastMath.abs(audioData.getCurrentVolume() - volume) > FastMath.FLT_EPSILON) {
// Left / Right channel get the same volume by now, only
AndroidAudioData audioData = (AndroidAudioData) src // positional
.getAudioData(); mp.setVolume(volume, volume);
if (FastMath.abs(audioData.getCurrentVolume() - volume) > FastMath.FLT_EPSILON) { audioData.setCurrentVolume(volume);
// Left / Right channel get the same volume by now, only }
// positional }
mp.setVolume(volume, volume); }
}
audioData.setCurrentVolume(volume);
} public void setListener(Listener listener) {
} if (audioDisabled) {
} return;
} }
public void setListener(Listener listener) { if (this.listener != null) {
if (audioDisabled) { // previous listener no longer associated with current
return; // renderer
} this.listener.setRenderer(null);
}
if (this.listener != null) {
// previous listener no longer associated with current this.listener = listener;
// renderer this.listener.setRenderer(this);
this.listener.setRenderer(null);
} }
this.listener = listener; @Override
this.listener.setRenderer(this); public void cleanup() {
// Cleanup sound pool
} if (soundPool != null) {
soundPool.release();
@Override soundPool = null;
public void cleanup() { }
// Cleanup sound pool
if (soundPool != null) { // Cleanup media player
soundPool.release(); for (AudioNode src : musicPlaying.keySet()) {
soundPool = null; MediaPlayer mp = musicPlaying.get(src);
} {
mp.stop();
// Cleanup media player mp.release();
for (AudioNode src : musicPlaying.keySet()) { src.setStatus(Status.Stopped);
MediaPlayer mp = musicPlaying.get(src); }
{ }
mp.stop(); musicPlaying.clear();
mp.release(); }
src.setStatus(Status.Stopped);
} @Override
} public void onCompletion(MediaPlayer mp) {
musicPlaying.clear(); mp.seekTo(0);
} mp.stop();
// XXX: This has bad performance -> maybe change overall structure of
@Override // mediaplayer in this audiorenderer?
public void onCompletion(MediaPlayer mp) { for (AudioNode src : musicPlaying.keySet()) {
mp.seekTo(0); if (musicPlaying.get(src) == mp) {
mp.stop(); src.setStatus(Status.Stopped);
// XXX: This has bad performance -> maybe change overall structure of break;
// mediaplayer in this audiorenderer? }
for (AudioNode src : musicPlaying.keySet()) { }
if (musicPlaying.get(src) == mp) { }
src.setStatus(Status.Stopped);
break; /**
} * Plays using the {@link SoundPool} of Android. Due to hard limitation of
} * the SoundPool: After playing more instances of the sound you only have
} * the channel of the last played instance.
*
/** * It is not possible to get information about the state of the soundpool of
* Plays using the {@link SoundPool} of Android. Due to hard limitation of * a specific streamid, so removing is not possilbe -> noone knows when
* the SoundPool: After playing more instances of the sound you only have * sound finished.
* the channel of the last played instance. */
* public void playSourceInstance(AudioNode src) {
* It is not possible to get information about the state of the soundpool of if (audioDisabled) {
* a specific streamid, so removing is not possilbe -> noone knows when return;
* sound finished. }
*/
public void playSourceInstance(AudioNode src) { AndroidAudioData audioData = (AndroidAudioData) src.getAudioData();
if (audioDisabled) {
return; if (!(audioData.getAssetKey() instanceof AudioKey)) {
} throw new IllegalArgumentException("Asset is not a AudioKey");
}
AndroidAudioData audioData = (AndroidAudioData) src.getAudioData();
AudioKey assetKey = (AudioKey) audioData.getAssetKey();
if (!(audioData.getAssetKey() instanceof AudioKey)) {
throw new IllegalArgumentException("Asset is not a AudioKey"); try {
} if (audioData.getId() < 0) { // found something to load
int soundId = soundPool.load(
AudioKey assetKey = (AudioKey) audioData.getAssetKey(); assetManager.openFd(assetKey.getName()), 1);
audioData.setId(soundId);
try { }
if (audioData.getId() < 0) { // found something to load
int soundId = soundPool.load( int channel = soundPool.play(audioData.getId(), 1f, 1f, 1, 0, 1f);
assetManager.openFd(assetKey.getName()), 1);
audioData.setId(soundId); if (channel == 0) {
} soundpoolStillLoading.put(audioData.getId(), src);
} else {
int channel = soundPool.play(audioData.getId(), 1f, 1f, 1, 0, 1f); src.setChannel(channel); // receive a channel at the last
// playing at least
if (channel == 0) { }
soundpoolStillLoading.put(audioData.getId(), src); } catch (IOException e) {
} else { logger.log(Level.SEVERE,
src.setChannel(channel); // receive a channel at the last "Failed to load sound " + assetKey.getName(), e);
// playing at least audioData.setId(-1);
} }
} catch (IOException e) { }
logger.log(Level.SEVERE,
"Failed to load sound " + assetKey.getName(), e); @Override
audioData.setId(-1); public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
} AudioNode src = soundpoolStillLoading.remove(sampleId);
}
if (src == null) {
@Override logger.warning("Something went terribly wrong! onLoadComplete"
public void onLoadComplete(SoundPool soundPool, int sampleId, int status) { + " had sampleId which was not in the HashMap of loading items");
AudioNode src = soundpoolStillLoading.remove(sampleId); return;
}
if (src == null) {
logger.warning("Something went terribly wrong! onLoadComplete" AudioData audioData = src.getAudioData();
+ " had sampleId which was not in the HashMap of loading items");
return; if (status == 0) // load was successfull
} {
int channelIndex;
AudioData audioData = src.getAudioData(); channelIndex = soundPool.play(audioData.getId(), 1f, 1f, 1, 0, 1f);
src.setChannel(channelIndex);
if (status == 0) // load was successfull }
{ }
int channelIndex;
channelIndex = soundPool.play(audioData.getId(), 1f, 1f, 1, 0, 1f); public void playSource(AudioNode src) {
src.setChannel(channelIndex); if (audioDisabled) {
} return;
} }
public void playSource(AudioNode src) { AndroidAudioData audioData = (AndroidAudioData) src.getAudioData();
if (audioDisabled) {
return; MediaPlayer mp = musicPlaying.get(src);
} if (mp == null) {
mp = new MediaPlayer();
AndroidAudioData audioData = (AndroidAudioData) src.getAudioData(); mp.setOnCompletionListener(this);
mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
MediaPlayer mp = musicPlaying.get(src); }
if (mp == null) {
mp = new MediaPlayer(); try {
mp.setOnCompletionListener(this); AssetKey<?> key = audioData.getAssetKey();
mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
} AssetFileDescriptor afd = assetManager.openFd(key.getName()); // assetKey.getName()
mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(),
try { afd.getLength());
AssetKey<?> key = audioData.getAssetKey(); mp.prepare();
mp.setLooping(src.isLooping());
AssetFileDescriptor afd = assetManager.openFd(key.getName()); // assetKey.getName() mp.start();
mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), src.setChannel(0);
afd.getLength()); src.setStatus(Status.Playing);
mp.prepare(); musicPlaying.put(src, mp);
mp.setLooping(src.isLooping());
mp.start(); } catch (IllegalStateException e) {
src.setChannel(0); e.printStackTrace();
src.setStatus(Status.Playing); } catch (Exception e) {
musicPlaying.put(src, mp); e.printStackTrace();
}
} catch (IllegalStateException e) { }
e.printStackTrace();
} catch (Exception e) { /**
e.printStackTrace(); * Pause the current playing sounds. Both from the {@link SoundPool} and the
} * active {@link MediaPlayer}s
} */
public void pauseAll() {
/** if (soundPool != null) {
* Pause the current playing sounds. Both from the {@link SoundPool} and the soundPool.autoPause();
* active {@link MediaPlayer}s for (MediaPlayer mp : musicPlaying.values()) {
*/ mp.pause();
public void pauseAll() { }
soundPool.autoPause(); }
for (MediaPlayer mp : musicPlaying.values()) { }
mp.pause();
} /**
} * Resume all paused sounds.
*/
/** public void resumeAll() {
* Resume all paused sounds. if (soundPool != null) {
*/ soundPool.autoResume();
public void resumeAll() { for (MediaPlayer mp : musicPlaying.values()) {
soundPool.autoResume(); mp.start(); //no resume -> api says call start to resume
for (MediaPlayer mp : musicPlaying.values()) { }
mp.start(); //no resume -> api says call start to resume }
} }
}
public void pauseSource(AudioNode src) {
public void pauseSource(AudioNode src) { if (audioDisabled) {
if (audioDisabled) { return;
return; }
}
MediaPlayer mp = musicPlaying.get(src);
MediaPlayer mp = musicPlaying.get(src); if (mp != null) {
if (mp != null) { mp.pause();
mp.pause(); src.setStatus(Status.Paused);
src.setStatus(Status.Paused); } else {
} else { int channel = src.getChannel();
int channel = src.getChannel(); if (channel != -1) {
if (channel != -1) soundPool.pause(channel); // is not very likley to make
soundPool.pause(channel); // is not very likley to make } // something useful :)
// something useful :) }
} }
}
public void stopSource(AudioNode src) {
public void stopSource(AudioNode src) { if (audioDisabled) {
if (audioDisabled) { return;
return; }
}
// can be stream or buffer -> so try to get mediaplayer
// can be stream or buffer -> so try to get mediaplayer // if there is non try to stop soundpool
// if there is non try to stop soundpool MediaPlayer mp = musicPlaying.get(src);
MediaPlayer mp = musicPlaying.get(src); if (mp != null) {
if (mp != null) { mp.stop();
mp.stop(); src.setStatus(Status.Paused);
src.setStatus(Status.Paused); } else {
} else { int channel = src.getChannel();
int channel = src.getChannel(); if (channel != -1) {
if (channel != -1) { soundPool.pause(channel); // is not very likley to make
soundPool.pause(channel); // is not very likley to make // something useful :)
// something useful :) }
} }
}
}
}
@Override
@Override public void deleteAudioData(AudioData ad) {
public void deleteAudioData(AudioData ad) {
for (AudioNode src : musicPlaying.keySet()) {
for (AudioNode src : musicPlaying.keySet()) { if (src.getAudioData() == ad) {
if (src.getAudioData() == ad) { MediaPlayer mp = musicPlaying.remove(src);
MediaPlayer mp = musicPlaying.remove(src); mp.stop();
mp.stop(); mp.release();
mp.release(); src.setStatus(Status.Stopped);
src.setStatus(Status.Stopped); src.setChannel(-1);
src.setChannel(-1); ad.setId(-1);
ad.setId(-1); break;
break; }
} }
}
if (ad.getId() > 0) {
if (ad.getId() > 0) { soundPool.unload(ad.getId());
soundPool.unload(ad.getId()); ad.setId(-1);
ad.setId(-1); }
} }
}
@Override
@Override public void setEnvironment(Environment env) {
public void setEnvironment(Environment env) { // not yet supported
// not yet supported }
}
@Override
@Override public void deleteFilter(Filter filter) {
public void deleteFilter(Filter filter) { }
}
} }

Loading…
Cancel
Save