Search code examples
javagame-developmentjavasound

Java Sound Exception


So after i learned how to create a working runnable .jar file and after some tests, I started changing my program so i can create a .jar file but the main problem is that after some changed the program can't play audio files. I moved the audio files into a sources directory like this:

ROOT
|
|--src
|   | -- com.game.main... etc
|
|--userdata
|
|--resources
|   |-- res
         | -- sound
               |--sound.wav

This logic works and i can create a .jar file When i run it on eclipse it throws exceptions:

java.lang.NullPointerException: Cannot invoke "javax.sound.sampled.Clip.start()" because "this.this$0.clip" is null
    at aGame.v2/com.game.lib.entity.Entity$SoundPlayer.run(Entity.java:92)
java.lang.NullPointerException: Cannot invoke "javax.sound.sampled.Clip.start()" because "this.this$0.clip" is null
    at aGame.v2/com.game.lib.entity.Entity$SoundPlayer.run(Entity.java:92)
java.lang.NullPointerException: Cannot invoke "javax.sound.sampled.Clip.start()" because "this.this$0.clip" is null
    at aGame.v2/com.game.lib.entity.Entity$SoundPlayer.run(Entity.java:92)
java.lang.NullPointerException: Cannot invoke "javax.sound.sampled.Clip.start()" because "this.this$0.clip" is null
    at aGame.v2/com.game.lib.entity.Entity$SoundPlayer.run(Entity.java:92)
java.lang.NullPointerException: Cannot invoke "javax.sound.sampled.Clip.start()" because "this.this$0.clip" is null
    at aGame.v2/com.game.lib.entity.Entity$SoundPlayer.run(Entity.java:92)
java.lang.NullPointerException: Cannot invoke "javax.sound.sampled.Clip.start()" because "this.this$0.clip" is null
    at aGame.v2/com.game.lib.entity.Entity$SoundPlayer.run(Entity.java:92)
java.lang.NullPointerException: Cannot invoke "javax.sound.sampled.Clip.start()" because "this.this$0.clip" is null
    at aGame.v2/com.game.lib.entity.Entity$SoundPlayer.run(Entity.java:92)
java.lang.NullPointerException: Cannot invoke "javax.sound.sampled.Clip.start()" because "this.this$0.clip" is null
    at aGame.v2/com.game.lib.entity.Entity$SoundPlayer.run(Entity.java:92)
java.lang.NullPointerException: Cannot invoke "javax.sound.sampled.Clip.start()" because "this.this$0.clip" is null
    at aGame.v2/com.game.lib.entity.Entity$SoundPlayer.run(Entity.java:92)
java.lang.NullPointerException: Cannot invoke "javax.sound.sampled.Clip.start()" because "this.this$0.clip" is null
    at aGame.v2/com.game.lib.entity.Entity$SoundPlayer.run(Entity.java:92)
java.lang.NullPointerException: Cannot invoke "javax.sound.sampled.Clip.start()" because "this.this$0.clip" is null
    at aGame.v2/com.game.lib.entity.Entity$SoundPlayer.run(Entity.java:92)

And exceptions:

javax.sound.sampled.LineUnavailableException: line with format PCM_SIGNED 48000.0 Hz, 16 bit, stereo, 4 bytes/frame, little-endian not supported.
    at java.desktop/com.sun.media.sound.DirectAudioDevice$DirectDL.implOpen(DirectAudioDevice.java:484)
    at java.desktop/com.sun.media.sound.DirectAudioDevice$DirectClip.implOpen(DirectAudioDevice.java:1238)
    at java.desktop/com.sun.media.sound.AbstractDataLine.open(AbstractDataLine.java:115)
    at java.desktop/com.sun.media.sound.DirectAudioDevice$DirectClip.open(DirectAudioDevice.java:1038)
    at java.desktop/com.sun.media.sound.DirectAudioDevice$DirectClip.open(DirectAudioDevice.java:1131)
    at aGame.v2/com.game.lib.entity.Entity$SoundPlayer.run(Entity.java:83)
javax.sound.sampled.LineUnavailableException: line with format PCM_SIGNED 48000.0 Hz, 16 bit, stereo, 4 bytes/frame, little-endian not supported.
    at java.desktop/com.sun.media.sound.DirectAudioDevice$DirectDL.implOpen(DirectAudioDevice.java:484)
    at java.desktop/com.sun.media.sound.DirectAudioDevice$DirectClip.implOpen(DirectAudioDevice.java:1238)
    at java.desktop/com.sun.media.sound.AbstractDataLine.open(AbstractDataLine.java:115)
    at java.desktop/com.sun.media.sound.DirectAudioDevice$DirectClip.open(DirectAudioDevice.java:1038)
    at java.desktop/com.sun.media.sound.DirectAudioDevice$DirectClip.open(DirectAudioDevice.java:1131)
    at aGame.v2/com.game.lib.entity.Entity$SoundPlayer.run(Entity.java:83)

This is the code:

public abstract class Entity {
    public int x, y;
    public int width, height;
    public Rectangle rect;
    
    protected int hp;
    protected int strength;
    protected int kills;
    
    public static final int GRAPHIC_BORDER = 6;
    protected boolean drawMore;
    protected Image image;
    protected boolean damaged;
    
    protected Context context;
    protected Color entityColor;
    protected GamePanel gp;
    protected KeyHandler keyH;
    protected Clip clip;
    
    public Entity(Context x, Color ec) {
        entityColor = ec;
        context = x;
        if (x!=null) {
            keyH = x.keyH;
            gp = x.gp;
        }
        damaged = false;
        hp = 100;
        kills = 0;
        
    }
    
    public synchronized void playSound (String path) {
        try {
            URL is = getClass().getResource(path);
            //BufferedInputStream bis = new BufferedInputStream(is);
            SoundPlayer sp = new SoundPlayer(is);
            sp.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    class SoundPlayer extends Thread {
        private URL soundFile;
        public SoundPlayer (URL is) {
            this.soundFile = is;
        }
        @Override
        public void run () {
            try {
                if (clip!=null) {
                    //clip.stop();
                    clip.close();
                }
                
                clip = null;
                
                AudioInputStream ais = AudioSystem.getAudioInputStream(soundFile);
                clip = AudioSystem.getClip();
                clip.open(ais);
                
                clip.start();
            } catch (Exception e) {
                e.printStackTrace();
            }
            
        }
    }

Can someone help me solve this ?????


Solution

  • I mistakenly wrote that Java doesn't support 48000 fps. I found this guide which says, as of Java 8, 48000 is supported. My apologies! I was remembering restrictions from back when coding in Java 6 and 7, I guess.

    Does your entity have a single sound that is used repeatedly? If so, you can simplify your code. First, use method injection or constructor injection to, at the least, instantiate the Clip instance variable.

    If you have code that makes an existing entity "active" or not, and a need to conserve resources, the method where that occurs might be an appropriate place to instantiate and open your clip.

    Then, for playback, all you need is a method to play the clip on demand. There is nothing to be gained by having a SoundPlayer thread. Clips run in their own thread automatically. Here is some simpler code to try:

    public abstract class Entity {
    
        // include existing declarations...but also add this one
        private Clip clip;
    
        public Entity(Context x, Color ec) {
            // same constructor code
        }
    
        // method injection for audio resource
        public void setUpSound(String path) {
            URL is = getClass().getResource(path);
            try {
                AudioInputStream ais = AudioSystem.getAudioInputStream(is);
                clip = AudioSystem.getClip();
                clip.open(ais);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        public void playSound() {
            clip.stop();
            clip.setFramePosition(0);
            clip.start();
        }
    }
    

    The reason for the .stop() and .setFramePosition(0) methods is that Clip doesn't support concurrent playback. Every time you launch the clip, if it is already playing, the best that can be done (without managing multiple Clip instances of the same resource) is to have the clip jump back to the start of the file. If you want concurrent playback (and other real time options concerning volume, panning or playback-speed) you could swap in AudioCue, an enhanced Clip available through Maven.

    If you are still getting the same or similar errors with this code, I recommend checking which AudioSystem such as .isLineSupported() and .isFileSupported() if the error messages are indicating they are not supported.