jMonkeyEngine / jmonkeyengine

A complete 3-D game development suite written in Java.
http://jmonkeyengine.org
BSD 3-Clause "New" or "Revised" License
3.78k stars 1.12k forks source link

Cannot load ogg audio from classpath (Android) #1972

Closed Ali-RS closed 1 year ago

Ali-RS commented 1 year ago

Android NativeVorbisLoader can not load audio files outside Android's assets directory.

java.lang.UnsupportedOperationException: Cannot load audio files from classpath.Place your audio files in Android's assets directory
        at com.jme3.audio.plugins.NativeVorbisLoader.load(NativeVorbisLoader.java:122)
        at com.jme3.asset.DesktopAssetManager.loadLocatedAsset(DesktopAssetManager.java:260)
        at com.jme3.asset.DesktopAssetManager.loadAsset(DesktopAssetManager.java:374)
        at com.jme3.audio.AudioNode.<init>(AudioNode.java:164)
        at com.jme3.audio.AudioNode.<init>(AudioNode.java:144)
        at com.scenemaxeng.projector.SceneMaxApp.loadAudioResource(SceneMaxApp.java:880)
        at com.scenemaxeng.projector.SceneMaxApp.loadResource(SceneMaxApp.java:864)
        at com.scenemaxeng.projector.SceneMaxApp.run(SceneMaxApp.java:719)
        at com.abware.scenemax3dgamehub.JmeProjectorFragment.runScript(JmeProjectorFragment.java:63)
        at com.abware.scenemax3dgamehub.ui.FullscreenGameActivity$7.run(FullscreenGameActivity.java:255)
        at android.os.Handler.handleCallback(Handler.java:789)
        at android.os.Handler.dispatchMessage(Handler.java:98)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6541)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)

https://github.com/jMonkeyEngine/jmonkeyengine/blob/0cb5fe755582d776ddf223ce88771d958f4818cf/jme3-android/src/main/java/com/jme3/audio/plugins/NativeVorbisLoader.java#L151-L158

Related forum posts:

https://hub.jmonkeyengine.org/t/solved-cannot-load-audio-files-from-classpath-place-your-audio-files-in-androids-assets-directory/37050

https://hub.jmonkeyengine.org/t/android-assets-manager-cannot-find-audio-files/44638

Ali-RS commented 1 year ago

Should probably be resolved after switching to OGGLoader https://github.com/jMonkeyEngine/jmonkeyengine/pull/1961

pavly-gerges commented 1 year ago

This is forced by the android architecture, android doesn't use regular .class and METAINF that adds some files to the classpath, the classpath of android is different and i don't know the underlying architecture as i still have some issues with the android classpath incompatibilities with regular java, but this is a user problem anyway, you should load the assets from the asset folder which is added to the application path and shipped with the apk.

EDIT:

Ali-RS commented 1 year ago

but this is a user problem anyway

Note that the author of the forum topic linked above mentioned that it works fine with textures (I guess texture also uses a native loader on android), wav audio, and models... the issue happens only with NativeVorbisLoader, so it sounds like a bug to me.

Going to try this myself

pavly-gerges commented 1 year ago

Android has its own AssetLocator that i think redirects everything to the asset folder even outside directories; because Class.getResources(String) is null....

Ali-RS commented 1 year ago

I need to take a closer look but from a quick glance, the main difference is that other loaders directly load from InputStream using JME AssetInfo.openStream() but NativeVorbisLoader depends on AndroidAssetInfo and AssetFileDescriptor.

For example, see AndroidNativeImageLoader

https://github.com/jMonkeyEngine/jmonkeyengine/blob/5e859d59a3193608aa2f55e582515cd3ae8192b7/jme3-android/src/main/java/com/jme3/texture/plugins/AndroidNativeImageLoader.java#L47-L64

or OGGLoader

https://github.com/jMonkeyEngine/jmonkeyengine/blob/c7d82696b8479891862b93a8edd3075e9bb87d5f/jme3-jogg/src/main/java/com/jme3/audio/plugins/OGGLoader.java#L300-L311

but NativeVorbisLoader works differently:

https://github.com/jMonkeyEngine/jmonkeyengine/blob/0cb5fe755582d776ddf223ce88771d958f4818cf/jme3-android/src/main/java/com/jme3/audio/plugins/NativeVorbisLoader.java#L120-L127

pavly-gerges commented 1 year ago

The NativeVorbisLoader needs a low level file descriptor for the native side code forced by the Ogg library from xiph.org and it doesn't need a direct stream...

Ali-RS commented 1 year ago

@Scrappers-glitch does NativeVorbisLoader work if I put Ogg files in the assets.jar (like the regular JME desktop app) when building for android?

pavly-gerges commented 1 year ago

If the asset.jar is added on the android lib folder and implemented as a jar from build.gradle then, yes the android apk can read them, but as for the NativeVorbisLoader, you may consider testing this; because the code may have other underlying problems we don't know unless spotted on a bug report.

EDIT: You have to give the right relative path when initializing an audio node, the same as the desktop one.

pavly-gerges commented 1 year ago

Btw, for more information, i suggest using the apk-analyzer tool shipped with the android-studio, it will help you a lot to locate files loaded into the application compression.

Ali-RS commented 1 year ago

does NativeVorbisLoader work if I put Ogg files in the assets.jar (like the regular JME desktop app) when building for android?

I tried this and it does not work with ogg. I got the same error java.lang.UnsupportedOperationException: Cannot load audio files from classpath.Place your audio files in Android's assets directory. It works fine with WAV files.

Also, it works fine if I use OGGLoader (from jme3-jogg) instead of NativeVorbisLoader.

Ali-RS commented 1 year ago

Resolved by #1961