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