IllegalArgumentException in jME2 createAudioTrack

i'm porting my code to jME2 and this line



AudioTrack sound = AudioSystem.getSystem().createAudioTrack(resource, false);



is now producing this exception:


java.lang.IllegalArgumentException: ByteBuffer is not direct
   at org.lwjgl.BufferChecks.checkDirect(BufferChecks.java:146)
   at org.lwjgl.openal.AL10.alBufferData(AL10.java:1042)
   at com.jmex.audio.openal.OpenALAudioBuffer.setup(OpenALAudioBuffer.java:71)
   at com.jmex.audio.util.AudioLoader.loadOGG(AudioLoader.java:80)
   at com.jmex.audio.util.AudioLoader.fillBuffer(AudioLoader.java:65)
   at com.jmex.audio.openal.OpenALSystem.createAudioTrack(OpenALSystem.java:182)
   at com.jmex.audio.openal.OpenALSystem.createAudioTrack(OpenALSystem.java:59)



any help would be greatly appreciated!

Well, I tried to look a bit into this, but I am not sure if the conclusions are correct… just bare with me…



When you try to load an ogg file, the OpenALSystem has the following code in its createAudioTrack method:

buff = OpenALAudioBuffer.generateBuffer();
try {
        AudioLoader.fillBuffer(buff, resource);
}



In the first method (generateBuffer) it allocates a new buffer and in the second one (fillBuffer) it fills the new buffer with data. Now I believe the problem comes from the fact that the original allocated buffer and the data that is inserted, are in different formats slightly. Let me show you.

In jME 1:
The original buffer is created with BufferUtils.createIntBuffer, which allocates a direct buffer. Then later in the AudioLoader.read() method, data is read into a second direct buffer with BufferUtils.createByteBuffer(bytes) and finally buffer.setup(data, channels, bitRate, time, depth); is called which stores the loaded data (from second buffer) into the buffer that was originally created.

In jME 2:
It starts out the same... The original direct buffer is created with BufferUtils.createIntBuffer, which allocates a direct buffer. Then later in the AudioLoader.read() method, data is read into a second buffer BUT in this case the call is BufferUtils.createByteBufferOnHeap(bytes) which creates a non-direct buffer. Finally in buffer.setup(data, channels, bitRate, time, depth); the loaded data from second buffer is stored in the buffer which was originally created. Now later when AL checks if data is in a direct buffer or not, this check is done against the actual data which is stored inside the buffer.... which is NOT direct.

While this MAY be what is causing the problem, I am not sure how or why the audio system is working atm at all. Maybe I am missing something? For those interested, here is a bit of info on direct and non-direct buffers from ByteBuffer's javadoc. All in all I'd consider this a bug if no-one corrects me.

For now the workaround might be streaming the audio. All this buffering code is inside a if (!stream) { ... } block, which means that when you call createAudioTrack(String resourceStr, boolean stream)), you can specify the stream parameter as TRUE, and it should bypass this problematic block. At least thats what caught my eye when looking at this.. I cannot reproduce the problem however . ogg files are loaded fine for me in both streaming and non-streaming modes..

I think someone else should also look into this.

interesting. thanks for all the information. i tried changing the boolean as you suggest and there's no more exception on createAudioTrack.



however now i get the same IllegalArgumentException exception later in my code, when i call play() on the AudioTrack.


java.lang.IllegalArgumentException: ByteBuffer is not direct
   at org.lwjgl.BufferChecks.checkDirect(BufferChecks.java:146)
   at org.lwjgl.openal.AL10.alBufferData(AL10.java:1042)
   at com.jmex.audio.openal.OpenALStreamedAudioPlayer.stream(OpenALStreamedAudioPlayer.java:319)
   at com.jmex.audio.openal.OpenALStreamedAudioPlayer.playStream(OpenALStreamedAudioPlayer.java:190)
   at com.jmex.audio.openal.OpenALStreamedAudioPlayer.playInNewThread(OpenALStreamedAudioPlayer.java:214)
   at com.jmex.audio.openal.OpenALStreamedAudioPlayer.play(OpenALStreamedAudioPlayer.java:166)
   at com.jmex.audio.AudioTrack.play(AudioTrack.java:117)

Yeah, makes sense… in the OpenALStreamedAudioPlayer there is also a change between jme1 and jme2 -

ByteBuffer dataBuffer = ByteBuffer.allocateDirect(BUFFER_SIZE);

…has been replaced with…

ByteBuffer dataBuffer = BufferUtils.createByteBufferOnHeap(BUFFER_SIZE);



However quite possibly I am completely off-track here - as the system does work mostly - I can run teh examples just fine. Perhaps you can report if the audio tests work for you (replace the wav files with ogg ones to get a fair assesment. If the examples work for you, then it would be probably useful to see some more code from your Audio handling… maybe it is something that you do…?

thanks. i tried TestJmexAudio and i get the same "ByteBuffer is not direct" exception. i tried both ogg and wav.



i also copied over the native library file "openal.dylib" from the jME2 download just to make sure i had the current library in place.



hmmm can i simply revert to the com.jmex.audio.openal.* in jME1? i.e. just to get my game up and running again? or will that break other things (the rest of my code is ported to jME2)?

I think reverting back to the old version should be the last option to consider… when everything else fails.

The changes I can trace down between lwjgl 1 last version and the lwjgl 2 which is used in jme 2:


  • Linux: Using openal-soft instead of the creative (was more or less broken anyway)
  • Windows: Using openal-soft instead of creatives.
  • Updated openal-soft to latest, with alsa and oss backend (linux), winmm and dsound for windows.



    So…


  1. Could you update all your soundcard drivers…
  2. What OS are you running on?
  3. Any other hardware and software specific info you think is relevant?

i develop on mac osx. my system is up to date using Software Update.



i see that openal-soft is crossplatform. but is this change really necessary for mac?

Mac…? weird… as this is from the LWJGL page:


Also, using latest openal-soft on all platforms, except mac (which uses the old creative one or bundle).


It would seem that at least the natives for openAL on Mac are the same in jme 1 and 2. I am sort of out of ideas ATM...

Had a little chat on the LWJGL channel… here is how it went:



<MatthiasM> Mindgamer: can you provide a stack trace for this error ?
<Mindgamer> yes, it is visible in this thread: http://www.jmonkeyengine.com/jmeforum/index.php?topic=9930.0
weird thing, the person did not have problems under LWJGL 1
<MatthiasM> Mindgamer: LWJGL 2.0.x will accept non-direct buffers with a speed penalty
<Mindgamer> so it should not crash with this error... just perform slower?
<MatthiasM> yes - and create more garbage - as it allocated a temporary direct buffer to copy the data in, so jME should be fixed to use direct buffers directly
<Mindgamer> it seemed in lwjgl source that there is a pretty straightforward condition for direct check.. and exception thrown
<MatthiasM> this is the LWJGL 2.x code: "data = NondirectBufferWrapper.wrapDirect(data);". it no longer uses BufferChecks
<Mindgamer> perhaps we should just update the lwjgl version in jme
<Mindgamer> unfortunately i do not know why jme was moved from direct to non-direct buffer during version change from 1 to 2.. It used to be a direct buffer
<MatthiasM> well - it's not a LWJGL issue - if you use the latest version it will work (slower)
<Mindgamer> so direct buffers are recommended always with LWJGL?
<MatthiasM> ofcourse - otherwise the native side can't access the data without copying
<Mindgamer> ok, thanks


Two thoughts on this:
1. Make sure your project indeed only has the newer LWJGL in its classpath... Remove all LWJGL references and add it again.. and only the version that comes with jME 2 and only once. Perhaps you have a classpath problem and you also have an older version in there somewhere?

2. It would seem that it would be a good idea to upgrade our LWJGL version if we have not done it yet... I believe they made a release Wednesday, Novemer 26th, 2008. Also.. I wonder what is the reason for moving away from the old approach of getting the data in a direct buffer? MatthiasM is very convinced that using a direct buffer would be more effective... Perhaps Renanse.. or Irrisor (Or someone else who knows about these changes) could comment on this.. if they read this thread?

thank you. that did the trick. it must have been a path problem on my end. i removed all jars and libraries from my development environment, and then added them again. works great now. thanks again for your help!

:smiley: