From c75f157cbb8371824ffd4d39e869a84bd33ed546 Mon Sep 17 00:00:00 2001 From: "PSp..om" Date: Mon, 16 May 2011 22:59:49 +0000 Subject: [PATCH] Sort of fixed a streaming related memory leak. Well, streams won't leak anymore but the buffered case technically will if you create them and drop them because that's a different level of fix. Also made the deleteAudioData synchronized since it can be called from another thread pretty trivially. And fixed a race condition that caused an IndexOutOfBounds exception if you happen to try adjusting an AudioNode's parameters right as it was finishing playing. git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7506 75d07b2b-3a1a-0410-a2c5-0572b91ccdca --- .../jme3/audio/lwjgl/LwjglAudioRenderer.java | 78 ++++++++++++++----- 1 file changed, 57 insertions(+), 21 deletions(-) diff --git a/engine/src/lwjgl-oal/com/jme3/audio/lwjgl/LwjglAudioRenderer.java b/engine/src/lwjgl-oal/com/jme3/audio/lwjgl/LwjglAudioRenderer.java index 1c69fa737..493e39d3b 100644 --- a/engine/src/lwjgl-oal/com/jme3/audio/lwjgl/LwjglAudioRenderer.java +++ b/engine/src/lwjgl-oal/com/jme3/audio/lwjgl/LwjglAudioRenderer.java @@ -298,6 +298,18 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable { } if (audioDisabled) return; + + // There is a race condition in AudioNode that can + // cause this to be called for a node that has been + // detached from its channel. For example, setVolume() + // called from the render thread may see that that AudioNode + // still has a channel value but the audio thread may + // clear that channel before setVolume() gets to call + // updateSourceParam() (because the audio stopped playing + // on its own right as the volume was set). In this case, + // it should be safe to just ignore the update + if (src.getChannel() < 0) + return; assert src.getChannel() >= 0; @@ -745,6 +757,10 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable { src.setChannel(-1); clearChannel(i); freeChannel(i); + + // And free the audio since it cannot be + // played again anyway. + deleteAudioData(stream); } } }else if (!streaming){ @@ -913,6 +929,18 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable { src.setChannel(-1); clearChannel(chan); freeChannel(chan); + + if (src.getAudioData() instanceof AudioStream) { + + AudioStream stream = (AudioStream)src.getAudioData(); + if (stream.isOpen()) { + stream.close(); + } + + // And free the audio since it cannot be + // played again anyway. + deleteAudioData(src.getAudioData()); + } } } } @@ -958,7 +986,7 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable { int[] ids = new int[STREAMING_BUFFER_COUNT]; ib.position(0).limit(STREAMING_BUFFER_COUNT); alGenBuffers(ib); - ib.position(0).limit(STREAMING_BUFFER_COUNT); + ib.position(0).limit(STREAMING_BUFFER_COUNT); ib.get(ids); as.setIds(ids); @@ -974,28 +1002,36 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable { } public void deleteAudioData(AudioData ad){ - if (audioDisabled) - return; - - if (ad instanceof AudioBuffer){ - AudioBuffer ab = (AudioBuffer) ad; - int id = ab.getId(); - if (id != -1){ - ib.put(0,id); - ib.position(0).limit(1); - alDeleteBuffers(ib); - ab.resetObject(); + synchronized (threadLock){ + while (!threadLock.get()){ + try { + threadLock.wait(); + } catch (InterruptedException ex) { + } } - }else if (ad instanceof AudioStream){ - AudioStream as = (AudioStream) ad; - int[] ids = as.getIds(); - if (ids != null){ - ib.clear(); - ib.put(ids).flip(); - alDeleteBuffers(ib); - as.resetObject(); + if (audioDisabled) + return; + + if (ad instanceof AudioBuffer){ + AudioBuffer ab = (AudioBuffer) ad; + int id = ab.getId(); + if (id != -1){ + ib.put(0,id); + ib.position(0).limit(1); + alDeleteBuffers(ib); + ab.resetObject(); + } + }else if (ad instanceof AudioStream){ + AudioStream as = (AudioStream) ad; + int[] ids = as.getIds(); + if (ids != null){ + ib.clear(); + ib.put(ids).flip(); + alDeleteBuffers(ib); + as.resetObject(); + } } - } + } } }